Merge branch 'pgsql_support' into nightly

This commit is contained in:
Alexei Sorokin 2019-09-12 12:01:50 +03:00
commit 8f309bc768
121 changed files with 5854 additions and 5316 deletions

View File

@ -164,10 +164,9 @@ The ones that you may want to set are listed below for clarity.
* `database` (string, required, default null): a DSN (Data Source Name) for your * `database` (string, required, default null): a DSN (Data Source Name) for your
GNU social database. This is in the format GNU social database. This is in the format
'protocol://username:password@hostname/databasename', where 'protocol' is ' 'protocol://username:password@hostname/databasename', where 'protocol' is
mysql' or 'mysqli' (or possibly 'postgresql', if you really know what 'mysqli' or 'pgsql' or 'mysql', 'username' is the username, 'password' is
you're doing), 'username' is the username, 'password' is the password, the password, and etc.
and etc.
* `ini_yourdbname` (string, default null): if your database is not named 'statusnet', * `ini_yourdbname` (string, default null): if your database is not named 'statusnet',
you'll need to set this to point to the location of the statusnet.ini file. you'll need to set this to point to the location of the statusnet.ini file.
@ -178,12 +177,9 @@ The ones that you may want to set are listed below for clarity.
'MDB2' to use the other driver type for DB_DataObject, but note that it 'MDB2' to use the other driver type for DB_DataObject, but note that it
breaks the OpenID libraries, which only support PEAR::DB. breaks the OpenID libraries, which only support PEAR::DB.
* `quote_identifiers`(boolean, default false): Set this to true if you're using * `type` (enum["mysql", "pgsql"], default 'mysql'): Used for certain
postgresql. database-specific optimization code. Assumes mysql if not set. "mysql"
covers MariaDB, Oracle MySQL, mysqli or otherwise.
* `type` (enum["mysql", "postgresql"], default 'mysql'): Used for certain
database-specific optimization code. Assumes mysql if not set. MySQL also
covers MySQLi and MariaDB.
* `mirror` (array, default null): you can set this to an array of DSNs, in the * `mirror` (array, default null): you can set this to an array of DSNs, in the
format of the above 'database' value. If it's set, certain read-only format of the above 'database' value. If it's set, certain read-only

View File

@ -1,55 +1,45 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Show the newest groups * Show the newest groups
* *
* 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 API * @category API
* @package StatusNet * @package GNUsocial
* @author Craig Andrews <candrews@integralblue.com> * @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com> * @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Returns of the lastest 20 groups for the site * Returns of the lastest 20 groups for the site
* *
* @category API * @copyright 2009 StatusNet, Inc.
* @package StatusNet * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @author Craig Andrews <candrews@integralblue.com> * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@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 ApiGroupListAllAction extends ApiPrivateAuthAction class ApiGroupListAllAction extends ApiPrivateAuthAction
{ {
var $groups = null; public $groups = null;
/** /**
* Take arguments for running * Take arguments for running
@ -58,7 +48,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return boolean success flag * @return boolean success flag
*/ */
function prepare(array $args = array()) public function prepare(array $args = [])
{ {
parent::prepare($args); parent::prepare($args);
@ -77,7 +67,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle() public function handle()
{ {
parent::handle(); parent::handle();
@ -90,7 +80,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
// TRANS: Message is used as a subtitle when listing the latest 20 groups. %s is a site name. // TRANS: Message is used as a subtitle when listing the latest 20 groups. %s is a site name.
$subtitle = sprintf(_("groups on %s"), $sitename); $subtitle = sprintf(_("groups on %s"), $sitename);
switch($this->format) { switch ($this->format) {
case 'xml': case 'xml':
$this->showXmlGroups($this->groups); $this->showXmlGroups($this->groups);
break; break;
@ -128,21 +118,20 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return array groups * @return array groups
*/ */
function getGroups() public function getGroups()
{ {
$qry = 'SELECT user_group.* '.
'from user_group join local_group on user_group.id = local_group.group_id '.
'order by created desc ';
$offset = intval($this->page - 1) * intval($this->count);
$limit = intval($this->count);
if (common_config('db', 'type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$group = new User_group(); $group = new User_group();
$group->query($qry); $offset = intval($this->page - 1) * intval($this->count);
$limit = intval($this->count);
$group->query(
'SELECT user_group.* '.
'FROM user_group INNER JOIN local_group ' .
'ON user_group.id = local_group.group_id '.
'ORDER BY created DESC ' .
'LIMIT ' . $limit . ' OFFSET ' . $offset
);
$groups = array(); $groups = array();
while ($group->fetch()) { while ($group->fetch()) {
@ -159,7 +148,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) public function isReadOnly($args)
{ {
return true; return true;
} }
@ -169,7 +158,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return string datestamp of the site's latest group * @return string datestamp of the site's latest group
*/ */
function lastModified() public function lastModified()
{ {
if (!empty($this->groups) && (count($this->groups) > 0)) { if (!empty($this->groups) && (count($this->groups) > 0)) {
return strtotime($this->groups[0]->created); return strtotime($this->groups[0]->created);
@ -186,10 +175,9 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() public function etag()
{ {
if (!empty($this->groups) && (count($this->groups) > 0)) { if (!empty($this->groups) && (count($this->groups) > 0)) {
$last = count($this->groups) - 1; $last = count($this->groups) - 1;
return '"' . implode( return '"' . implode(

View File

@ -1,48 +1,40 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Settings for email * Settings for email
* *
* 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 Settings * @category Settings
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Settings for email * Settings for email
* *
* @category Settings * @copyright 2008-2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@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 Widget * @see Widget
*/ */
class EmailsettingsAction extends SettingsAction class EmailsettingsAction extends SettingsAction
{ {
/** /**
@ -50,7 +42,7 @@ class EmailsettingsAction extends SettingsAction
* *
* @return string Title of the page * @return string Title of the page
*/ */
function title() public function title()
{ {
// TRANS: Title for e-mail settings. // TRANS: Title for e-mail settings.
return _('Email settings'); return _('Email settings');
@ -61,7 +53,7 @@ class EmailsettingsAction extends SettingsAction
* *
* @return instructions for use * @return instructions for use
*/ */
function getInstructions() public function getInstructions()
{ {
// XXX: For consistency of parameters in messages, this should be a // XXX: For consistency of parameters in messages, this should be a
// regular parameters, replaced with sprintf(). // regular parameters, replaced with sprintf().
@ -70,7 +62,7 @@ class EmailsettingsAction extends SettingsAction
return _('Manage how you get email from %%site.name%%.'); return _('Manage how you get email from %%site.name%%.');
} }
function showScripts() public function showScripts()
{ {
parent::showScripts(); parent::showScripts();
$this->script('emailsettings.js'); $this->script('emailsettings.js');
@ -85,7 +77,7 @@ class EmailsettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function showContent() public function showContent()
{ {
$user = $this->scoped->getUser(); $user = $this->scoped->getUser();
@ -106,35 +98,41 @@ class EmailsettingsAction extends SettingsAction
$this->element('p', array('class' => 'form_note'), _('Current confirmed email address.')); $this->element('p', array('class' => 'form_note'), _('Current confirmed email address.'));
$this->hidden('email', $user->email); $this->hidden('email', $user->email);
// TRANS: Button label to remove a confirmed e-mail address. // TRANS: Button label to remove a confirmed e-mail address.
$this->submit('remove', _m('BUTTON','Remove')); $this->submit('remove', _m('BUTTON', 'Remove'));
} else { } else {
try { try {
$confirm = $this->getConfirmation(); $confirm = $this->getConfirmation();
$this->element('p', array('id' => 'form_unconfirmed'), $confirm->address); $this->element('p', array('id' => 'form_unconfirmed'), $confirm->address);
$this->element('p', array('class' => 'form_note'), $this->element(
'p',
['class' => 'form_note'],
// TRANS: Form note in e-mail settings form. // TRANS: Form note in e-mail settings form.
_('Awaiting confirmation on this address. '. _('Awaiting confirmation on this address. '.
'Check your inbox (and spam box!) for a message '. 'Check your inbox (and spam box!) for a message '.
'with further instructions.')); 'with further instructions.')
);
$this->hidden('email', $confirm->address); $this->hidden('email', $confirm->address);
// TRANS: Button label to cancel an e-mail address confirmation procedure. // TRANS: Button label to cancel an e-mail address confirmation procedure.
$this->submit('cancel', _m('BUTTON','Cancel')); $this->submit('cancel', _m('BUTTON', 'Cancel'));
} catch (NoResultException $e) { } catch (NoResultException $e) {
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label for e-mail address input in e-mail settings form. // TRANS: Field label for e-mail address input in e-mail settings form.
$this->input('email', _('Email address'), $this->input(
'email',
_('Email address'),
$this->trimmed('email') ?: null, $this->trimmed('email') ?: null,
// TRANS: Instructions for e-mail address input form. Do not translate // TRANS: Instructions for e-mail address input form. Do not translate
// TRANS: "example.org". It is one of the domain names reserved for // TRANS: "example.org". It is one of the domain names reserved for
// TRANS: use in examples by http://www.rfc-editor.org/rfc/rfc2606.txt. // TRANS: use in examples by http://www.rfc-editor.org/rfc/rfc2606.txt.
// TRANS: Any other domain may be owned by a legitimate person or // TRANS: Any other domain may be owned by a legitimate person or
// TRANS: organization. // TRANS: organization.
_('Email address, like "UserName@example.org"')); _('Email address, like "UserName@example.org"')
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Button label for adding an e-mail address in e-mail settings form. // TRANS: Button label for adding an e-mail address in e-mail settings form.
$this->submit('add', _m('BUTTON','Add')); $this->submit('add', _m('BUTTON', 'Add'));
} }
} }
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
@ -146,10 +144,12 @@ class EmailsettingsAction extends SettingsAction
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('emailpost', $this->checkbox(
'emailpost',
// TRANS: Checkbox label in e-mail preferences form. // TRANS: Checkbox label in e-mail preferences form.
_('I want to post notices by email.'), _('I want to post notices by email.'),
$user->emailpost); $user->emailpost
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
@ -168,12 +168,15 @@ class EmailsettingsAction extends SettingsAction
$this->element('span', 'address', $user->incomingemail); $this->element('span', 'address', $user->incomingemail);
// @todo XXX: Looks a little awkward in the UI. // @todo XXX: Looks a little awkward in the UI.
// Something like "xxxx@identi.ca Send email ..". Needs improvement. // Something like "xxxx@identi.ca Send email ..". Needs improvement.
$this->element('span', 'input_instructions', $this->element(
'span',
'input_instructions',
// TRANS: Form instructions for incoming e-mail form in e-mail settings. // TRANS: Form instructions for incoming e-mail form in e-mail settings.
_('Send email to this address to post new notices.')); _('Send email to this address to post new notices.')
);
$this->elementEnd('p'); $this->elementEnd('p');
// TRANS: Button label for removing a set sender e-mail address to post notices from. // TRANS: Button label for removing a set sender e-mail address to post notices from.
$this->submit('removeincoming', _m('BUTTON','Remove')); $this->submit('removeincoming', _m('BUTTON', 'Remove'));
} }
$this->elementStart('p'); $this->elementStart('p');
@ -189,7 +192,7 @@ class EmailsettingsAction extends SettingsAction
$this->elementEnd('p'); $this->elementEnd('p');
// TRANS: Button label for adding an e-mail address to send notices from. // TRANS: Button label for adding an e-mail address to send notices from.
$this->submit('newincoming', _m('BUTTON','New')); $this->submit('newincoming', _m('BUTTON', 'New'));
$this->elementEnd('div'); // div#emailincoming $this->elementEnd('div'); // div#emailincoming
@ -204,34 +207,42 @@ class EmailsettingsAction extends SettingsAction
if (Event::handle('StartEmailFormData', array($this, $this->scoped))) { if (Event::handle('StartEmailFormData', array($this, $this->scoped))) {
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('emailnotifysub', $this->checkbox(
'emailnotifysub',
// TRANS: Checkbox label in e-mail preferences form. // TRANS: Checkbox label in e-mail preferences form.
_('Send me notices of new subscriptions through email.'), _('Send me notices of new subscriptions through email.'),
$user->emailnotifysub); $user->emailnotifysub
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('emailnotifymsg', $this->checkbox(
'emailnotifymsg',
// TRANS: Checkbox label in e-mail preferences form. // TRANS: Checkbox label in e-mail preferences form.
_('Send me email when someone sends me a private message.'), _('Send me email when someone sends me a private message.'),
$user->emailnotifymsg); $user->emailnotifymsg
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('emailnotifyattn', $this->checkbox(
'emailnotifyattn',
// TRANS: Checkbox label in e-mail preferences form. // TRANS: Checkbox label in e-mail preferences form.
_('Send me email when someone sends me an "@-reply".'), _('Send me email when someone sends me an "@-reply".'),
$user->emailnotifyattn); $user->emailnotifyattn
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('emailnotifynudge', $this->checkbox(
'emailnotifynudge',
// TRANS: Checkbox label in e-mail preferences form. // TRANS: Checkbox label in e-mail preferences form.
_('Allow friends to nudge me and send me an email.'), _('Allow friends to nudge me and send me an email.'),
$user->emailnotifynudge); $user->emailnotifynudge
);
$this->elementEnd('li'); $this->elementEnd('li');
Event::handle('EndEmailFormData', array($this, $this->scoped)); Event::handle('EndEmailFormData', array($this, $this->scoped));
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Button label to save e-mail preferences. // TRANS: Button label to save e-mail preferences.
$this->submit('save', _m('BUTTON','Save')); $this->submit('save', _m('BUTTON', 'Save'));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
@ -242,7 +253,7 @@ class EmailsettingsAction extends SettingsAction
* *
* @return Confirm_address Email address confirmation for user, or null * @return Confirm_address Email address confirmation for user, or null
*/ */
function getConfirmation() public function getConfirmation()
{ {
$confirm = new Confirm_address(); $confirm = new Confirm_address();
@ -260,15 +271,15 @@ class EmailsettingsAction extends SettingsAction
{ {
if ($this->arg('save')) { if ($this->arg('save')) {
return $this->savePreferences(); return $this->savePreferences();
} else if ($this->arg('add')) { } elseif ($this->arg('add')) {
return $this->addAddress(); return $this->addAddress();
} else if ($this->arg('cancel')) { } elseif ($this->arg('cancel')) {
return $this->cancelConfirmation(); return $this->cancelConfirmation();
} else if ($this->arg('remove')) { } elseif ($this->arg('remove')) {
return $this->removeAddress(); return $this->removeAddress();
} else if ($this->arg('removeincoming')) { } elseif ($this->arg('removeincoming')) {
return $this->removeIncoming(); return $this->removeIncoming();
} else if ($this->arg('newincoming')) { } elseif ($this->arg('newincoming')) {
return $this->newIncoming(); return $this->newIncoming();
} }
@ -281,14 +292,14 @@ class EmailsettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function savePreferences() public function savePreferences()
{ {
if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) { if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) {
$emailnotifysub = $this->booleanintstring('emailnotifysub'); $emailnotifysub = $this->boolean('emailnotifysub');
$emailnotifymsg = $this->booleanintstring('emailnotifymsg'); $emailnotifymsg = $this->boolean('emailnotifymsg');
$emailnotifynudge = $this->booleanintstring('emailnotifynudge'); $emailnotifynudge = $this->boolean('emailnotifynudge');
$emailnotifyattn = $this->booleanintstring('emailnotifyattn'); $emailnotifyattn = $this->boolean('emailnotifyattn');
$emailpost = $this->booleanintstring('emailpost'); $emailpost = $this->boolean('emailpost');
$user = $this->scoped->getUser(); $user = $this->scoped->getUser();
$user->query('BEGIN'); $user->query('BEGIN');
@ -322,7 +333,7 @@ class EmailsettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function addAddress() public function addAddress()
{ {
$user = $this->scoped->getUser(); $user = $this->scoped->getUser();
@ -344,16 +355,15 @@ class EmailsettingsAction extends SettingsAction
if (!Validate::email($email, common_config('email', 'check_domain'))) { if (!Validate::email($email, common_config('email', 'check_domain'))) {
// TRANS: Message given saving e-mail address that not valid. // TRANS: Message given saving e-mail address that not valid.
throw new ClientException(_('Not a valid email address.')); throw new ClientException(_('Not a valid email address.'));
} else if ($user->email == $email) { } elseif ($user->email === $email) {
// TRANS: Message given saving e-mail address that is already set. // TRANS: Message given saving e-mail address that is already set.
throw new ClientException(_('That is already your email address.')); throw new ClientException(_('That is already your email address.'));
} else if ($this->emailExists($email)) { } elseif ($this->emailExists($email)) {
// TRANS: Message given saving e-mail address that is already set for another user. // TRANS: Message given saving e-mail address that is already set for another user.
throw new ClientException(_('That email address already belongs to another user.')); throw new ClientException(_('That email address already belongs to another user.'));
} }
if (Event::handle('StartAddEmailAddress', array($user, $email))) { if (Event::handle('StartAddEmailAddress', array($user, $email))) {
$confirm = new Confirm_address(); $confirm = new Confirm_address();
$confirm->address = $email; $confirm->address = $email;
@ -385,7 +395,7 @@ class EmailsettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function cancelConfirmation() public function cancelConfirmation()
{ {
$email = $this->trimmed('email'); $email = $this->trimmed('email');
@ -411,7 +421,7 @@ class EmailsettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function removeAddress() public function removeAddress()
{ {
$user = common_current_user(); $user = common_current_user();
@ -425,7 +435,7 @@ class EmailsettingsAction extends SettingsAction
} }
$original = clone($user); $original = clone($user);
$user->email = null; $user->email = DB_DataObject_Cast::sql('NULL');
// Throws exception on failure. Also performs it within a transaction. // Throws exception on failure. Also performs it within a transaction.
$user->updateWithKeys($original); $user->updateWithKeys($original);
@ -438,7 +448,7 @@ class EmailsettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function removeIncoming() public function removeIncoming()
{ {
$user = common_current_user(); $user = common_current_user();
@ -448,8 +458,8 @@ class EmailsettingsAction extends SettingsAction
} }
$orig = clone($user); $orig = clone($user);
$user->incomingemail = null; $user->incomingemail = DB_DataObject_Cast::sql('NULL');
$user->emailpost = 0; $user->emailpost = false;
// Throws exception on failure. Also performs it within a transaction. // Throws exception on failure. Also performs it within a transaction.
$user->updateWithKeys($orig); $user->updateWithKeys($orig);
@ -462,12 +472,12 @@ class EmailsettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function newIncoming() public function newIncoming()
{ {
$user = common_current_user(); $user = common_current_user();
$orig = clone($user); $orig = clone($user);
$user->incomingemail = mail_new_incoming_address(); $user->incomingemail = mail_new_incoming_address();
$user->emailpost = 1; $user->emailpost = true;
// Throws exception on failure. Also performs it within a transaction. // Throws exception on failure. Also performs it within a transaction.
$user->updateWithKeys($orig); $user->updateWithKeys($orig);
@ -485,7 +495,7 @@ class EmailsettingsAction extends SettingsAction
* @return boolean Whether the email already exists. * @return boolean Whether the email already exists.
*/ */
function emailExists($email) public function emailExists($email)
{ {
$user = common_current_user(); $user = common_current_user();

View File

@ -1,36 +1,31 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* List of featured users * List of featured users
* *
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public * @category Public
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
require_once INSTALLDIR . '/lib/profile/profilelist.php'; require_once INSTALLDIR . '/lib/profile/profilelist.php';
require_once INSTALLDIR . '/lib/groups/publicgroupnav.php'; require_once INSTALLDIR . '/lib/groups/publicgroupnav.php';
@ -38,23 +33,19 @@ require_once INSTALLDIR . '/lib/groups/publicgroupnav.php';
/** /**
* List of featured users * List of featured users
* *
* @category Public * @copyright 2008-2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Zach Copley <zach@status.net>
* @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 FeaturedAction extends Action class FeaturedAction extends Action
{ {
var $page = null; public $page = null;
function isReadOnly($args) public function isReadOnly($args)
{ {
return true; return true;
} }
function prepare(array $args = array()) public function prepare(array $args = [])
{ {
parent::prepare($args); parent::prepare($args);
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
@ -62,7 +53,7 @@ class FeaturedAction extends Action
return true; return true;
} }
function title() public function title()
{ {
if ($this->page == 1) { if ($this->page == 1) {
// TRANS: Page title for first page of featured users. // TRANS: Page title for first page of featured users.
@ -74,14 +65,14 @@ class FeaturedAction extends Action
} }
} }
function handle() public function handle()
{ {
parent::handle(); parent::handle();
$this->showPage(); $this->showPage();
} }
function showPageNotice() public function showPageNotice()
{ {
$instr = $this->getInstructions(); $instr = $this->getInstructions();
$output = common_markup_to_html($instr); $output = common_markup_to_html($instr);
@ -90,14 +81,16 @@ class FeaturedAction extends Action
$this->elementEnd('div'); $this->elementEnd('div');
} }
function getInstructions() public function getInstructions()
{ {
// TRANS: Description on page displaying featured users. // TRANS: Description on page displaying featured users.
return sprintf(_('A selection of some great users on %s.'), return sprintf(
common_config('site', 'name')); _('A selection of some great users on %s.'),
common_config('site', 'name')
);
} }
function showContent() public function showContent()
{ {
// XXX: Note I'm doing it this two-stage way because a raw query // XXX: Note I'm doing it this two-stage way because a raw query
// with a JOIN was *not* working. --Zach // with a JOIN was *not* working. --Zach
@ -105,7 +98,6 @@ class FeaturedAction extends Action
$featured_nicks = common_config('nickname', 'featured'); $featured_nicks = common_config('nickname', 'featured');
if (count($featured_nicks) > 0) { if (count($featured_nicks) > 0) {
$quoted = array(); $quoted = array();
foreach ($featured_nicks as $nick) { foreach ($featured_nicks as $nick) {
@ -115,7 +107,7 @@ class FeaturedAction extends Action
$user = new User; $user = new User;
$user->whereAdd(sprintf('nickname IN (%s)', implode(',', $quoted))); $user->whereAdd(sprintf('nickname IN (%s)', implode(',', $quoted)));
$user->limit(($this->page - 1) * PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1); $user->limit(($this->page - 1) * PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
$user->orderBy(common_database_tablename('user') .'.nickname ASC'); $user->orderBy($user->escapedTableName() . '.nickname ASC');
$user->find(); $user->find();
@ -138,8 +130,12 @@ class FeaturedAction extends Action
$profile->free(); $profile->free();
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, $this->pagination(
$this->page, 'featured'); $this->page > 1,
$cnt > PROFILES_PER_PAGE,
$this->page,
'featured'
);
} }
} }
} }

View File

@ -1,50 +1,41 @@
<?php <?php
/** // This file is part of GNU social - https://www.gnu.org/software/social
* Make another user an admin of a group //
* // GNU social is free software: you can redistribute it and/or modify
* PHP version 5 // 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
* @category Action // (at your option) any later version.
* @package StatusNet //
* @author Evan Prodromou <evan@status.net> // GNU social is distributed in the hope that it will be useful,
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 // but WITHOUT ANY WARRANTY; without even the implied warranty of
* @link http://status.net/ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* // GNU Affero General Public License for more details.
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // You should have received a copy of the GNU Affero General Public License
* // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
/** /**
* Make another user an admin of a group * Make another user an admin of a group
* *
* @category Action * @category Action
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2008, 2009 StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
defined('GNUSOCIAL') || die();
/**
* Make another user an admin of a group
*
* @copyright 2008, 2009 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
class MakeadminAction extends RedirectingAction class MakeadminAction extends RedirectingAction
{ {
var $profile = null; public $profile = null;
var $group = null; public $group = null;
/** /**
* Take arguments for running * Take arguments for running
@ -54,7 +45,7 @@ class MakeadminAction extends RedirectingAction
* @return boolean success flag * @return boolean success flag
*/ */
function prepare(array $args = array()) public function prepare(array $args = [])
{ {
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
@ -95,10 +86,14 @@ class MakeadminAction extends RedirectingAction
if ($this->profile->isAdmin($this->group)) { if ($this->profile->isAdmin($this->group)) {
// TRANS: Client error displayed when trying to make another user admin on the Make Admin page who already is admin. // TRANS: Client error displayed when trying to make another user admin on the Make Admin page who already is admin.
// TRANS: %1$s is the user that is already admin, %2$s is the group user is already admin for. // TRANS: %1$s is the user that is already admin, %2$s is the group user is already admin for.
$this->clientError(sprintf(_('%1$s is already an admin for group "%2$s".'), $this->clientError(
sprintf(
_('%1$s is already an admin for group "%2$s".'),
$this->profile->getBestName(), $this->profile->getBestName(),
$this->group->getBestName()), $this->group->getBestName()
401); ),
401
);
} }
return true; return true;
} }
@ -111,7 +106,7 @@ class MakeadminAction extends RedirectingAction
* @return void * @return void
*/ */
function handle() public function handle()
{ {
parent::handle(); parent::handle();
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
@ -125,7 +120,7 @@ class MakeadminAction extends RedirectingAction
* @return void * @return void
*/ */
function makeAdmin() public function makeAdmin()
{ {
$member = Group_member::pkeyGet(array('group_id' => $this->group->id, $member = Group_member::pkeyGet(array('group_id' => $this->group->id,
'profile_id' => $this->profile->id)); 'profile_id' => $this->profile->id));
@ -134,14 +129,16 @@ class MakeadminAction extends RedirectingAction
// TRANS: Server error displayed when trying to make another user admin on the Make Admin page fails // TRANS: Server error displayed when trying to make another user admin on the Make Admin page fails
// TRANS: because the group membership record could not be gotten. // TRANS: because the group membership record could not be gotten.
// TRANS: %1$s is the to be admin user, %2$s is the group user should be admin for. // TRANS: %1$s is the to be admin user, %2$s is the group user should be admin for.
$this->serverError(_('Can\'t get membership record for %1$s in group %2$s.'), $this->serverError(
_('Can\'t get membership record for %1$s in group %2$s.'),
$this->profile->getBestName(), $this->profile->getBestName(),
$this->group->getBestName()); $this->group->getBestName()
);
} }
$orig = clone($member); $orig = clone($member);
$member->is_admin = 1; $member->is_admin = true;
$result = $member->update($orig); $result = $member->update($orig);
@ -150,9 +147,11 @@ class MakeadminAction extends RedirectingAction
// TRANS: Server error displayed when trying to make another user admin on the Make Admin page fails // TRANS: Server error displayed when trying to make another user admin on the Make Admin page fails
// TRANS: because the group adminship record coud not be saved properly. // TRANS: because the group adminship record coud not be saved properly.
// TRANS: %1$s is the to be admin user, %2$s is the group user is already admin for. // TRANS: %1$s is the to be admin user, %2$s is the group user is already admin for.
$this->serverError(_('Can\'t make %1$s an admin for group %2$s.'), $this->serverError(
_('Can\'t make %1$s an admin for group %2$s.'),
$this->profile->getBestName(), $this->profile->getBestName(),
$this->group->getBestName()); $this->group->getBestName()
);
} }
$this->returnToPrevious(); $this->returnToPrevious();
@ -164,10 +163,11 @@ class MakeadminAction extends RedirectingAction
* *
* @return string URL * @return string URL
*/ */
function defaultReturnTo() public function defaultReturnTo()
{ {
return common_local_url('groupmembers', return common_local_url(
array('nickname' => $this->group->nickname)); 'groupmembers',
['nickname' => $this->group->nickname]
);
} }
} }

View File

@ -1,46 +1,38 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Change profile settings * Change profile settings
* *
* 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 Settings * @category Settings
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @author Sarven Capadisli <csarven@status.net> * @author Sarven Capadisli <csarven@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Change profile settings * Change profile settings
* *
* @category Settings * @copyright 2008-2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@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/
*/ */
class ProfilesettingsAction extends SettingsAction class ProfilesettingsAction extends SettingsAction
{ {
@ -49,7 +41,7 @@ class ProfilesettingsAction extends SettingsAction
* *
* @return string Title of the page * @return string Title of the page
*/ */
function title() public function title()
{ {
// TRANS: Page title for profile settings. // TRANS: Page title for profile settings.
return _('Profile settings'); return _('Profile settings');
@ -60,14 +52,14 @@ class ProfilesettingsAction extends SettingsAction
* *
* @return instructions for use * @return instructions for use
*/ */
function getInstructions() public function getInstructions()
{ {
// TRANS: Usage instructions for profile settings. // TRANS: Usage instructions for profile settings.
return _('You can update your personal profile info here '. return _('You can update your personal profile info here '.
'so people know more about you.'); 'so people know more about you.');
} }
function showScripts() public function showScripts()
{ {
parent::showScripts(); parent::showScripts();
$this->autofocus('fullname'); $this->autofocus('fullname');
@ -80,7 +72,7 @@ class ProfilesettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function showContent() public function showContent()
{ {
$user = $this->scoped->getUser(); $user = $this->scoped->getUser();
@ -98,29 +90,40 @@ class ProfilesettingsAction extends SettingsAction
if (Event::handle('StartProfileFormData', array($this))) { if (Event::handle('StartProfileFormData', array($this))) {
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings. // TRANS: Field label in form for profile settings.
$this->input('nickname', _('Nickname'), $this->input(
'nickname',
_('Nickname'),
$this->trimmed('nickname') ?: $this->scoped->getNickname(), $this->trimmed('nickname') ?: $this->scoped->getNickname(),
// TRANS: Tooltip for field label in form for profile settings. // TRANS: Tooltip for field label in form for profile settings.
_('1-64 lowercase letters or numbers, no punctuation or spaces.'), _('1-64 lowercase letters or numbers, no punctuation or spaces.'),
null, false, // "name" (will be set to id), then "required" null,
!common_config('profile', 'changenick') false, // "name" (will be set to id), then "required"
? array('disabled' => 'disabled', 'placeholder' => null) (common_config('profile', 'changenick')
: array('placeholder' => null)); ? ['placeholder' => null]
: ['disabled' => 'disabled', 'placeholder' => null])
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings. // TRANS: Field label in form for profile settings.
$this->input('fullname', _('Full name'), $this->input(
'fullname',
_('Full name'),
$this->trimmed('fullname') ?: $this->scoped->getFullname(), $this->trimmed('fullname') ?: $this->scoped->getFullname(),
// TRANS: Instructions for full name text field on profile settings // TRANS: Instructions for full name text field on profile settings
_('A full name is required, if empty it will be set to your nickname.'), _('A full name is required, if empty it will be set to your nickname.'),
null, true); null,
true
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings. // TRANS: Field label in form for profile settings.
$this->input('homepage', _('Homepage'), $this->input(
'homepage',
_('Homepage'),
$this->trimmed('homepage') ?: $this->scoped->getHomepage(), $this->trimmed('homepage') ?: $this->scoped->getHomepage(),
// TRANS: Tooltip for field label in form for profile settings. // TRANS: Tooltip for field label in form for profile settings.
_('URL of your homepage, blog, or profile on another site.')); _('URL of your homepage, blog, or profile on another site.')
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$maxBio = Profile::maxBio(); $maxBio = Profile::maxBio();
@ -128,97 +131,129 @@ class ProfilesettingsAction extends SettingsAction
// TRANS: Tooltip for field label in form for profile settings. Plural // TRANS: Tooltip for field label in form for profile settings. Plural
// TRANS: is decided by the number of characters available for the // TRANS: is decided by the number of characters available for the
// TRANS: biography (%d). // TRANS: biography (%d).
$bioInstr = sprintf(_m('Describe yourself and your interests in %d character.', $bioInstr = sprintf(
_m('Describe yourself and your interests in %d character.',
'Describe yourself and your interests in %d characters.', 'Describe yourself and your interests in %d characters.',
$maxBio), $maxBio),
$maxBio); $maxBio
);
} else { } else {
// TRANS: Tooltip for field label in form for profile settings. // 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. // TRANS: their biography.
$this->textarea('bio', _('Bio'), $this->textarea(
$this->trimmed('bio') ?: $this->scoped->getDescription(), 'bio',
$bioInstr); _('Bio'),
($this->trimmed('bio') ?: $this->scoped->getDescription()),
$bioInstr
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings. // TRANS: Field label in form for profile settings.
$this->input('location', _('Location'), $this->input(
$this->trimmed('location') ?: $this->scoped->location, 'location',
_('Location'),
($this->trimmed('location') ?: $this->scoped->location),
// TRANS: Tooltip for field label in form for profile settings. // 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'); $this->elementEnd('li');
if (common_config('location', 'share') == 'user') { if (common_config('location', 'share') == 'user') {
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Checkbox label in form for profile settings. // TRANS: Checkbox label in form for profile settings.
$this->checkbox('sharelocation', _('Share my current location when posting notices'), $this->checkbox(
($this->arg('sharelocation')) ? 'sharelocation',
$this->boolean('sharelocation') : $this->scoped->shareLocation()); _('Share my current location when posting notices'),
($this->arg('sharelocation') ?
$this->boolean('sharelocation') : $this->scoped->shareLocation())
);
$this->elementEnd('li'); $this->elementEnd('li');
} }
Event::handle('EndProfileFormData', array($this)); Event::handle('EndProfileFormData', array($this));
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label in form for profile settings. // TRANS: Field label in form for profile settings.
$this->input('tags', _('Tags'), $this->input(
$this->trimmed('tags') ?: implode(' ', Profile_tag::getSelfTagsArray($this->scoped)), 'tags',
_('Tags'),
($this->trimmed('tags') ?: implode(' ', Profile_tag::getSelfTagsArray($this->scoped))),
// TRANS: Tooltip for field label in form for profile settings. // TRANS: Tooltip for field label in form for profile settings.
_('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated.')); _('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated.')
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$language = common_language(); $language = common_language();
// TRANS: Dropdownlist label in form for profile settings. // TRANS: Dropdownlist label in form for profile settings.
$this->dropdown('language', _('Language'), $this->dropdown(
'language',
_('Language'),
// TRANS: Tooltip for dropdown list label in form for profile settings. // TRANS: Tooltip for dropdown list label in form for profile settings.
get_nice_language_list(), _('Preferred language.'), get_nice_language_list(),
false, $language); _('Preferred language.'),
false,
$language
);
$this->elementEnd('li'); $this->elementEnd('li');
$timezone = common_timezone(); $timezone = common_timezone();
$timezones = array(); $timezones = array();
foreach(DateTimeZone::listIdentifiers() as $k => $v) { foreach (DateTimeZone::listIdentifiers() as $k => $v) {
$timezones[$v] = $v; $timezones[$v] = $v;
} }
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Dropdownlist label in form for profile settings. // TRANS: Dropdownlist label in form for profile settings.
$this->dropdown('timezone', _('Timezone'), $this->dropdown(
'timezone',
_('Timezone'),
// TRANS: Tooltip for dropdown list label in form for profile settings. // TRANS: Tooltip for dropdown list label in form for profile settings.
$timezones, _('What timezone are you normally in?'), $timezones,
true, $timezone); _('What timezone are you normally in?'),
true,
$timezone
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('autosubscribe', $this->checkbox(
'autosubscribe',
// TRANS: Checkbox label in form for profile settings. // TRANS: Checkbox label in form for profile settings.
_('Automatically subscribe to whoever '. _('Automatically subscribe to whoever '.
'subscribes to me (best for non-humans)'), 'subscribes to me (best for non-humans)'),
($this->arg('autosubscribe')) ? ($this->arg('autosubscribe') ?
$this->boolean('autosubscribe') : $user->autosubscribe); $this->boolean('autosubscribe') : $user->autosubscribe)
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
$this->dropdown('subscribe_policy', $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. // TRANS: Dropdown field label on profile settings, for what policies to apply when someone else tries to subscribe to your updates.
_('Subscription policy'), _('Subscription policy'),
[
// TRANS: Dropdown field option for following policy. // TRANS: Dropdown field option for following policy.
array(User::SUBSCRIBE_POLICY_OPEN => _('Let anyone follow me'), User::SUBSCRIBE_POLICY_OPEN => _('Let anyone follow me'),
// TRANS: Dropdown field option for following policy. // TRANS: Dropdown field option for following policy.
User::SUBSCRIBE_POLICY_MODERATE => _('Ask me first')), User::SUBSCRIBE_POLICY_MODERATE => _('Ask me first'),
],
// TRANS: Dropdown field title on group edit form. // TRANS: Dropdown field title on group edit form.
_('Whether other users need your permission to follow your updates.'), _('Whether other users need your permission to follow your updates.'),
false, false,
(empty($user->subscribe_policy)) ? User::SUBSCRIBE_POLICY_OPEN : $user->subscribe_policy); (empty($user->subscribe_policy) ? User::SUBSCRIBE_POLICY_OPEN : $user->subscribe_policy)
);
$this->elementEnd('li'); $this->elementEnd('li');
} }
if (common_config('profile', 'allowprivate') || $user->private_stream) { if (common_config('profile', 'allowprivate') || $user->private_stream) {
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('private_stream', $this->checkbox(
'private_stream',
// TRANS: Checkbox label in profile settings. // TRANS: Checkbox label in profile settings.
_('Make updates visible only to my followers'), _('Make updates visible only to my followers'),
($this->arg('private_stream')) ? ($this->arg('private_stream') ?
$this->boolean('private_stream') : $user->private_stream); $this->boolean('private_stream') : $user->private_stream)
);
$this->elementEnd('li'); $this->elementEnd('li');
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Button to save input in profile settings. // TRANS: Button to save input in profile settings.
$this->submit('save', _m('BUTTON','Save')); $this->submit('save', _m('BUTTON', 'Save'));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
@ -255,7 +290,7 @@ class ProfilesettingsAction extends SettingsAction
$homepage = $this->trimmed('homepage'); $homepage = $this->trimmed('homepage');
$bio = $this->trimmed('bio'); $bio = $this->trimmed('bio');
$location = $this->trimmed('location'); $location = $this->trimmed('location');
$autosubscribe = $this->booleanintstring('autosubscribe'); $autosubscribe = $this->boolean('autosubscribe');
$subscribe_policy = $this->trimmed('subscribe_policy'); $subscribe_policy = $this->trimmed('subscribe_policy');
$language = $this->trimmed('language'); $language = $this->trimmed('language');
$timezone = $this->trimmed('timezone'); $timezone = $this->trimmed('timezone');
@ -266,24 +301,26 @@ class ProfilesettingsAction extends SettingsAction
!common_valid_http_url($homepage)) { !common_valid_http_url($homepage)) {
// TRANS: Validation error in form for profile settings. // TRANS: Validation error in form for profile settings.
throw new ClientException(_('Homepage is not a valid URL.')); throw new ClientException(_('Homepage is not a valid URL.'));
} else if (!is_null($fullname) && mb_strlen($fullname) > 191) { } elseif (!is_null($fullname) && mb_strlen($fullname) > 191) {
// TRANS: Validation error in form for profile settings. // TRANS: Validation error in form for profile settings.
throw new ClientException(_('Full name is too long (maximum 191 characters).')); throw new ClientException(_('Full name is too long (maximum 191 characters).'));
} else if (Profile::bioTooLong($bio)) { } elseif (Profile::bioTooLong($bio)) {
// TRANS: Validation error in form for profile settings. // TRANS: Validation error in form for profile settings.
// TRANS: Plural form is used based on the maximum number of allowed // TRANS: Plural form is used based on the maximum number of allowed
// TRANS: characters for the biography (%d). // TRANS: characters for the biography (%d).
throw new ClientException(sprintf(_m('Bio is too long (maximum %d character).', throw new ClientException(sprintf(
_m('Bio is too long (maximum %d character).',
'Bio is too long (maximum %d characters).', 'Bio is too long (maximum %d characters).',
Profile::maxBio()), Profile::maxBio()),
Profile::maxBio())); Profile::maxBio()
} else if (!is_null($location) && mb_strlen($location) > 191) { ));
} elseif (!is_null($location) && mb_strlen($location) > 191) {
// TRANS: Validation error in form for profile settings. // TRANS: Validation error in form for profile settings.
throw new ClientException(_('Location is too long (maximum 191 characters).')); throw new ClientException(_('Location is too long (maximum 191 characters).'));
} else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) { } elseif (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) {
// TRANS: Validation error in form for profile settings. // TRANS: Validation error in form for profile settings.
throw new ClientException(_('Timezone not selected.')); throw new ClientException(_('Timezone not selected.'));
} else if (!is_null($language) && strlen($language) > 50) { } elseif (!is_null($language) && strlen($language) > 50) {
// TRANS: Validation error in form for profile settings. // TRANS: Validation error in form for profile settings.
throw new ClientException(_('Language is too long (maximum 50 characters).')); throw new ClientException(_('Language is too long (maximum 50 characters).'));
} }
@ -291,7 +328,6 @@ class ProfilesettingsAction extends SettingsAction
$tags = array(); $tags = array();
$tag_priv = array(); $tag_priv = array();
if (is_string($tagstring) && strlen($tagstring) > 0) { if (is_string($tagstring) && strlen($tagstring) > 0) {
$tags = preg_split('/[\s,]+/', $tagstring); $tags = preg_split('/[\s,]+/', $tagstring);
foreach ($tags as &$tag) { foreach ($tags as &$tag) {
@ -314,21 +350,19 @@ class ProfilesettingsAction extends SettingsAction
// Only allow setting private_stream if site policy allows it // Only allow setting private_stream if site policy allows it
// (or user already _has_ a private stream, then you can unset it) // (or user already _has_ a private stream, then you can unset it)
if (common_config('profile', 'allowprivate') || $user->private_stream) { if (common_config('profile', 'allowprivate') || $user->private_stream) {
$private_stream = $this->booleanintstring('private_stream'); $private_stream = $this->boolean('private_stream');
} else { } else {
// if not allowed, we set to the existing value // if not allowed, we set to the existing value
$private_stream = $user->private_stream; $private_stream = (bool) $user->private_stream;
} }
// $user->nickname is updated through Profile->update(); // $user->nickname is updated through Profile->update();
// XXX: XOR if ((bool) $user->autosubscribe != $autosubscribe
if (($user->autosubscribe ^ $autosubscribe) || (bool) $user->private_stream != $private_stream
|| ($user->private_stream ^ $private_stream)
|| $user->timezone != $timezone || $user->timezone != $timezone
|| $user->language != $language || $user->language != $language
|| $user->subscribe_policy != $subscribe_policy) { || $user->subscribe_policy != $subscribe_policy) {
$original = clone($user); $original = clone($user);
$user->autosubscribe = $autosubscribe; $user->autosubscribe = $autosubscribe;
@ -378,7 +412,6 @@ class ProfilesettingsAction extends SettingsAction
} }
if (common_config('location', 'share') == 'user') { if (common_config('location', 'share') == 'user') {
$exists = false; $exists = false;
$prefs = User_location_prefs::getKV('user_id', $this->scoped->getID()); $prefs = User_location_prefs::getKV('user_id', $this->scoped->getID());
@ -393,7 +426,7 @@ class ProfilesettingsAction extends SettingsAction
$orig = clone($prefs); $orig = clone($prefs);
} }
$prefs->share_location = $this->booleanintstring('sharelocation'); $prefs->share_location = $this->boolean('sharelocation');
if ($exists) { if ($exists) {
$result = $prefs->update($orig); $result = $prefs->update($orig);
@ -429,11 +462,11 @@ class ProfilesettingsAction extends SettingsAction
// TRANS: Confirmation shown when user profile settings are saved. // TRANS: Confirmation shown when user profile settings are saved.
return _('Settings saved.'); return _('Settings saved.');
} }
} }
function showAside() { public function showAside()
{
$this->elementStart('div', array('id' => 'aside_primary', $this->elementStart('div', array('id' => 'aside_primary',
'class' => 'aside')); 'class' => 'aside'));
@ -443,26 +476,32 @@ class ProfilesettingsAction extends SettingsAction
if (Event::handle('StartProfileSettingsActions', array($this))) { if (Event::handle('StartProfileSettingsActions', array($this))) {
if ($this->scoped->hasRight(Right::BACKUPACCOUNT)) { if ($this->scoped->hasRight(Right::BACKUPACCOUNT)) {
$this->elementStart('li'); $this->elementStart('li');
$this->element('a', $this->element(
array('href' => common_local_url('backupaccount')), 'a',
['href' => common_local_url('backupaccount')],
// TRANS: Option in profile settings to create a backup of the account of the currently logged in user. // TRANS: Option in profile settings to create a backup of the account of the currently logged in user.
_('Backup account')); _('Backup account')
);
$this->elementEnd('li'); $this->elementEnd('li');
} }
if ($this->scoped->hasRight(Right::DELETEACCOUNT)) { if ($this->scoped->hasRight(Right::DELETEACCOUNT)) {
$this->elementStart('li'); $this->elementStart('li');
$this->element('a', $this->element(
array('href' => common_local_url('deleteaccount')), 'a',
['href' => common_local_url('deleteaccount')],
// TRANS: Option in profile settings to delete the account of the currently logged in user. // TRANS: Option in profile settings to delete the account of the currently logged in user.
_('Delete account')); _('Delete account')
);
$this->elementEnd('li'); $this->elementEnd('li');
} }
if ($this->scoped->hasRight(Right::RESTOREACCOUNT)) { if ($this->scoped->hasRight(Right::RESTOREACCOUNT)) {
$this->elementStart('li'); $this->elementStart('li');
$this->element('a', $this->element(
array('href' => common_local_url('restoreaccount')), 'a',
['href' => common_local_url('restoreaccount')],
// TRANS: Option in profile settings to restore the account of the currently logged in user from a backup. // TRANS: Option in profile settings to restore the account of the currently logged in user from a backup.
_('Restore account')); _('Restore account')
);
$this->elementEnd('li'); $this->elementEnd('li');
} }
Event::handle('EndProfileSettingsActions', array($this)); Event::handle('EndProfileSettingsActions', array($this));

View File

@ -1,53 +1,45 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Action for showing profiles self-tagged with a given tag * Action for showing profiles self-tagged with a given tag
* *
* 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 Action * @category Action
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* This class outputs a paginated list of profiles self-tagged with a given tag * This class outputs a paginated list of profiles self-tagged with a given tag
* *
* @category Output * @category Output
* @package StatusNet * @copyright 2009 StatusNet, Inc.
* @author Evan Prodromou <evan@status.net> * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Zach Copley <zach@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 Action * @see Action
*/ */
class SelftagAction extends Action class SelftagAction extends Action
{ {
var $tag = null; public $tag = null;
var $page = null; public $page = null;
/** /**
* For initializing members of the class. * For initializing members of the class.
@ -57,7 +49,7 @@ class SelftagAction extends Action
* @return boolean true * @return boolean true
* @throws ClientException * @throws ClientException
*/ */
function prepare(array $args = []) public function prepare(array $args = [])
{ {
parent::prepare($args); parent::prepare($args);
@ -66,8 +58,10 @@ class SelftagAction extends Action
if (!common_valid_profile_tag($this->tag)) { if (!common_valid_profile_tag($this->tag)) {
// TRANS: Client error displayed when trying to list a profile with an invalid list. // TRANS: Client error displayed when trying to list a profile with an invalid list.
// TRANS: %s is the invalid list name. // TRANS: %s is the invalid list name.
$this->clientError(sprintf(_('Not a valid list: %s.'), $this->clientError(sprintf(
$this->tag)); _('Not a valid list: %s.'),
$this->tag
));
return null; return null;
} }
@ -83,7 +77,7 @@ class SelftagAction extends Action
* *
* @return void is read only action? * @return void is read only action?
*/ */
function handle() public function handle()
{ {
parent::handle(); parent::handle();
$this->showPage(); $this->showPage();
@ -94,19 +88,13 @@ class SelftagAction extends Action
* people tag and page, initalizes a ProfileList widget, and displays * people tag and page, initalizes a ProfileList widget, and displays
* it to the user. * it to the user.
*/ */
function showContent() public function showContent()
{ {
$profile = new Profile(); $profile = new Profile();
$offset = ($this->page - 1) * PROFILES_PER_PAGE; $offset = ($this->page - 1) * PROFILES_PER_PAGE;
$limit = PROFILES_PER_PAGE + 1; $limit = PROFILES_PER_PAGE + 1;
if (common_config('db', 'type') == 'pgsql') {
$lim = ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$lim = ' LIMIT ' . $offset . ', ' . $limit;
}
// XXX: memcached this // XXX: memcached this
$qry = 'SELECT profile.* ' . $qry = 'SELECT profile.* ' .
@ -125,18 +113,21 @@ class SelftagAction extends Action
' OR profile_list.private = false) '; ' OR profile_list.private = false) ';
} }
$qry .= 'ORDER BY profile_tag.modified DESC%s'; $qry .= 'ORDER BY profile_tag.modified DESC ' .
'LIMIT ' . $limit . ' OFFSET ' . $offset;
$profile->query(sprintf($qry, $this->tag, $lim)); $profile->query(sprintf($qry, $this->tag));
$ptl = new SelfTagProfileList($profile, $this); // pass the ammunition $ptl = new SelfTagProfileList($profile, $this); // pass the ammunition
$cnt = $ptl->show(); $cnt = $ptl->show();
$this->pagination($this->page > 1, $this->pagination(
$this->page > 1,
$cnt > PROFILES_PER_PAGE, $cnt > PROFILES_PER_PAGE,
$this->page, $this->page,
'selftag', 'selftag',
array('tag' => $this->tag)); ['tag' => $this->tag]
);
} }
/** /**
@ -144,18 +135,21 @@ class SelftagAction extends Action
* *
* @return string page title * @return string page title
*/ */
function title() public function title()
{ {
// TRANS: Page title for page showing self tags. // TRANS: Page title for page showing self tags.
// TRANS: %1$s is a tag, %2$d is a page number. // TRANS: %1$s is a tag, %2$d is a page number.
return sprintf(_('Users self-tagged with %1$s, page %2$d'), return sprintf(
$this->tag, $this->page); _('Users self-tagged with %1$s, page %2$d'),
$this->tag,
$this->page
);
} }
} }
class SelfTagProfileList extends ProfileList class SelfTagProfileList extends ProfileList
{ {
function newListItem(Profile $target) public function newListItem(Profile $target)
{ {
return new SelfTagProfileListItem($target, $this->action); return new SelfTagProfileListItem($target, $this->action);
} }
@ -163,7 +157,7 @@ class SelfTagProfileList extends ProfileList
class SelfTagProfileListItem extends ProfileListItem class SelfTagProfileListItem extends ProfileListItem
{ {
function linkAttributes() public function linkAttributes()
{ {
$aAttrs = parent::linkAttributes(); $aAttrs = parent::linkAttributes();
@ -174,7 +168,7 @@ class SelfTagProfileListItem extends ProfileListItem
return $aAttrs; return $aAttrs;
} }
function homepageAttributes() public function homepageAttributes()
{ {
$aAttrs = parent::linkAttributes(); $aAttrs = parent::linkAttributes();
@ -185,7 +179,7 @@ class SelfTagProfileListItem extends ProfileListItem
return $aAttrs; return $aAttrs;
} }
function showTags() public function showTags()
{ {
$selftags = new SelfTagsWidget($this->out, $this->profile, $this->profile); $selftags = new SelfTagsWidget($this->out, $this->profile, $this->profile);
$selftags->show(); $selftags->show();

View File

@ -1,46 +1,39 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool * Settings for SMS.
* *
* Settings for SMS * @category Setting
* * @package GNUsocial
* 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 Settings
* @package StatusNet
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Settings for SMS * Settings for SMS
* *
* @category Settings * @copyright 2008-2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @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/
* *
* @see SettingsAction * @see SettingsAction
*/ */
class SmssettingsAction extends SettingsAction class SmssettingsAction extends SettingsAction
{ {
protected function doPreparation() protected function doPreparation()
@ -56,7 +49,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return string Title of the page * @return string Title of the page
*/ */
function title() public function title()
{ {
// TRANS: Title for SMS settings. // TRANS: Title for SMS settings.
return _('SMS settings'); return _('SMS settings');
@ -67,7 +60,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return instructions for use * @return instructions for use
*/ */
function getInstructions() public function getInstructions()
{ {
// XXX: For consistency of parameters in messages, this should be a // XXX: For consistency of parameters in messages, this should be a
// regular parameters, replaced with sprintf(). // regular parameters, replaced with sprintf().
@ -76,7 +69,7 @@ class SmssettingsAction extends SettingsAction
return _('You can receive SMS messages through email from %%site.name%%.'); return _('You can receive SMS messages through email from %%site.name%%.');
} }
function showScripts() public function showScripts()
{ {
parent::showScripts(); parent::showScripts();
$this->autofocus('sms'); $this->autofocus('sms');
@ -90,7 +83,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function showContent() public function showContent()
{ {
$user = $this->scoped->getUser(); $user = $this->scoped->getUser();
@ -107,80 +100,105 @@ class SmssettingsAction extends SettingsAction
if ($user->sms) { if ($user->sms) {
$carrier = $user->getCarrier(); $carrier = $user->getCarrier();
$this->element('p', 'form_confirmed', $this->element(
$user->sms . ' (' . $carrier->name . ')'); 'p',
$this->element('p', 'form_guide', 'form_confirmed',
$user->sms . ' (' . $carrier->name . ')'
);
$this->element(
'p',
'form_guide',
// TRANS: Form guide in SMS settings form. // TRANS: Form guide in SMS settings form.
_('Current confirmed SMS-enabled phone number.')); _('Current confirmed SMS-enabled phone number.')
);
$this->hidden('sms', $user->sms); $this->hidden('sms', $user->sms);
$this->hidden('carrier', $user->carrier); $this->hidden('carrier', $user->carrier);
// TRANS: Button label to remove a confirmed SMS address. // TRANS: Button label to remove a confirmed SMS address.
$this->submit('remove', _m('BUTTON','Remove')); $this->submit('remove', _m('BUTTON', 'Remove'));
} else { } else {
try { try {
$confirm = $this->getConfirmation(); $confirm = $this->getConfirmation();
$carrier = Sms_carrier::getKV($confirm->address_extra); $carrier = Sms_carrier::getKV($confirm->address_extra);
$this->element('p', 'form_unconfirmed', $this->element(
$confirm->address . ' (' . $carrier->name . ')'); 'p',
$this->element('p', 'form_guide', 'form_unconfirmed',
$confirm->address . ' (' . $carrier->name . ')'
);
$this->element(
'p',
'form_guide',
// TRANS: Form guide in IM settings form. // TRANS: Form guide in IM settings form.
_('Awaiting confirmation on this phone number.')); _('Awaiting confirmation on this phone number.')
);
$this->hidden('sms', $confirm->address); $this->hidden('sms', $confirm->address);
$this->hidden('carrier', $confirm->address_extra); $this->hidden('carrier', $confirm->address_extra);
// TRANS: Button label to cancel a SMS address confirmation procedure. // TRANS: Button label to cancel a SMS address confirmation procedure.
$this->submit('cancel', _m('BUTTON','Cancel')); $this->submit('cancel', _m('BUTTON', 'Cancel'));
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label for SMS address input in SMS settings form. // TRANS: Field label for SMS address input in SMS settings form.
$this->input('code', _('Confirmation code'), null, $this->input(
'code',
_('Confirmation code'),
null,
// TRANS: Form field instructions in SMS settings form. // TRANS: Form field instructions in SMS settings form.
_('Enter the code you received on your phone.')); _('Enter the code you received on your phone.')
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Button label to confirm SMS confirmation code in SMS settings. // TRANS: Button label to confirm SMS confirmation code in SMS settings.
$this->submit('confirm', _m('BUTTON','Confirm')); $this->submit('confirm', _m('BUTTON', 'Confirm'));
} catch (NoResultException $e) { } catch (NoResultException $e) {
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label for SMS phone number input in SMS settings form. // TRANS: Field label for SMS phone number input in SMS settings form.
$this->input('sms', _('SMS phone number'), $this->input(
($this->arg('sms')) ? $this->arg('sms') : null, 'sms',
_('SMS phone number'),
($this->arg('sms') ?: null),
// TRANS: SMS phone number input field instructions in SMS settings form. // TRANS: SMS phone number input field instructions in SMS settings form.
_('Phone number, no punctuation or spaces, '. _('Phone number, no punctuation or spaces, ' .
'with area code.')); 'with area code.')
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
$this->carrierSelect(); $this->carrierSelect();
// TRANS: Button label for adding a SMS phone number in SMS settings form. // TRANS: Button label for adding a SMS phone number in SMS settings form.
$this->submit('add', _m('BUTTON','Add')); $this->submit('add', _m('BUTTON', 'Add'));
} }
} }
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
if ($user->sms) { if ($user->sms) {
$this->elementStart('fieldset', array('id' => 'settings_sms_incoming_email')); $this->elementStart('fieldset', ['id' => 'settings_sms_incoming_email']);
// XXX: Confused! This is about SMS. Should this message be updated? // XXX: Confused! This is about SMS. Should this message be updated?
// TRANS: Form legend for incoming SMS settings form. // TRANS: Form legend for incoming SMS settings form.
$this->element('legend', null, _('Incoming email')); $this->element('legend', null, _('Incoming email'));
if ($user->incomingemail) { if ($user->incomingemail) {
$this->element('p', 'form_unconfirmed', $user->incomingemail); $this->element('p', 'form_unconfirmed', $user->incomingemail);
$this->element('p', 'form_note', $this->element(
'p',
'form_note',
// XXX: Confused! This is about SMS. Should this message be updated? // XXX: Confused! This is about SMS. Should this message be updated?
// TRANS: Form instructions for incoming SMS e-mail address form in SMS settings. // TRANS: Form instructions for incoming SMS e-mail address form in SMS settings.
_('Send email to this address to post new notices.')); _('Send email to this address to post new notices.')
);
// TRANS: Button label for removing a set sender SMS e-mail address to post notices from. // TRANS: Button label for removing a set sender SMS e-mail address to post notices from.
$this->submit('removeincoming', _m('BUTTON','Remove')); $this->submit('removeincoming', _m('BUTTON', 'Remove'));
} }
$this->element('p', 'form_guide', $this->element(
'p',
'form_guide',
// XXX: Confused! This is about SMS. Should this message be updated? // XXX: Confused! This is about SMS. Should this message be updated?
// TRANS: Instructions for incoming SMS e-mail address input form. // TRANS: Instructions for incoming SMS e-mail address input form.
_('Make a new email address for posting to; '. _('Make a new email address for posting to; ' .
'cancels the old one.')); 'cancels the old one.')
);
// TRANS: Button label for adding an SMS e-mail address to send notices from. // TRANS: Button label for adding an SMS e-mail address to send notices from.
$this->submit('newincoming', _m('BUTTON','New')); $this->submit('newincoming', _m('BUTTON', 'New'));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
} }
@ -190,17 +208,19 @@ class SmssettingsAction extends SettingsAction
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
$this->checkbox('smsnotify', $this->checkbox(
'smsnotify',
// TRANS: Checkbox label in SMS preferences form. // TRANS: Checkbox label in SMS preferences form.
_('Send me notices through SMS; '. _('Send me notices through SMS; ' .
'I understand I may incur '. 'I understand I may incur ' .
'exorbitant charges from my carrier.'), 'exorbitant charges from my carrier.'),
$user->smsnotify); $user->smsnotify
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Button label to save SMS preferences. // TRANS: Button label to save SMS preferences.
$this->submit('save', _m('BUTTON','Save')); $this->submit('save', _m('BUTTON', 'Save'));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
@ -213,7 +233,7 @@ class SmssettingsAction extends SettingsAction
* *
* @todo very similar to EmailsettingsAction::getConfirmation(); refactor? * @todo very similar to EmailsettingsAction::getConfirmation(); refactor?
*/ */
function getConfirmation() public function getConfirmation()
{ {
$confirm = new Confirm_address(); $confirm = new Confirm_address();
@ -229,20 +249,19 @@ class SmssettingsAction extends SettingsAction
protected function doPost() protected function doPost()
{ {
if ($this->arg('save')) { if ($this->arg('save')) {
return $this->savePreferences(); return $this->savePreferences();
} else if ($this->arg('add')) { } elseif ($this->arg('add')) {
return $this->addAddress(); return $this->addAddress();
} else if ($this->arg('cancel')) { } elseif ($this->arg('cancel')) {
return $this->cancelConfirmation(); return $this->cancelConfirmation();
} else if ($this->arg('remove')) { } elseif ($this->arg('remove')) {
return $this->removeAddress(); return $this->removeAddress();
} else if ($this->arg('removeincoming')) { } elseif ($this->arg('removeincoming')) {
return $this->removeIncoming(); return $this->removeIncoming();
} else if ($this->arg('newincoming')) { } elseif ($this->arg('newincoming')) {
return $this->newIncoming(); return $this->newIncoming();
} else if ($this->arg('confirm')) { } elseif ($this->arg('confirm')) {
return $this->confirmCode(); return $this->confirmCode();
} }
// TRANS: Message given submitting a form with an unknown action in SMS settings. // TRANS: Message given submitting a form with an unknown action in SMS settings.
@ -256,7 +275,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function savePreferences() public function savePreferences()
{ {
$user = $this->scoped->getUser(); $user = $this->scoped->getUser();
@ -288,7 +307,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function addAddress() public function addAddress()
{ {
$user = common_current_user(); $user = common_current_user();
@ -312,7 +331,7 @@ class SmssettingsAction extends SettingsAction
if ($user->sms === $sms) { if ($user->sms === $sms) {
// TRANS: Message given saving SMS phone number that is already set. // TRANS: Message given saving SMS phone number that is already set.
throw new AlreadyFulfilledException(_('That is already your phone number.')); throw new AlreadyFulfilledException(_('That is already your phone number.'));
} else if ($this->smsExists($sms)) { } elseif ($this->smsExists($sms)) {
// TRANS: Message given saving SMS phone number that is already set for another user. // TRANS: Message given saving SMS phone number that is already set for another user.
throw new ClientException(_('That phone number already belongs to another user.')); throw new ClientException(_('That phone number already belongs to another user.'));
} }
@ -335,9 +354,11 @@ class SmssettingsAction extends SettingsAction
$carrier = Sms_carrier::getKV($carrier_id); $carrier = Sms_carrier::getKV($carrier_id);
mail_confirm_sms($confirm->code, mail_confirm_sms(
$confirm->code,
$user->nickname, $user->nickname,
$carrier->toEmailAddress($sms)); $carrier->toEmailAddress($sms)
);
// TRANS: Message given saving valid SMS phone number that is to be confirmed. // TRANS: Message given saving valid SMS phone number that is to be confirmed.
return _('A confirmation code was sent to the phone number you added. '. return _('A confirmation code was sent to the phone number you added. '.
@ -352,7 +373,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function cancelConfirmation() public function cancelConfirmation()
{ {
$sms = $this->trimmed('sms'); $sms = $this->trimmed('sms');
$carrier = $this->trimmed('carrier'); $carrier = $this->trimmed('carrier');
@ -379,7 +400,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function removeAddress() public function removeAddress()
{ {
$user = $this->scoped->getUser(); $user = $this->scoped->getUser();
@ -396,9 +417,9 @@ class SmssettingsAction extends SettingsAction
$original = clone($user); $original = clone($user);
$user->sms = null; $user->sms = DB_DataObject_Cast::sql('NULL');
$user->carrier = null; $user->carrier = DB_DataObject_Cast::sql('NULL');
$user->smsemail = null; $user->smsemail = DB_DataObject_Cast::sql('NULL');
// Throws exception on failure. Also performs it within a transaction. // Throws exception on failure. Also performs it within a transaction.
$user->updateWithKeys($original); $user->updateWithKeys($original);
@ -416,7 +437,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return boolean does the number exist * @return boolean does the number exist
*/ */
function smsExists($sms) public function smsExists($sms)
{ {
$other = User::getKV('sms', $sms); $other = User::getKV('sms', $sms);
@ -432,7 +453,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function carrierSelect() public function carrierSelect()
{ {
$carrier = new Sms_carrier(); $carrier = new Sms_carrier();
@ -444,22 +465,33 @@ class SmssettingsAction extends SettingsAction
$this->element('label', array('for' => 'carrier'), _('Mobile carrier')); $this->element('label', array('for' => 'carrier'), _('Mobile carrier'));
$this->elementStart('select', array('name' => 'carrier', $this->elementStart('select', array('name' => 'carrier',
'id' => 'carrier')); 'id' => 'carrier'));
$this->element('option', array('value' => 0), $this->element(
'option',
['value' => 0],
// TRANS: Default option for mobile carrier dropdown menu in SMS settings. // TRANS: Default option for mobile carrier dropdown menu in SMS settings.
_('Select a carrier')); _('Select a carrier')
);
while ($carrier->fetch()) { while ($carrier->fetch()) {
$this->element('option', array('value' => $carrier->id), $this->element(
$carrier->name); 'option',
['value' => $carrier->id],
$carrier->name
);
} }
$this->elementEnd('select'); $this->elementEnd('select');
$this->element('p', 'form_guide', $this->element(
'p',
'form_guide',
// TRANS: Form instructions for mobile carrier dropdown menu in SMS settings. // TRANS: Form instructions for mobile carrier dropdown menu in SMS settings.
// TRANS: %s is an administrative contact's e-mail address. // TRANS: %s is an administrative contact's e-mail address.
sprintf(_('Mobile carrier for your phone. '. sprintf(
_('Mobile carrier for your phone. ' .
'If you know a carrier that accepts ' . 'If you know a carrier that accepts ' .
'SMS over email but isn\'t listed here, ' . 'SMS over email but isn\'t listed here, ' .
'send email to let us know at %s.'), 'send email to let us know at %s.'),
common_config('site', 'email'))); common_config('site', 'email')
)
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
} }
@ -471,7 +503,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function confirmCode() public function confirmCode()
{ {
$code = $this->trimmed('code'); $code = $this->trimmed('code');
@ -488,7 +520,7 @@ class SmssettingsAction extends SettingsAction
* *
* @return void * @return void
*/ */
function removeIncoming() public function removeIncoming()
{ {
$user = common_current_user(); $user = common_current_user();
@ -499,7 +531,7 @@ class SmssettingsAction extends SettingsAction
$orig = clone($user); $orig = clone($user);
$user->incomingemail = null; $user->incomingemail = DB_DataObject_Cast::sql('NULL');
// Throws exception on failure. Also performs it within a transaction. // Throws exception on failure. Also performs it within a transaction.
$user->updateWithKeys($orig); $user->updateWithKeys($orig);
@ -515,7 +547,7 @@ class SmssettingsAction extends SettingsAction
* *
* @see Emailsettings::newIncoming * @see Emailsettings::newIncoming
*/ */
function newIncoming() public function newIncoming()
{ {
$user = $this->scoped->getUser(); $user = $this->scoped->getUser();

View File

@ -1,28 +1,25 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } defined('GNUSOCIAL') || die();
// @todo FIXME: documentation needed. // @todo FIXME: documentation needed.
class SupAction extends Action class SupAction extends Action
{ {
function handle() public function handle()
{ {
parent::handle(); parent::handle();
@ -43,21 +40,23 @@ class SupAction extends Action
'updates' => $updates)); 'updates' => $updates));
} }
function availablePeriods() public function availablePeriods()
{ {
static $periods = array(86400, 43200, 21600, 7200, static $periods = array(86400, 43200, 21600, 7200,
3600, 1800, 600, 300, 120, 3600, 1800, 600, 300, 120,
60, 30, 15); 60, 30, 15);
$available = array(); $available = array();
foreach ($periods as $period) { foreach ($periods as $period) {
$available[$period] = common_local_url('sup', $available[$period] = common_local_url(
array('seconds' => $period)); 'sup',
['seconds' => $period]
);
} }
return $available; return $available;
} }
function getUpdates($seconds) public function getUpdates($seconds)
{ {
$notice = new Notice(); $notice = new Notice();
@ -69,9 +68,7 @@ class SupAction extends Action
$notice->query('SELECT profile_id, max(id) AS max_id ' . $notice->query('SELECT profile_id, max(id) AS max_id ' .
'FROM ( ' . 'FROM ( ' .
'SELECT profile_id, id FROM notice ' . 'SELECT profile_id, id FROM notice ' .
((common_config('db','type') == 'pgsql') ? "WHERE created > TIMESTAMP '" . $divider . "' " .
'WHERE extract(epoch from created) > (extract(epoch from now()) - ' . $seconds . ') ' :
'WHERE created > "'.$divider.'" ' ) .
') AS latest ' . ') AS latest ' .
'GROUP BY profile_id'); 'GROUP BY profile_id');
@ -84,7 +81,7 @@ class SupAction extends Action
return $updates; return $updates;
} }
function isReadOnly($args) public function isReadOnly($args)
{ {
return true; return true;
} }

View File

@ -1,6 +1,20 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Table Definition for avatar * Table Definition for avatar
@ -10,7 +24,7 @@ class Avatar extends Managed_DataObject
{ {
public $__table = 'avatar'; // table name public $__table = 'avatar'; // table name
public $profile_id; // int(4) primary_key not_null public $profile_id; // int(4) primary_key not_null
public $original; // tinyint(1) public $original; // bool default_false
public $width; // int(4) primary_key not_null public $width; // int(4) primary_key not_null
public $height; // int(4) primary_key not_null public $height; // int(4) primary_key not_null
public $mediatype; // varchar(32) not_null public $mediatype; // varchar(32) not_null
@ -23,7 +37,7 @@ class Avatar extends Managed_DataObject
return array( return array(
'fields' => array( 'fields' => array(
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'), 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
'original' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'uploaded by user or generated?'), 'original' => array('type' => 'bool', 'default' => false, 'description' => 'uploaded by user or generated?'),
'width' => array('type' => 'int', 'not null' => true, 'description' => 'image width'), 'width' => array('type' => 'int', 'not null' => true, 'description' => 'image width'),
'height' => array('type' => 'int', 'not null' => true, 'description' => 'image height'), 'height' => array('type' => 'int', 'not null' => true, 'description' => 'image height'),
'mediatype' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'file type'), 'mediatype' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'file type'),
@ -45,7 +59,7 @@ class Avatar extends Managed_DataObject
} }
// We clean up the file, too // We clean up the file, too
function delete($useWhere=false) public function delete($useWhere = false)
{ {
$filename = $this->filename; $filename = $this->filename;
if (file_exists(Avatar::path($filename))) { if (file_exists(Avatar::path($filename))) {
@ -61,7 +75,8 @@ class Avatar extends Managed_DataObject
* @param Profile $target The profile we're deleting avatars of. * @param Profile $target The profile we're deleting avatars of.
* @param boolean $original Whether original should be removed or not. * @param boolean $original Whether original should be removed or not.
*/ */
public static function deleteFromProfile(Profile $target, $original=true) { public static function deleteFromProfile(Profile $target, $original = true)
{
try { try {
$avatars = self::getProfileAvatars($target); $avatars = self::getProfileAvatars($target);
foreach ($avatars as $avatar) { foreach ($avatars as $avatar) {
@ -77,7 +92,7 @@ class Avatar extends Managed_DataObject
return true; return true;
} }
static protected $_avatars = array(); protected static $_avatars = [];
/* /*
* Get an avatar by profile. Currently can't call newSize with $height * Get an avatar by profile. Currently can't call newSize with $height
@ -93,7 +108,7 @@ class Avatar extends Managed_DataObject
$size = "{$width}x{$height}"; $size = "{$width}x{$height}";
if (!isset(self::$_avatars[$target->id])) { if (!isset(self::$_avatars[$target->id])) {
self::$_avatars[$target->id] = array(); self::$_avatars[$target->id] = array();
} elseif (isset(self::$_avatars[$target->id][$size])){ } elseif (isset(self::$_avatars[$target->id][$size])) {
return self::$_avatars[$target->id][$size]; return self::$_avatars[$target->id][$size];
} }
@ -137,7 +152,8 @@ class Avatar extends Managed_DataObject
return $avatar; return $avatar;
} }
public static function getProfileAvatars(Profile $target) { public static function getProfileAvatars(Profile $target)
{
$avatar = new Avatar(); $avatar = new Avatar();
$avatar->profile_id = $target->id; $avatar->profile_id = $target->id;
if (!$avatar->find()) { if (!$avatar->find()) {
@ -149,7 +165,7 @@ class Avatar extends Managed_DataObject
/** /**
* Where should the avatar go for this user? * Where should the avatar go for this user?
*/ */
static function filename($id, $extension, $size=null, $extra=null) public static function filename($id, $extension, $size = null, $extra = null)
{ {
if ($size) { if ($size) {
return $id . '-' . $size . (($extra) ? ('-' . $extra) : '') . $extension; return $id . '-' . $size . (($extra) ? ('-' . $extra) : '') . $extension;
@ -158,7 +174,7 @@ class Avatar extends Managed_DataObject
} }
} }
static function path($filename) public static function path($filename)
{ {
$dir = common_config('avatar', 'dir'); $dir = common_config('avatar', 'dir');
@ -169,7 +185,7 @@ class Avatar extends Managed_DataObject
return $dir . $filename; return $dir . $filename;
} }
static function url($filename) public static function url($filename)
{ {
$path = common_config('avatar', 'path'); $path = common_config('avatar', 'path');
@ -194,12 +210,13 @@ class Avatar extends Managed_DataObject
return $protocol.'://'.$server.$path.$filename; return $protocol.'://'.$server.$path.$filename;
} }
function displayUrl() public function displayUrl()
{ {
return Avatar::url($this->filename); return Avatar::url($this->filename);
} }
static function urlByProfile(Profile $target, $width=null, $height=null) { public static function urlByProfile(Profile $target, $width = null, $height = null)
{
try { try {
return self::byProfile($target, $width, $height)->displayUrl(); return self::byProfile($target, $width, $height)->displayUrl();
} catch (Exception $e) { } catch (Exception $e) {
@ -207,7 +224,7 @@ class Avatar extends Managed_DataObject
} }
} }
static function defaultImage($size=null) public static function defaultImage($size = null)
{ {
if (is_null($size)) { if (is_null($size)) {
$size = AVATAR_PROFILE_SIZE; $size = AVATAR_PROFILE_SIZE;
@ -218,7 +235,8 @@ class Avatar extends Managed_DataObject
return Theme::path('default-avatar-'.$sizenames[$size].'.png'); return Theme::path('default-avatar-'.$sizenames[$size].'.png');
} }
static function newSize(Profile $target, $width) { public static function newSize(Profile $target, $width)
{
$width = intval($width); $width = intval($width);
if ($width < 1 || $width > common_config('avatar', 'maxsize')) { if ($width < 1 || $width > common_config('avatar', 'maxsize')) {
// TRANS: An error message when avatar size is unreasonable // TRANS: An error message when avatar size is unreasonable
@ -231,8 +249,12 @@ class Avatar extends Managed_DataObject
$original = Avatar::getUploaded($target); $original = Avatar::getUploaded($target);
$imagefile = new ImageFile(null, Avatar::path($original->filename)); $imagefile = new ImageFile(null, Avatar::path($original->filename));
$filename = Avatar::filename($target->getID(), image_type_to_extension($imagefile->preferredType()), $filename = Avatar::filename(
$width, common_timestamp()); $target->getID(),
image_type_to_extension($imagefile->preferredType()),
$width,
common_timestamp()
);
$imagefile->resizeTo(Avatar::path($filename), array('width'=>$width, 'height'=>$height)); $imagefile->resizeTo(Avatar::path($filename), array('width'=>$width, 'height'=>$height));
$scaled = clone($original); $scaled = clone($original);

View File

@ -1,35 +1,32 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Data class for Conversations * Data class for Conversations
* *
* 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 Data * @category Data
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @author Mikael Nordfeldth <mmn@hethane.se> * @author Mikael Nordfeldth <mmn@hethane.se>
* @copyright 2010 StatusNet Inc. * @copyright 2010 StatusNet Inc.
* @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org * @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
class Conversation extends Managed_DataObject class Conversation extends Managed_DataObject
{ {
@ -57,14 +54,14 @@ class Conversation extends Managed_DataObject
); );
} }
static public function beforeSchemaUpdate() public static function beforeSchemaUpdate()
{ {
$table = strtolower(get_called_class()); $table = strtolower(get_called_class());
$schema = Schema::get(); $schema = Schema::get();
$schemadef = $schema->getTableDef($table); $schemadef = $schema->getTableDef($table);
// 2016-01-06 We have to make sure there is no conversation with id==0 since it will screw up auto increment resequencing // 2016-01-06 We have to make sure there is no conversation with id==0 since it will screw up auto increment resequencing
if ($schemadef['fields']['id']['auto_increment']) { if ($schemadef['fields']['id']['auto_increment'] ?? false) {
// since we already have auto incrementing ('serial') we can continue // since we already have auto incrementing ('serial') we can continue
return; return;
} }
@ -91,7 +88,7 @@ class Conversation extends Managed_DataObject
* *
* @return Conversation the new conversation DO * @return Conversation the new conversation DO
*/ */
static function create(ActivityContext $ctx=null, $created=null) public static function create(ActivityContext $ctx = null, $created = null)
{ {
// Be aware that the Notice does not have an id yet since it's not inserted! // Be aware that the Notice does not have an id yet since it's not inserted!
$conv = new Conversation(); $conv = new Conversation();
@ -100,11 +97,16 @@ class Conversation extends Managed_DataObject
$conv->uri = $ctx->conversation; $conv->uri = $ctx->conversation;
$conv->url = $ctx->conversation_url; $conv->url = $ctx->conversation_url;
} else { } else {
$conv->uri = sprintf('%s%s=%s:%s=%s', $conv->uri = sprintf(
'%s%s=%s:%s=%s',
TagURI::mint(), TagURI::mint(),
'objectType', 'thread', 'objectType',
'nonce', common_random_hexstr(8)); 'thread',
$conv->url = null; // locally generated Conversation objects don't get static URLs stored 'nonce',
common_random_hexstr(8)
);
// locally generated Conversation objects don't get static URLs stored
$conv->url = DB_DataObject_Cast::sql('NULL');
} }
// This insert throws exceptions on failure // This insert throws exceptions on failure
$conv->insert(); $conv->insert();
@ -112,7 +114,7 @@ class Conversation extends Managed_DataObject
return $conv; return $conv;
} }
static function noticeCount($id) public static function noticeCount($id)
{ {
$keypart = sprintf('conversation:notice_count:%d', $id); $keypart = sprintf('conversation:notice_count:%d', $id);
@ -132,7 +134,7 @@ class Conversation extends Managed_DataObject
return $cnt; return $cnt;
} }
static public function getUrlFromNotice(Notice $notice, $anchor=true) public static function getUrlFromNotice(Notice $notice, $anchor = true)
{ {
$conv = Conversation::getByID($notice->conversation); $conv = Conversation::getByID($notice->conversation);
return $conv->getUrl($anchor ? $notice->getID() : null); return $conv->getUrl($anchor ? $notice->getID() : null);

View File

@ -1,29 +1,26 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* GNU social - a federating social network
*
* Abstraction for files
*
* 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 Files * @category Files
* @package GNUsocial * @package GNUsocial
* @author Mikael Nordfeldth <mmn@hethane.se> * @author Mikael Nordfeldth <mmn@hethane.se>
* @author Miguel Dantas <biodantas@gmail.com> * @author Miguel Dantas <biodantas@gmail.com>
* @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org * @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link https://www.gnu.org/software/social/
*/ */
defined('GNUSOCIAL') || die(); defined('GNUSOCIAL') || die();
@ -346,7 +343,8 @@ class File extends Managed_DataObject
* @param string $filename * @param string $filename
* @return string|bool Value from the 'extblacklist' array, in the config * @return string|bool Value from the 'extblacklist' array, in the config
*/ */
public static function getSafeExtension(string $filename) { public static function getSafeExtension(string $filename)
{
if (preg_match('/^.+?\.([A-Za-z0-9]+)$/', $filename, $matches) === 1) { if (preg_match('/^.+?\.([A-Za-z0-9]+)$/', $filename, $matches) === 1) {
// we matched on a file extension, so let's see if it means something. // we matched on a file extension, so let's see if it means something.
$ext = mb_strtolower($matches[1]); $ext = mb_strtolower($matches[1]);
@ -888,7 +886,11 @@ class File extends Managed_DataObject
echo "\nFound old $table table, upgrading it to contain 'urlhash' field..."; echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
$file = new File(); $file = new File();
$file->query(sprintf('SELECT id, LEFT(url, 191) AS shortenedurl, COUNT(*) AS c FROM %1$s WHERE LENGTH(url)>191 GROUP BY shortenedurl HAVING c > 1', $schema->quoteIdentifier($table))); $file->query(sprintf(
'SELECT id, LEFT(url, 191) AS shortenedurl, COUNT(*) FROM %1$s ' .
'WHERE LENGTH(url) > 191 GROUP BY id, shortenedurl HAVING COUNT(*) > 1',
common_database_tablename($table)
));
print "\nFound {$file->N} URLs with too long entries in file table\n"; print "\nFound {$file->N} URLs with too long entries in file table\n";
while ($file->fetch()) { while ($file->fetch()) {
// We've got a URL that is too long for our future file table // We've got a URL that is too long for our future file table
@ -941,13 +943,20 @@ class File extends Managed_DataObject
$tablefix = new $classname; $tablefix = new $classname;
// urlhash is hash('sha256', $url) in the File table // urlhash is hash('sha256', $url) in the File table
echo "Updating urlhash fields in $table table..."; echo "Updating urlhash fields in $table table...";
// Maybe very MySQL specific :( switch (common_config('db', 'type')) {
case 'pgsql':
$url_sha256 = 'encode(sha256(CAST("url" AS bytea)), \'hex\')';
break;
case 'mysql':
$url_sha256 = 'sha2(`url`, 256)';
break;
default:
throw new ServerException('Unknown DB type selected.');
}
$tablefix->query(sprintf( $tablefix->query(sprintf(
'UPDATE %1$s SET %2$s=%3$s;', 'UPDATE %1$s SET urlhash = %2$s;',
$schema->quoteIdentifier($table), $tablefix->escapedTableName(),
'urlhash', $url_sha256
// The line below is "result of sha256 on column `url`"
'SHA2(url, 256)'
)); ));
echo "DONE.\n"; echo "DONE.\n";
echo "Resuming core schema upgrade..."; echo "Resuming core schema upgrade...";

View File

@ -1,28 +1,24 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Table Definition for file_redirection * Table Definition for file_redirection
*/ */
class File_redirection extends Managed_DataObject class File_redirection extends Managed_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
@ -54,17 +50,18 @@ class File_redirection extends Managed_DataObject
), ),
'primary key' => array('urlhash'), 'primary key' => array('urlhash'),
'foreign keys' => array( 'foreign keys' => array(
'file_redirection_file_id_fkey' => array('file' => array('file_id' => 'id')), 'file_redirection_file_id_fkey' => array('file', array('file_id' => 'id')),
), ),
); );
} }
static public function getByUrl($url) public static function getByUrl($url)
{ {
return self::getByPK(array('urlhash' => File::hashurl($url))); return self::getByPK(array('urlhash' => File::hashurl($url)));
} }
static function _commonHttp($url, $redirs) { public static function _commonHttp($url, $redirs)
{
$request = new HTTPClient($url); $request = new HTTPClient($url);
$request->setConfig(array( $request->setConfig(array(
'connect_timeout' => 10, // # seconds to wait 'connect_timeout' => 10, // # seconds to wait
@ -96,10 +93,13 @@ class File_redirection extends Managed_DataObject
* size (optional): byte size from Content-Length header * size (optional): byte size from Content-Length header
* time (optional): timestamp from Last-Modified header * time (optional): timestamp from Last-Modified header
*/ */
static function lookupWhere($short_url, $redirs = 10, $protected = false) { public static function lookupWhere($short_url, $redirs = 10, $protected = false)
if ($redirs < 0) return false; {
if ($redirs < 0) {
return false;
}
if(strpos($short_url,'://') === false){ if (strpos($short_url, '://') === false) {
return $short_url; return $short_url;
} }
try { try {
@ -132,7 +132,7 @@ class File_redirection extends Managed_DataObject
// if last url after all redirections is protected, // if last url after all redirections is protected,
// use the url before it in the redirection chain // use the url before it in the redirection chain
if ($response->getRedirectCount() && File::isProtected($response->getEffectiveUrl())) { if ($response->getRedirectCount() && File::isProtected($response->getEffectiveUrl())) {
$return_url = $response->redirUrls[$response->getRedirectCount()-1]; $return_url = $response->redirUrls[$response->getRedirectCount() - 1];
} else { } else {
$return_url = $response->getEffectiveUrl(); $return_url = $response->getEffectiveUrl();
} }
@ -142,12 +142,20 @@ class File_redirection extends Managed_DataObject
, 'url' => $return_url); , 'url' => $return_url);
$type = $response->getHeader('Content-Type'); $type = $response->getHeader('Content-Type');
if ($type) $ret['type'] = $type; if ($type) {
if ($protected) $ret['protected'] = true; $ret['type'] = $type;
}
if ($protected) {
$ret['protected'] = true;
}
$size = $response->getHeader('Content-Length'); // @fixme bytes? $size = $response->getHeader('Content-Length'); // @fixme bytes?
if ($size) $ret['size'] = $size; if ($size) {
$ret['size'] = $size;
}
$time = $response->getHeader('Last-Modified'); $time = $response->getHeader('Last-Modified');
if ($time) $ret['time'] = strtotime($time); if ($time) {
$ret['time'] = strtotime($time);
}
return $ret; return $ret;
} }
@ -164,7 +172,8 @@ class File_redirection extends Managed_DataObject
* @param boolean $discover true to attempt dereferencing the redirect if we don't know it already * @param boolean $discover true to attempt dereferencing the redirect if we don't know it already
* @return File_redirection * @return File_redirection
*/ */
static function where($in_url, $discover=true) { public static function where($in_url, $discover = true)
{
$redir = new File_redirection(); $redir = new File_redirection();
$redir->url = $in_url; $redir->url = $in_url;
$redir->urlhash = File::hashurl($redir->url); $redir->urlhash = File::hashurl($redir->url);
@ -179,14 +188,16 @@ class File_redirection extends Managed_DataObject
$r->redir_url = $f->url; $r->redir_url = $f->url;
} catch (NoResultException $e) { } catch (NoResultException $e) {
// Invalid entry, delete and run again // Invalid entry, delete and run again
common_log(LOG_ERR, "Could not find File with id=".$r->file_id." referenced in File_redirection, deleting File redirection entry and and trying again..."); common_log(
LOG_ERR,
'Could not find File with id=' . $r->file_id . ' referenced in File_redirection, deleting File redirection entry and and trying again...'
);
$r->delete(); $r->delete();
return self::where($in_url); return self::where($in_url);
} }
// File_redirecion and File record found, return both // File_redirecion and File record found, return both
return $r; return $r;
} catch (NoResultException $e) { } catch (NoResultException $e) {
// File_redirecion record not found, but this might be a direct link to a file // File_redirecion record not found, but this might be a direct link to a file
try { try {
@ -202,7 +213,7 @@ class File_redirection extends Managed_DataObject
if ($discover) { if ($discover) {
// try to follow redirects and get the final url // try to follow redirects and get the final url
$redir_info = File_redirection::lookupWhere($in_url); $redir_info = File_redirection::lookupWhere($in_url);
if(is_string($redir_info)) { if (is_string($redir_info)) {
$redir_info = array('url' => $redir_info); $redir_info = array('url' => $redir_info);
} }
@ -212,21 +223,24 @@ class File_redirection extends Managed_DataObject
try { try {
$r = File_redirection::getByUrl($redir_info['url']); $r = File_redirection::getByUrl($redir_info['url']);
$f = File::getKV('id',$r->file_id); $f = File::getKV('id', $r->file_id);
if($f instanceof File) { if ($f instanceof File) {
$redir->file = $f; $redir->file = $f;
$redir->redir_url = $f->url; $redir->redir_url = $f->url;
} else { } else {
// Invalid entry in File_redirection, delete and run again // Invalid entry in File_redirection, delete and run again
common_log(LOG_ERR, "Could not find File with id=".$r->file_id." referenced in File_redirection, deleting File_redirection entry and trying again..."); common_log(
LOG_ERR,
'Could not find File with id=' . $r->file_id . ' referenced in File_redirection, deleting File_redirection entry and trying again...'
);
$r->delete(); $r->delete();
return self::where($in_url); return self::where($in_url);
} }
} catch (NoResultException $e) { } catch (NoResultException $e) {
// save the file now when we know that we don't have it in File_redirection // save the file now when we know that we don't have it in File_redirection
try { try {
$redir->file = File::saveNew($redir_info,$redir_info['url']); $redir->file = File::saveNew($redir_info, $redir_info['url']);
} catch (ServerException $e) { } catch (ServerException $e) {
common_log(LOG_ERR, $e); common_log(LOG_ERR, $e);
} }
@ -234,7 +248,7 @@ class File_redirection extends Managed_DataObject
// If this is a redirection and we have a file to redirect to, save it // If this is a redirection and we have a file to redirect to, save it
// (if it doesn't exist in File_redirection already) // (if it doesn't exist in File_redirection already)
if($redir->file instanceof File && $redir_info['url'] != $in_url) { if ($redir->file instanceof File && $redir_info['url'] != $in_url) {
try { try {
$file_redir = File_redirection::getByUrl($in_url); $file_redir = File_redirection::getByUrl($in_url);
} catch (NoResultException $e) { } catch (NoResultException $e) {
@ -268,7 +282,7 @@ class File_redirection extends Managed_DataObject
* @param User $user whose shortening options to use; defaults to the current web session user * @param User $user whose shortening options to use; defaults to the current web session user
* @return string * @return string
*/ */
static function makeShort($long_url, $user=null) public static function makeShort($long_url, $user = null)
{ {
$canon = File_redirection::_canonUrl($long_url); $canon = File_redirection::_canonUrl($long_url);
@ -293,7 +307,7 @@ class File_redirection extends Managed_DataObject
* @return string * @return string
*/ */
static function forceShort($long_url, $user) public static function forceShort($long_url, $user)
{ {
$canon = File_redirection::_canonUrl($long_url); $canon = File_redirection::_canonUrl($long_url);
@ -303,7 +317,8 @@ class File_redirection extends Managed_DataObject
return !empty($short_url) ? $short_url : $long_url; return !empty($short_url) ? $short_url : $long_url;
} }
static function _userMakeShort($long_url, User $user=null, $force = false) { public static function _userMakeShort($long_url, User $user = null, $force = false)
{
$short_url = common_shorten_url($long_url, $user, $force); $short_url = common_shorten_url($long_url, $user, $force);
if (!empty($short_url) && $short_url != $long_url) { if (!empty($short_url) && $short_url != $long_url) {
$short_url = (string)$short_url; $short_url = (string)$short_url;
@ -343,8 +358,11 @@ class File_redirection extends Managed_DataObject
* @param string $default_scheme if given a bare link; defaults to 'http://' * @param string $default_scheme if given a bare link; defaults to 'http://'
* @return string * @return string
*/ */
static function _canonUrl($in_url, $default_scheme = 'http://') { public static function _canonUrl($in_url, $default_scheme = 'http://')
if (empty($in_url)) return false; {
if (empty($in_url)) {
return false;
}
$out_url = $in_url; $out_url = $in_url;
$p = parse_url($out_url); $p = parse_url($out_url);
if (empty($p['host']) || empty($p['scheme'])) { if (empty($p['host']) || empty($p['scheme'])) {
@ -377,13 +395,17 @@ class File_redirection extends Managed_DataObject
default: default:
$out_url = $default_scheme . ltrim($out_url, '/'); $out_url = $default_scheme . ltrim($out_url, '/');
$p = parse_url($out_url); $p = parse_url($out_url);
if (empty($p['scheme'])) return false; if (empty($p['scheme'])) {
return false;
}
break; break;
} }
} }
if (('ftp' == $p['scheme']) || ('ftps' == $p['scheme']) || ('http' == $p['scheme']) || ('https' == $p['scheme'])) { if (('ftp' == $p['scheme']) || ('ftps' == $p['scheme']) || ('http' == $p['scheme']) || ('https' == $p['scheme'])) {
if (empty($p['host'])) return false; if (empty($p['host'])) {
return false;
}
if (empty($p['path'])) { if (empty($p['path'])) {
$out_url .= '/'; $out_url .= '/';
} }
@ -392,7 +414,8 @@ class File_redirection extends Managed_DataObject
return $out_url; return $out_url;
} }
static function saveNew($data, $file_id, $url) { public static function saveNew($data, $file_id, $url)
{
$file_redir = new File_redirection; $file_redir = new File_redirection;
$file_redir->urlhash = File::hashurl($url); $file_redir->urlhash = File::hashurl($url);
$file_redir->url = $url; $file_redir->url = $url;
@ -402,7 +425,7 @@ class File_redirection extends Managed_DataObject
$file_redir->insert(); $file_redir->insert();
} }
static public function beforeSchemaUpdate() public static function beforeSchemaUpdate()
{ {
$table = strtolower(get_called_class()); $table = strtolower(get_called_class());
$schema = Schema::get(); $schema = Schema::get();
@ -416,16 +439,16 @@ class File_redirection extends Managed_DataObject
echo "\nFound old $table table, upgrading it to contain 'urlhash' field..."; echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
// We have to create a urlhash that is _not_ the primary key, // We have to create a urlhash that is _not_ the primary key,
// transfer data and THEN run checkSchema // transfer data and THEN run checkSchema
$schemadef['fields']['urlhash'] = array ( $schemadef['fields']['urlhash'] = [
'type' => 'varchar', 'type' => 'varchar',
'length' => 64, 'length' => 64,
'not null' => true, 'not null' => true,
'description' => 'sha256 hash of the URL', 'description' => 'sha256 hash of the URL',
); ];
$schemadef['fields']['url'] = array ( $schemadef['fields']['url'] = [
'type' => 'text', 'type' => 'text',
'description' => 'short URL (or any other kind of redirect) for file (id)', 'description' => 'short URL (or any other kind of redirect) for file (id)',
); ];
unset($schemadef['primary key']); unset($schemadef['primary key']);
$schema->ensureTable($table, $schemadef); $schema->ensureTable($table, $schemadef);
echo "DONE.\n"; echo "DONE.\n";
@ -434,17 +457,27 @@ class File_redirection extends Managed_DataObject
$tablefix = new $classname; $tablefix = new $classname;
// urlhash is hash('sha256', $url) in the File table // urlhash is hash('sha256', $url) in the File table
echo "Updating urlhash fields in $table table..."; echo "Updating urlhash fields in $table table...";
// Maybe very MySQL specific :( switch (common_config('db', 'type')) {
$tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;', case 'pgsql':
$schema->quoteIdentifier($table), $url_sha256 = 'encode(sha256(CAST("url" AS bytea)), \'hex\')';
'urlhash', break;
// The line below is "result of sha256 on column `url`" case 'mysql':
'SHA2(url, 256)')); $url_sha256 = 'sha2(`url`, 256)';
break;
default:
throw new ServerException('Unknown DB type selected.');
}
$tablefix->query(sprintf(
'UPDATE %1$s SET urlhash = %2$s;',
$tablefix->escapedTableName(),
$url_sha256
));
echo "DONE.\n"; echo "DONE.\n";
echo "Resuming core schema upgrade..."; echo "Resuming core schema upgrade...";
} }
public function getFile() { public function getFile()
{
if (!$this->file instanceof File) { if (!$this->file instanceof File) {
$this->file = File::getByID($this->file_id); $this->file = File::getByID($this->file_id);
} }

View File

@ -1,28 +1,29 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/* /*
* StatusNet - the distributed open-source microblogging tool * @copyright 2008-2009 StatusNet, Inc.
* Copyright (C) 2008, 2009, StatusNet, Inc. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Table Definition for file_thumbnail * Table Definition for file_thumbnail
*/ */
class File_thumbnail extends Managed_DataObject class File_thumbnail extends Managed_DataObject
{ {
public $__table = 'file_thumbnail'; // table name public $__table = 'file_thumbnail'; // table name
@ -44,8 +45,8 @@ class File_thumbnail extends Managed_DataObject
'urlhash' => array('type' => 'varchar', 'length' => 64, 'description' => 'sha256 of url field if non-empty'), 'urlhash' => array('type' => 'varchar', 'length' => 64, 'description' => 'sha256 of url field if non-empty'),
'url' => array('type' => 'text', 'description' => 'URL of thumbnail'), 'url' => array('type' => 'text', 'description' => 'URL of thumbnail'),
'filename' => array('type' => 'text', 'description' => 'if stored locally, filename is put here'), 'filename' => array('type' => 'text', 'description' => 'if stored locally, filename is put here'),
'width' => array('type' => 'int', 'description' => 'width of thumbnail'), 'width' => array('type' => 'int', 'not null' => true, 'description' => 'width of thumbnail'),
'height' => array('type' => 'int', 'description' => 'height of thumbnail'), 'height' => array('type' => 'int', 'not null' => true, 'description' => 'height of thumbnail'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'),
), ),
'primary key' => array('file_id', 'width', 'height'), 'primary key' => array('file_id', 'width', 'height'),
@ -65,21 +66,26 @@ class File_thumbnail extends Managed_DataObject
* @param object $data * @param object $data
* @param int $file_id * @param int $file_id
*/ */
public static function saveNew($data, $file_id) { public static function saveNew($data, $file_id)
{
if (!empty($data->thumbnail_url)) { if (!empty($data->thumbnail_url)) {
// Non-photo types such as video will usually // Non-photo types such as video will usually
// show us a thumbnail, though it's not required. // show us a thumbnail, though it's not required.
self::saveThumbnail($file_id, self::saveThumbnail(
$file_id,
$data->thumbnail_url, $data->thumbnail_url,
$data->thumbnail_width, $data->thumbnail_width,
$data->thumbnail_height); $data->thumbnail_height
} else if ($data->type == 'photo') { );
} elseif ($data->type == 'photo') {
// The inline photo URL given should also fit within // The inline photo URL given should also fit within
// our requested thumbnail size, per oEmbed spec. // our requested thumbnail size, per oEmbed spec.
self::saveThumbnail($file_id, self::saveThumbnail(
$file_id,
$data->url, $data->url,
$data->width, $data->width,
$data->height); $data->height
);
} }
} }
@ -92,7 +98,8 @@ class File_thumbnail extends Managed_DataObject
* @return File_thumbnail * @return File_thumbnail
* @throws NoResultException if no File_thumbnail matched the criteria * @throws NoResultException if no File_thumbnail matched the criteria
*/ */
static function byFile(File $file, $notNullUrl=true) { public static function byFile(File $file, $notNullUrl = true)
{
$thumb = new File_thumbnail(); $thumb = new File_thumbnail();
$thumb->file_id = $file->getID(); $thumb->file_id = $file->getID();
if ($notNullUrl) { if ($notNullUrl) {
@ -116,7 +123,7 @@ class File_thumbnail extends Managed_DataObject
* @param int $width * @param int $width
* @param int $height * @param int $height
*/ */
static function saveThumbnail($file_id, $url, $width, $height, $filename=null) public static function saveThumbnail($file_id, $url, $width, $height, $filename = null)
{ {
$tn = new File_thumbnail; $tn = new File_thumbnail;
$tn->file_id = $file_id; $tn->file_id = $file_id;
@ -128,7 +135,7 @@ class File_thumbnail extends Managed_DataObject
return $tn; return $tn;
} }
static function path($filename) public static function path($filename)
{ {
File::tryFilename($filename); File::tryFilename($filename);
@ -142,7 +149,7 @@ class File_thumbnail extends Managed_DataObject
return $dir . $filename; return $dir . $filename;
} }
static function url($filename) public static function url($filename)
{ {
File::tryFilename($filename); File::tryFilename($filename);
@ -276,7 +283,7 @@ class File_thumbnail extends Managed_DataObject
return $this->file_id; return $this->file_id;
} }
static public function hashurl($url) public static function hashurl($url)
{ {
if (!mb_strlen($url)) { if (!mb_strlen($url)) {
throw new Exception('No URL provided to hash algorithm.'); throw new Exception('No URL provided to hash algorithm.');

View File

@ -1,4 +1,21 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
/** /**
* Table Definition for request_queue * Table Definition for request_queue
*/ */
@ -23,7 +40,7 @@ class Group_join_queue extends Managed_DataObject
'description' => 'Holder for group join requests awaiting moderation.', 'description' => 'Holder for group join requests awaiting moderation.',
'fields' => array( 'fields' => array(
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'remote or local profile making the request'), 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'remote or local profile making the request'),
'group_id' => array('type' => 'int', 'description' => 'remote or local group to join, if any'), 'group_id' => array('type' => 'int', 'not null' => true, 'description' => 'remote or local group to join, if any'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'),
), ),
'primary key' => array('profile_id', 'group_id'), 'primary key' => array('profile_id', 'group_id'),
@ -48,27 +65,27 @@ class Group_join_queue extends Managed_DataObject
return $rq; return $rq;
} }
function getMember() public function getMember()
{ {
$member = Profile::getKV('id', $this->profile_id); $member = Profile::getKV('id', $this->profile_id);
if (empty($member)) { if (empty($member)) {
// TRANS: Exception thrown providing an invalid profile ID. // TRANS: Exception thrown providing an invalid profile ID.
// TRANS: %s is the invalid profile ID. // TRANS: %s is the invalid profile ID.
throw new Exception(sprintf(_('Profile ID %s is invalid.'),$this->profile_id)); throw new Exception(sprintf(_('Profile ID %s is invalid.'), $this->profile_id));
} }
return $member; return $member;
} }
function getGroup() public function getGroup()
{ {
$group = User_group::getKV('id', $this->group_id); $group = User_group::getKV('id', $this->group_id);
if (empty($group)) { if (empty($group)) {
// TRANS: Exception thrown providing an invalid group ID. // TRANS: Exception thrown providing an invalid group ID.
// TRANS: %s is the invalid group ID. // TRANS: %s is the invalid group ID.
throw new Exception(sprintf(_('Group ID %s is invalid.'),$this->group_id)); throw new Exception(sprintf(_('Group ID %s is invalid.'), $this->group_id));
} }
return $group; return $group;
@ -77,7 +94,7 @@ class Group_join_queue extends Managed_DataObject
/** /**
* Abort the pending group join... * Abort the pending group join...
*/ */
function abort() public function abort()
{ {
$profile = $this->getMember(); $profile = $this->getMember();
$group = $this->getGroup(); $group = $this->getGroup();
@ -93,7 +110,7 @@ class Group_join_queue extends Managed_DataObject
* *
* @return Group_member object on success * @return Group_member object on success
*/ */
function complete() public function complete()
{ {
$join = null; $join = null;
$profile = $this->getMember(); $profile = $this->getMember();

View File

@ -1,4 +1,21 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
/** /**
* Table Definition for group_member * Table Definition for group_member
*/ */
@ -11,7 +28,7 @@ class Group_member extends Managed_DataObject
public $__table = 'group_member'; // table name public $__table = 'group_member'; // table name
public $group_id; // int(4) primary_key not_null public $group_id; // int(4) primary_key not_null
public $profile_id; // int(4) primary_key not_null public $profile_id; // int(4) primary_key not_null
public $is_admin; // tinyint(1) public $is_admin; // bool default_false
public $uri; // varchar(191) not 255 because utf8mb4 takes more space public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00 public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00
public $modified; // datetime() not_null default_CURRENT_TIMESTAMP public $modified; // datetime() not_null default_CURRENT_TIMESTAMP
@ -25,7 +42,7 @@ class Group_member extends Managed_DataObject
'fields' => array( 'fields' => array(
'group_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to user_group'), 'group_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to user_group'),
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'), 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
'is_admin' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'is this user an admin?'), 'is_admin' => array('type' => 'bool', 'default' => false, 'description' => 'is this user an admin?'),
'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universal identifier'), 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universal identifier'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'),
@ -58,16 +75,18 @@ class Group_member extends Managed_DataObject
* @return Group_member new membership object * @return Group_member new membership object
*/ */
static function join($group_id, $profile_id) public static function join($group_id, $profile_id)
{ {
$member = new Group_member(); $member = new Group_member();
$member->group_id = $group_id; $member->group_id = $group_id;
$member->profile_id = $profile_id; $member->profile_id = $profile_id;
$member->created = common_sql_now(); $member->created = common_sql_now();
$member->uri = self::newUri(Profile::getByID($profile_id), $member->uri = self::newUri(
Profile::getByID($profile_id),
User_group::getByID($group_id), User_group::getByID($group_id),
$member->created); $member->created
);
$result = $member->insert(); $result = $member->insert();
@ -80,7 +99,7 @@ class Group_member extends Managed_DataObject
return $member; return $member;
} }
static function leave($group_id, $profile_id) public static function leave($group_id, $profile_id)
{ {
$member = Group_member::pkeyGet(array('group_id' => $group_id, $member = Group_member::pkeyGet(array('group_id' => $group_id,
'profile_id' => $profile_id)); 'profile_id' => $profile_id));
@ -101,27 +120,27 @@ class Group_member extends Managed_DataObject
return true; return true;
} }
function getMember() public function getMember()
{ {
$member = Profile::getKV('id', $this->profile_id); $member = Profile::getKV('id', $this->profile_id);
if (empty($member)) { if (empty($member)) {
// TRANS: Exception thrown providing an invalid profile ID. // TRANS: Exception thrown providing an invalid profile ID.
// TRANS: %s is the invalid profile ID. // TRANS: %s is the invalid profile ID.
throw new Exception(sprintf(_("Profile ID %s is invalid."),$this->profile_id)); throw new Exception(sprintf(_("Profile ID %s is invalid."), $this->profile_id));
} }
return $member; return $member;
} }
function getGroup() public function getGroup()
{ {
$group = User_group::getKV('id', $this->group_id); $group = User_group::getKV('id', $this->group_id);
if (empty($group)) { if (empty($group)) {
// TRANS: Exception thrown providing an invalid group ID. // TRANS: Exception thrown providing an invalid group ID.
// TRANS: %s is the invalid group ID. // TRANS: %s is the invalid group ID.
throw new Exception(sprintf(_("Group ID %s is invalid."),$this->group_id)); throw new Exception(sprintf(_('Group ID %s is invalid.'), $this->group_id));
} }
return $group; return $group;
@ -137,7 +156,7 @@ class Group_member extends Managed_DataObject
* @return Group_member stream of memberships, use fetch() to iterate * @return Group_member stream of memberships, use fetch() to iterate
*/ */
static function byMember($memberId, $offset=0, $limit=GROUPS_PER_PAGE) public static function byMember($memberId, $offset = 0, $limit = GROUPS_PER_PAGE)
{ {
$membership = new Group_member(); $membership = new Group_member();
@ -152,7 +171,7 @@ class Group_member extends Managed_DataObject
return $membership; return $membership;
} }
function asActivity() public function asActivity()
{ {
$member = $this->getMember(); $member = $this->getMember();
@ -180,13 +199,19 @@ class Group_member extends Managed_DataObject
// TRANS: Success message for subscribe to group attempt through OStatus. // TRANS: Success message for subscribe to group attempt through OStatus.
// TRANS: %1$s is the member name, %2$s is the subscribed group's name. // TRANS: %1$s is the member name, %2$s is the subscribed group's name.
$act->content = sprintf(_('%1$s has joined group %2$s.'), $act->content = sprintf(
_('%1$s has joined group %2$s.'),
$member->getBestName(), $member->getBestName(),
$group->getBestName()); $group->getBestName()
);
$url = common_local_url('AtomPubShowMembership', $url = common_local_url(
array('profile' => $member->id, 'AtomPubShowMembership',
'group' => $group->id)); [
'profile' => $member->id,
'group' => $group->id,
]
);
$act->selfLink = $url; $act->selfLink = $url;
$act->editLink = $url; $act->editLink = $url;
@ -203,7 +228,7 @@ class Group_member extends Managed_DataObject
mail_notify_group_join($this->getGroup(), $this->getMember()); mail_notify_group_join($this->getGroup(), $this->getMember());
} }
function getUri() public function getUri()
{ {
return $this->uri ?: self::newUri($this->getMember(), $this->getGroup()->getProfile(), $this->created); return $this->uri ?: self::newUri($this->getMember(), $this->getGroup()->getProfile(), $this->created);
} }

View File

@ -1,28 +1,31 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2010, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>.
*/
/** /**
* Wrapper for Memcached_DataObject which knows its own schema definition. * Wrapper for Memcached_DataObject which knows its own schema definition.
* Builds its own damn settings from a schema definition. * Builds its own damn settings from a schema definition.
* *
* @package GNUsocial
* @author Brion Vibber <brion@status.net> * @author Brion Vibber <brion@status.net>
* @copyright 2010 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
defined('GNUSOCIAL') || die();
abstract class Managed_DataObject extends Memcached_DataObject abstract class Managed_DataObject extends Memcached_DataObject
{ {
/** /**
@ -42,7 +45,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return get_called_class() object if found, or null for no hits * @return get_called_class() object if found, or null for no hits
* *
*/ */
static function getKV($k,$v=NULL) public static function getKV($k, $v = null)
{ {
return parent::getClassKV(get_called_class(), $k, $v); return parent::getClassKV(get_called_class(), $k, $v);
} }
@ -59,12 +62,12 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return get_called_class() object if found, or null for no hits * @return get_called_class() object if found, or null for no hits
* *
*/ */
static function pkeyGet(array $kv) public static function pkeyGet(array $kv)
{ {
return parent::pkeyGetClass(get_called_class(), $kv); return parent::pkeyGetClass(get_called_class(), $kv);
} }
static function pkeyCols() public static function pkeyCols()
{ {
return parent::pkeyColsClass(get_called_class()); return parent::pkeyColsClass(get_called_class());
} }
@ -78,7 +81,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* *
* @return array Array of objects, in order * @return array Array of objects, in order
*/ */
static function multiGet($keyCol, array $keyVals, $skipNulls=true) public static function multiGet($keyCol, array $keyVals, $skipNulls = true)
{ {
return parent::multiGetClass(get_called_class(), $keyCol, $keyVals, $skipNulls); return parent::multiGetClass(get_called_class(), $keyCol, $keyVals, $skipNulls);
} }
@ -92,7 +95,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* *
* @return array Array mapping $keyVals to objects, or null if not found * @return array Array mapping $keyVals to objects, or null if not found
*/ */
static function pivotGet($keyCol, array $keyVals, array $otherCols=array()) public static function pivotGet($keyCol, array $keyVals, array $otherCols = [])
{ {
return parent::pivotGetClass(get_called_class(), $keyCol, $keyVals, $otherCols); return parent::pivotGetClass(get_called_class(), $keyCol, $keyVals, $otherCols);
} }
@ -110,7 +113,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* Exception is thrown when no entries are found. * Exception is thrown when no entries are found.
* *
*/ */
static function listFind($keyCol, array $keyVals) public static function listFind($keyCol, array $keyVals)
{ {
return parent::listFindClass(get_called_class(), $keyCol, $keyVals); return parent::listFindClass(get_called_class(), $keyCol, $keyVals);
} }
@ -128,7 +131,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return array with an get_called_class() object for each $keyVals entry * @return array with an get_called_class() object for each $keyVals entry
* *
*/ */
static function listGet($keyCol, array $keyVals) public static function listGet($keyCol, array $keyVals)
{ {
return parent::listGetClass(get_called_class(), $keyCol, $keyVals); return parent::listGetClass(get_called_class(), $keyCol, $keyVals);
} }
@ -153,7 +156,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @access private * @access private
* @return array * @return array
*/ */
function keys() public function keys()
{ {
return array_keys($this->keyTypes()); return array_keys($this->keyTypes());
} }
@ -167,7 +170,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return array (column,use_native,sequence_name) * @return array (column,use_native,sequence_name)
*/ */
function sequenceKey() public function sequenceKey()
{ {
$table = static::schemaDef(); $table = static::schemaDef();
foreach ($table['fields'] as $name => $column) { foreach ($table['fields'] as $name => $column) {
@ -191,7 +194,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return array key definitions * @return array key definitions
*/ */
function keyTypes() public function keyTypes()
{ {
$table = static::schemaDef(); $table = static::schemaDef();
$keys = array(); $keys = array();
@ -218,16 +221,17 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @param array $column * @param array $column
* @return int * @return int
*/ */
function columnBitmap($column) public function columnBitmap($column)
{ {
$type = $column['type']; $type = $column['type'];
// For quoting style... // For quoting style...
$intTypes = array('int', $intTypes = [
'integer', 'int',
'float', 'float',
'serial', 'serial',
'numeric'); 'numeric'
];
if (in_array($type, $intTypes)) { if (in_array($type, $intTypes)) {
$style = DB_DATAOBJECT_INT; $style = DB_DATAOBJECT_INT;
} else { } else {
@ -235,12 +239,15 @@ abstract class Managed_DataObject extends Memcached_DataObject
} }
// Data type formatting style... // Data type formatting style...
$formatStyles = array('blob' => DB_DATAOBJECT_BLOB, $formatStyles = [
'blob' => DB_DATAOBJECT_BLOB,
'text' => DB_DATAOBJECT_TXT, 'text' => DB_DATAOBJECT_TXT,
'bool' => DB_DATAOBJECT_BOOL,
'date' => DB_DATAOBJECT_DATE, 'date' => DB_DATAOBJECT_DATE,
'time' => DB_DATAOBJECT_TIME, 'time' => DB_DATAOBJECT_TIME,
'datetime' => DB_DATAOBJECT_DATE | DB_DATAOBJECT_TIME, 'datetime' => DB_DATAOBJECT_DATE | DB_DATAOBJECT_TIME,
'timestamp' => DB_DATAOBJECT_MYSQLTIMESTAMP); 'timestamp' => DB_DATAOBJECT_MYSQLTIMESTAMP,
];
if (isset($formatStyles[$type])) { if (isset($formatStyles[$type])) {
$style |= $formatStyles[$type]; $style |= $formatStyles[$type];
@ -254,7 +261,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
return $style; return $style;
} }
function links() public function links()
{ {
$links = array(); $links = array();
@ -277,7 +284,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* *
* @return array of strings * @return array of strings
*/ */
function _allCacheKeys() public function _allCacheKeys()
{ {
$table = static::schemaDef(); $table = static::schemaDef();
$ckeys = array(); $ckeys = array();
@ -322,7 +329,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return Managed_DataObject of the get_called_class() type * @return Managed_DataObject of the get_called_class() type
* @throws NoResultException if no object with that primary key * @throws NoResultException if no object with that primary key
*/ */
static function getByPK(array $vals) public static function getByPK(array $vals)
{ {
$classname = get_called_class(); $classname = get_called_class();
@ -356,7 +363,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
* @return Managed_DataObject of the get_called_class() type * @return Managed_DataObject of the get_called_class() type
* @throws NoResultException if no object with that primary key * @throws NoResultException if no object with that primary key
*/ */
static function getByKeys(array $vals) public static function getByKeys(array $vals)
{ {
$classname = get_called_class(); $classname = get_called_class();
@ -381,7 +388,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
return $object; return $object;
} }
static function getByID($id) public static function getByID($id)
{ {
if (!property_exists(get_called_class(), 'id')) { if (!property_exists(get_called_class(), 'id')) {
throw new ServerException('Trying to get undefined property of dataobject class.'); throw new ServerException('Trying to get undefined property of dataobject class.');
@ -394,7 +401,7 @@ abstract class Managed_DataObject extends Memcached_DataObject
return static::getByPK(array('id' => $id)); return static::getByPK(array('id' => $id));
} }
static function getByUri($uri) public static function getByUri($uri)
{ {
if (!property_exists(get_called_class(), 'uri')) { if (!property_exists(get_called_class(), 'uri')) {
throw new ServerException('Trying to get undefined property of dataobject class.'); throw new ServerException('Trying to get undefined property of dataobject class.');
@ -537,18 +544,20 @@ abstract class Managed_DataObject extends Memcached_DataObject
$pid = $schema['primary key']; $pid = $schema['primary key'];
unset($schema); unset($schema);
} }
$pidWhere = array(); $pidWhere = [];
foreach((array)$pid as $pidCol) { foreach ((array) $pid as $pidCol) {
$pidWhere[] = sprintf('%1$s = %2$s', $pidCol, $this->_quote($orig->$pidCol)); $pidWhere[] = sprintf('%1$s = %2$s', $pidCol, $this->_quote($orig->$pidCol));
} }
if (empty($pidWhere)) { if (empty($pidWhere)) {
throw new ServerException('No primary ID column(s) set for updateWithKeys'); throw new ServerException('No primary ID column(s) set for updateWithKeys');
} }
$qry = sprintf('UPDATE %1$s SET %2$s WHERE %3$s', $qry = sprintf(
common_database_tablename($this->tableName()), 'UPDATE %1$s SET %2$s WHERE %3$s',
$this->escapedTableName(),
implode(', ', $parts), implode(', ', $parts),
implode(' AND ', $pidWhere)); implode(' AND ', $pidWhere)
);
$result = $this->query($qry); $result = $this->query($qry);
if ($result === false) { if ($result === false) {
@ -576,21 +585,23 @@ abstract class Managed_DataObject extends Memcached_DataObject
return $result; return $result;
} }
static public function beforeSchemaUpdate() public static function beforeSchemaUpdate()
{ {
// NOOP // NOOP
} }
static function newUri(Profile $actor, Managed_DataObject $object, $created=null) public static function newUri(Profile $actor, Managed_DataObject $object, $created = null)
{ {
if (is_null($created)) { if (is_null($created)) {
$created = common_sql_now(); $created = common_sql_now();
} }
return TagURI::mint(strtolower(get_called_class()).':%d:%s:%d:%s', return TagURI::mint(
strtolower(get_called_class()) . ':%d:%s:%d:%s',
$actor->getID(), $actor->getID(),
ActivityUtils::resolveUri($object->getObjectType(), true), ActivityUtils::resolveUri($object->getObjectType(), true),
$object->getID(), $object->getID(),
common_date_iso8601($created)); common_date_iso8601($created)
);
} }
protected function onInsert() protected function onInsert()

View File

@ -1,23 +1,25 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>. /**
* @copyright 2008, 2009 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
class Memcached_DataObject extends Safe_DataObject class Memcached_DataObject extends Safe_DataObject
{ {
@ -30,7 +32,7 @@ class Memcached_DataObject extends Safe_DataObject
* @param mixed $v key field value, or leave out for primary key lookup * @param mixed $v key field value, or leave out for primary key lookup
* @return mixed Memcached_DataObject subtype or false * @return mixed Memcached_DataObject subtype or false
*/ */
static function getClassKV($cls, $k, $v=null) public static function getClassKV($cls, $k, $v = null)
{ {
if (is_null($v)) { if (is_null($v)) {
$v = $k; $v = $k;
@ -71,7 +73,7 @@ class Memcached_DataObject extends Safe_DataObject
* *
* @return array Array of objects, in order * @return array Array of objects, in order
*/ */
static function multiGetClass($cls, $keyCol, array $keyVals, $skipNulls=true) public static function multiGetClass($cls, $keyCol, array $keyVals, $skipNulls = true)
{ {
$obj = new $cls; $obj = new $cls;
@ -100,8 +102,27 @@ class Memcached_DataObject extends Safe_DataObject
$keyVals[$key] = $obj->escape($val); $keyVals[$key] = $obj->escape($val);
} }
// FIND_IN_SET will make sure we keep the desired order switch (common_config('db', 'type')) {
$obj->orderBy(sprintf("FIND_IN_SET(%s, '%s')", $keyCol, implode(',', $keyVals))); case 'pgsql':
// "position" will make sure we keep the desired order
$obj->orderBy(sprintf(
"position(',' || CAST(%s AS text) || ',' IN ',%s,')",
$keyCol,
implode(',', $keyVals)
));
break;
case 'mysql':
// "find_in_set" will make sure we keep the desired order
$obj->orderBy(sprintf(
"find_in_set(%s, '%s')",
$keyCol,
implode(',', $keyVals)
));
break;
default:
throw new ServerException('Unknown DB type selected.');
}
$obj->find(); $obj->find();
return $obj; return $obj;
@ -117,7 +138,7 @@ class Memcached_DataObject extends Safe_DataObject
* *
* @return array Array mapping $keyVals to objects, or null if not found * @return array Array mapping $keyVals to objects, or null if not found
*/ */
static function pivotGetClass($cls, $keyCol, array $keyVals, array $otherCols = array()) public static function pivotGetClass($cls, $keyCol, array $keyVals, array $otherCols = [])
{ {
if (is_array($keyCol)) { if (is_array($keyCol)) {
foreach ($keyVals as $keyVal) { foreach ($keyVals as $keyVal) {
@ -130,7 +151,6 @@ class Memcached_DataObject extends Safe_DataObject
$toFetch = array(); $toFetch = array();
foreach ($keyVals as $keyVal) { foreach ($keyVals as $keyVal) {
if (is_array($keyCol)) { if (is_array($keyCol)) {
$kv = array_combine($keyCol, $keyVal); $kv = array_combine($keyCol, $keyVal);
} else { } else {
@ -147,7 +167,7 @@ class Memcached_DataObject extends Safe_DataObject
} else { } else {
$result[$keyVal] = $i; $result[$keyVal] = $i;
} }
} else if (!empty($keyVal)) { } elseif (!empty($keyVal)) {
$toFetch[] = $keyVal; $toFetch[] = $keyVal;
} }
} }
@ -207,7 +227,7 @@ class Memcached_DataObject extends Safe_DataObject
return $result; return $result;
} }
static function _inMultiKey($i, $cols, $values) public static function _inMultiKey($i, $cols, $values)
{ {
$types = array(); $types = array();
@ -255,7 +275,7 @@ class Memcached_DataObject extends Safe_DataObject
return $query; return $query;
} }
static function pkeyColsClass($cls) public static function pkeyColsClass($cls)
{ {
$i = new $cls; $i = new $cls;
$types = $i->keyTypes(); $types = $i->keyTypes();
@ -272,7 +292,7 @@ class Memcached_DataObject extends Safe_DataObject
return $pkey; return $pkey;
} }
static function listFindClass($cls, $keyCol, array $keyVals) public static function listFindClass($cls, $keyCol, array $keyVals)
{ {
$i = new $cls; $i = new $cls;
$i->whereAddIn($keyCol, $keyVals, $i->columnType($keyCol)); $i->whereAddIn($keyCol, $keyVals, $i->columnType($keyCol));
@ -283,7 +303,7 @@ class Memcached_DataObject extends Safe_DataObject
return $i; return $i;
} }
static function listGetClass($cls, $keyCol, array $keyVals) public static function listGetClass($cls, $keyCol, array $keyVals)
{ {
$pkeyMap = array_fill_keys($keyVals, array()); $pkeyMap = array_fill_keys($keyVals, array());
$result = array_fill_keys($keyVals, array()); $result = array_fill_keys($keyVals, array());
@ -296,7 +316,7 @@ class Memcached_DataObject extends Safe_DataObject
// We only cache keys -- not objects! // We only cache keys -- not objects!
foreach ($keyVals as $keyVal) { foreach ($keyVals as $keyVal) {
$l = self::cacheGet(sprintf("%s:list-ids:%s:%s", strtolower($cls), $keyCol, $keyVal)); $l = self::cacheGet(sprintf('%s:list-ids:%s:%s', strtolower($cls), $keyCol, $keyVal));
if ($l !== false) { if ($l !== false) {
$pkeyMap[$keyVal] = $l; $pkeyMap[$keyVal] = $l;
foreach ($l as $pkey) { foreach ($l as $pkey) {
@ -312,7 +332,7 @@ class Memcached_DataObject extends Safe_DataObject
foreach ($pkeyMap as $keyVal => $pkeyList) { foreach ($pkeyMap as $keyVal => $pkeyList) {
foreach ($pkeyList as $pkeyVal) { foreach ($pkeyList as $pkeyVal) {
$i = $keyResults[implode(',',$pkeyVal)]; $i = $keyResults[implode(',', $pkeyVal)];
if (!empty($i)) { if (!empty($i)) {
$result[$keyVal][] = $i; $result[$keyVal][] = $i;
} }
@ -338,15 +358,17 @@ class Memcached_DataObject extends Safe_DataObject
// no results found for our keyVals, so we leave them as empty arrays // no results found for our keyVals, so we leave them as empty arrays
} }
foreach ($toFetch as $keyVal) { foreach ($toFetch as $keyVal) {
self::cacheSet(sprintf("%s:list-ids:%s:%s", strtolower($cls), $keyCol, $keyVal), self::cacheSet(
$pkeyMap[$keyVal]); sprintf("%s:list-ids:%s:%s", strtolower($cls), $keyCol, $keyVal),
$pkeyMap[$keyVal]
);
} }
} }
return $result; return $result;
} }
function columnType($columnName) public function columnType($columnName)
{ {
$keys = $this->table(); $keys = $this->table();
if (!array_key_exists($columnName, $keys)) { if (!array_key_exists($columnName, $keys)) {
@ -365,7 +387,7 @@ class Memcached_DataObject extends Safe_DataObject
/** /**
* @todo FIXME: Should this return false on lookup fail to match getKV? * @todo FIXME: Should this return false on lookup fail to match getKV?
*/ */
static function pkeyGetClass($cls, array $kv) public static function pkeyGetClass($cls, array $kv)
{ {
$i = self::multicache($cls, $kv); $i = self::multicache($cls, $kv);
if ($i !== false) { // false == cache miss if ($i !== false) { // false == cache miss
@ -395,7 +417,7 @@ class Memcached_DataObject extends Safe_DataObject
} }
} }
function insert() public function insert()
{ {
$result = parent::insert(); $result = parent::insert();
if ($result) { if ($result) {
@ -405,7 +427,7 @@ class Memcached_DataObject extends Safe_DataObject
return $result; return $result;
} }
function update($dataObject=false) public function update($dataObject = false)
{ {
if (is_object($dataObject) && $dataObject instanceof Memcached_DataObject) { if (is_object($dataObject) && $dataObject instanceof Memcached_DataObject) {
$dataObject->decache(); # might be different keys $dataObject->decache(); # might be different keys
@ -418,17 +440,19 @@ class Memcached_DataObject extends Safe_DataObject
return $result; return $result;
} }
function delete($useWhere=false) public function delete($useWhere = false)
{ {
$this->decache(); # while we still have the values! $this->decache(); # while we still have the values!
return parent::delete($useWhere); return parent::delete($useWhere);
} }
static function memcache() { public static function memcache()
{
return Cache::instance(); return Cache::instance();
} }
static function cacheKey($cls, $k, $v) { public static function cacheKey($cls, $k, $v)
{
if (is_object($cls) || is_object($k) || (is_object($v) && !($v instanceof DB_DataObject_Cast))) { if (is_object($cls) || is_object($k) || (is_object($v) && !($v instanceof DB_DataObject_Cast))) {
$e = new Exception(); $e = new Exception();
common_log(LOG_ERR, __METHOD__ . ' object in param: ' . common_log(LOG_ERR, __METHOD__ . ' object in param: ' .
@ -438,7 +462,8 @@ class Memcached_DataObject extends Safe_DataObject
return Cache::key(strtolower($cls).':'.$k.':'.$vstr); return Cache::key(strtolower($cls).':'.$k.':'.$vstr);
} }
static function getcached($cls, $k, $v) { public static function getcached($cls, $k, $v)
{
$c = self::memcache(); $c = self::memcache();
if (!$c) { if (!$c) {
return false; return false;
@ -456,7 +481,7 @@ class Memcached_DataObject extends Safe_DataObject
} }
} }
function keyTypes() public function keyTypes()
{ {
// ini-based classes return number-indexed arrays. handbuilt // ini-based classes return number-indexed arrays. handbuilt
// classes return column => keytype. Make this uniform. // classes return column => keytype. Make this uniform.
@ -472,18 +497,17 @@ class Memcached_DataObject extends Safe_DataObject
global $_DB_DATAOBJECT; global $_DB_DATAOBJECT;
if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"])) { if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"])) {
$this->databaseStructure(); $this->databaseStructure();
} }
return $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"]; return $_DB_DATAOBJECT['INI'][$this->_database][$this->tableName()."__keys"];
} }
function encache() public function encache()
{ {
$c = self::memcache(); $c = self::memcache();
if (!$c) { if (!$c) {
return false; return false;
} else if ($this->tableName() == 'user' && is_object($this->id)) { } elseif ($this->tableName() === 'user' && is_object($this->id)) {
// Special case for User bug // Special case for User bug
$e = new Exception(); $e = new Exception();
common_log(LOG_ERR, __METHOD__ . ' caching user with User object as ID ' . common_log(LOG_ERR, __METHOD__ . ' caching user with User object as ID ' .
@ -498,7 +522,7 @@ class Memcached_DataObject extends Safe_DataObject
} }
} }
function decache() public function decache()
{ {
$c = self::memcache(); $c = self::memcache();
@ -513,7 +537,7 @@ class Memcached_DataObject extends Safe_DataObject
} }
} }
function _allCacheKeys() public function _allCacheKeys()
{ {
$ckeys = array(); $ckeys = array();
@ -524,7 +548,6 @@ class Memcached_DataObject extends Safe_DataObject
$pval = array(); $pval = array();
foreach ($types as $key => $type) { foreach ($types as $key => $type) {
assert(!empty($key)); assert(!empty($key));
if ($type == 'U') { if ($type == 'U') {
@ -532,7 +555,7 @@ class Memcached_DataObject extends Safe_DataObject
continue; continue;
} }
$ckeys[] = self::cacheKey($this->tableName(), $key, self::valueString($this->$key)); $ckeys[] = self::cacheKey($this->tableName(), $key, self::valueString($this->$key));
} else if ($type == 'K' || $type == 'N') { } elseif (in_array($type, ['K', 'N'])) {
$pkey[] = $key; $pkey[] = $key;
$pval[] = self::valueString($this->$key); $pval[] = self::valueString($this->$key);
} else { } else {
@ -552,7 +575,7 @@ class Memcached_DataObject extends Safe_DataObject
return $ckeys; return $ckeys;
} }
static function multicache($cls, $kv) public static function multicache($cls, $kv)
{ {
ksort($kv); ksort($kv);
$c = self::memcache(); $c = self::memcache();
@ -563,7 +586,7 @@ class Memcached_DataObject extends Safe_DataObject
} }
} }
static function multicacheKey($cls, $kv) public static function multicacheKey($cls, $kv)
{ {
ksort($kv); ksort($kv);
$pkeys = implode(',', array_keys($kv)); $pkeys = implode(',', array_keys($kv));
@ -571,30 +594,35 @@ class Memcached_DataObject extends Safe_DataObject
return self::cacheKey($cls, $pkeys, $pvals); return self::cacheKey($cls, $pkeys, $pvals);
} }
function getSearchEngine($table) public function getSearchEngine($table)
{ {
require_once INSTALLDIR . '/lib/search/search_engines.php'; require_once INSTALLDIR . '/lib/search/search_engines.php';
if (Event::handle('GetSearchEngine', array($this, $table, &$search_engine))) { if (Event::handle('GetSearchEngine', [$this, $table, &$search_engine])) {
if ('mysql' === common_config('db', 'type')) {
$type = common_config('search', 'type'); $type = common_config('search', 'type');
if ($type == 'like') { if ($type === 'like') {
$search_engine = new MySQLLikeSearch($this, $table); $search_engine = new SQLLikeSearch($this, $table);
} else if ($type == 'fulltext') { } elseif ($type === 'fulltext') {
switch (common_config('db', 'type')) {
case 'pgsql':
$search_engine = new PostgreSQLSearch($this, $table);
break;
case 'mysql':
$search_engine = new MySQLSearch($this, $table); $search_engine = new MySQLSearch($this, $table);
break;
default:
throw new ServerException('Unknown DB type selected.');
}
} else { } else {
// Low level exception. No need for i18n as discussed with Brion. // Low level exception. No need for i18n as discussed with Brion.
throw new ServerException('Unknown search type: ' . $type); throw new ServerException('Unknown search type: ' . $type);
} }
} else {
$search_engine = new PGSearch($this, $table);
}
} }
return $search_engine; return $search_engine;
} }
static function cachedQuery($cls, $qry, $expiry=3600) public static function cachedQuery($cls, $qry, $expiry = 3600)
{ {
$c = self::memcache(); $c = self::memcache();
if (!$c) { if (!$c) {
@ -631,7 +659,7 @@ class Memcached_DataObject extends Safe_DataObject
* @access private * @access private
* @return mixed none or PEAR_Error * @return mixed none or PEAR_Error
*/ */
function _query($string) public function _query($string)
{ {
if (common_config('db', 'annotate_queries')) { if (common_config('db', 'annotate_queries')) {
$string = $this->annotateQuery($string); $string = $this->annotateQuery($string);
@ -680,7 +708,7 @@ class Memcached_DataObject extends Safe_DataObject
* @param string $string SQL query string * @param string $string SQL query string
* @return string SQL query string, with a comment in it * @return string SQL query string, with a comment in it
*/ */
function annotateQuery($string) public function annotateQuery($string)
{ {
$ignore = array('annotateQuery', $ignore = array('annotateQuery',
'_query', '_query',
@ -707,7 +735,7 @@ class Memcached_DataObject extends Safe_DataObject
} }
$here = $frame['class'] . '::' . $func; $here = $frame['class'] . '::' . $func;
break; break;
} else if (isset($frame['type']) && $frame['type'] == '->') { } elseif (isset($frame['type']) && $frame['type'] === '->') {
if ($frame['object'] === $this && in_array($func, $ignore)) { if ($frame['object'] === $this && in_array($func, $ignore)) {
continue; continue;
} }
@ -736,7 +764,7 @@ class Memcached_DataObject extends Safe_DataObject
// Sanitize a query for logging // Sanitize a query for logging
// @fixme don't trim spaces in string literals // @fixme don't trim spaces in string literals
function sanitizeQuery($string) public function sanitizeQuery($string)
{ {
$string = preg_replace('/\s+/', ' ', $string); $string = preg_replace('/\s+/', ' ', $string);
$string = trim($string); $string = trim($string);
@ -746,7 +774,7 @@ class Memcached_DataObject extends Safe_DataObject
// We overload so that 'SET NAMES "utf8mb4"' is called for // We overload so that 'SET NAMES "utf8mb4"' is called for
// each connection // each connection
function _connect() public function _connect()
{ {
global $_DB_DATAOBJECT, $_PEAR; global $_DB_DATAOBJECT, $_PEAR;
@ -794,7 +822,7 @@ class Memcached_DataObject extends Safe_DataObject
if (!empty($conn)) { if (!empty($conn)) {
if ($DB instanceof DB_mysqli || $DB instanceof MDB2_Driver_mysqli) { if ($DB instanceof DB_mysqli || $DB instanceof MDB2_Driver_mysqli) {
mysqli_set_charset($conn, 'utf8mb4'); mysqli_set_charset($conn, 'utf8mb4');
} else if ($DB instanceof DB_mysql || $DB instanceof MDB2_Driver_mysql) { } elseif ($DB instanceof DB_mysql || $DB instanceof MDB2_Driver_mysql) {
mysql_set_charset('utf8mb4', $conn); mysql_set_charset('utf8mb4', $conn);
} }
} }
@ -810,7 +838,7 @@ class Memcached_DataObject extends Safe_DataObject
// XXX: largely cadged from DB_DataObject // XXX: largely cadged from DB_DataObject
function _getDbDsnMD5() public function _getDbDsnMD5()
{ {
if ($this->_database_dsn_md5) { if ($this->_database_dsn_md5) {
return $this->_database_dsn_md5; return $this->_database_dsn_md5;
@ -828,7 +856,7 @@ class Memcached_DataObject extends Safe_DataObject
return $sum; return $sum;
} }
function _getDbDsn() public function _getDbDsn()
{ {
global $_DB_DATAOBJECT; global $_DB_DATAOBJECT;
@ -843,14 +871,13 @@ class Memcached_DataObject extends Safe_DataObject
$dsn = isset($this->_database_dsn) ? $this->_database_dsn : null; $dsn = isset($this->_database_dsn) ? $this->_database_dsn : null;
if (!$dsn) { if (!$dsn) {
if (!$this->_database) { if (!$this->_database) {
$this->_database = isset($options["table_{$this->tableName()}"]) ? $options["table_{$this->tableName()}"] : null; $this->_database = isset($options["table_{$this->tableName()}"]) ? $options["table_{$this->tableName()}"] : null;
} }
if ($this->_database && !empty($options["database_{$this->_database}"])) { if ($this->_database && !empty($options["database_{$this->_database}"])) {
$dsn = $options["database_{$this->_database}"]; $dsn = $options["database_{$this->_database}"];
} else if (!empty($options['database'])) { } elseif (!empty($options['database'])) {
$dsn = $options['database']; $dsn = $options['database'];
} }
} }
@ -863,7 +890,7 @@ class Memcached_DataObject extends Safe_DataObject
return $dsn; return $dsn;
} }
static function blow() public static function blow()
{ {
$c = self::memcache(); $c = self::memcache();
@ -882,7 +909,7 @@ class Memcached_DataObject extends Safe_DataObject
return $c->delete($cacheKey); return $c->delete($cacheKey);
} }
function fixupTimestamps() public function fixupTimestamps()
{ {
// Fake up timestamp columns // Fake up timestamp columns
$columns = $this->table(); $columns = $this->table();
@ -893,12 +920,12 @@ class Memcached_DataObject extends Safe_DataObject
} }
} }
function debugDump() public function debugDump()
{ {
common_debug("debugDump: " . common_log_objstring($this)); common_debug("debugDump: " . common_log_objstring($this));
} }
function raiseError($message, $type = null, $behaviour = null) public function raiseError($message, $type = null, $behavior = null)
{ {
$id = get_class($this); $id = get_class($this);
if (!empty($this->id)) { if (!empty($this->id)) {
@ -911,7 +938,7 @@ class Memcached_DataObject extends Safe_DataObject
throw new ServerException("[$id] DB_DataObject error [$type]: $message"); throw new ServerException("[$id] DB_DataObject error [$type]: $message");
} }
static function cacheGet($keyPart) public static function cacheGet($keyPart)
{ {
$c = self::memcache(); $c = self::memcache();
@ -924,7 +951,7 @@ class Memcached_DataObject extends Safe_DataObject
return $c->get($cacheKey); return $c->get($cacheKey);
} }
static function cacheSet($keyPart, $value, $flag=null, $expiry=null) public static function cacheSet($keyPart, $value, $flag = null, $expiry = null)
{ {
$c = self::memcache(); $c = self::memcache();
@ -937,7 +964,7 @@ class Memcached_DataObject extends Safe_DataObject
return $c->set($cacheKey, $value, $flag, $expiry); return $c->set($cacheKey, $value, $flag, $expiry);
} }
static function valueString($v) public static function valueString($v)
{ {
$vstr = null; $vstr = null;
if (is_object($v) && $v instanceof DB_DataObject_Cast) { if (is_object($v) && $v instanceof DB_DataObject_Cast) {

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,32 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* GNU social
*
* Data class for Notice preferences * Data class for Notice preferences
* *
* 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 Data * @category Data
* @package GNUsocial * @package GNUsocial
* @author Mikael Nordfeldth <mmn@hethane.se> * @author Mikael Nordfeldth <mmn@hethane.se>
* @copyright 2013 Free Software Foundation, Inc. * @author Diogo Cordeiro <diogo@fc.up.pt>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @copyright 2013 Free Software Foundation, Inc http://www.fsf.org
* @link http://www.gnu.org/software/social/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
defined('GNUSOCIAL') || die();
class Notice_prefs extends Managed_DataObject class Notice_prefs extends Managed_DataObject
{ {
public $__table = 'notice_prefs'; // table name public $__table = 'notice_prefs'; // table name
@ -58,7 +58,7 @@ class Notice_prefs extends Managed_DataObject
); );
} }
static function getNamespacePrefs(Notice $notice, $namespace, array $topic=array()) public static function getNamespacePrefs(Notice $notice, $namespace, array $topic = [])
{ {
if (empty($topic)) { if (empty($topic)) {
$prefs = new Notice_prefs(); $prefs = new Notice_prefs();
@ -76,13 +76,13 @@ class Notice_prefs extends Managed_DataObject
return $prefs; return $prefs;
} }
static function getNamespace(Notice $notice, $namespace, array $topic=array()) public static function getNamespace(Notice $notice, $namespace, array $topic = [])
{ {
$prefs = self::getNamespacePrefs($notice, $namespace, $topic); $prefs = self::getNamespacePrefs($notice, $namespace, $topic);
return $prefs->fetchAll(); return $prefs->fetchAll();
} }
static function getAll(Notice $notice) public static function getAll(Notice $notice)
{ {
try { try {
$prefs = self::listFind('notice_id', array($notice->getID())); $prefs = self::listFind('notice_id', array($notice->getID()));
@ -100,13 +100,17 @@ class Notice_prefs extends Managed_DataObject
return $list; return $list;
} }
static function getTopic(Notice $notice, $namespace, $topic) { public static function getTopic(Notice $notice, $namespace, $topic)
return self::getByPK(array('notice_id' => $notice->getID(), {
return self::getByPK([
'notice_id' => $notice->getID(),
'namespace' => $namespace, 'namespace' => $namespace,
'topic' => $topic)); 'topic' => $topic,
]);
} }
static function getData(Notice $notice, $namespace, $topic, $def=null) { public static function getData(Notice $notice, $namespace, $topic, $def = null)
{
try { try {
$pref = self::getTopic($notice, $namespace, $topic); $pref = self::getTopic($notice, $namespace, $topic);
} catch (NoResultException $e) { } catch (NoResultException $e) {
@ -120,7 +124,8 @@ class Notice_prefs extends Managed_DataObject
return $pref->data; return $pref->data;
} }
static function getConfigData(Notice $notice, $namespace, $topic) { public static function getConfigData(Notice $notice, $namespace, $topic)
{
try { try {
$data = self::getData($notice, $namespace, $topic); $data = self::getData($notice, $namespace, $topic);
} catch (NoResultException $e) { } catch (NoResultException $e) {
@ -140,14 +145,15 @@ class Notice_prefs extends Managed_DataObject
* @return true if changes are made, false if no action taken * @return true if changes are made, false if no action taken
* @throws ServerException if preference could not be saved * @throws ServerException if preference could not be saved
*/ */
static function setData(Notice $notice, $namespace, $topic, $data=null) { public static function setData(Notice $notice, $namespace, $topic, $data = null)
{
try { try {
$pref = self::getTopic($notice, $namespace, $topic); $pref = self::getTopic($notice, $namespace, $topic);
if (is_null($data)) { if (is_null($data)) {
$pref->delete(); $pref->delete();
} else { } else {
$orig = clone($pref); $orig = clone($pref);
$pref->data = $data; $pref->data = DB_DataObject_Cast::blob($data);
$pref->update($orig); $pref->update($orig);
} }
return true; return true;
@ -161,7 +167,7 @@ class Notice_prefs extends Managed_DataObject
$pref->notice_id = $notice->getID(); $pref->notice_id = $notice->getID();
$pref->namespace = $namespace; $pref->namespace = $namespace;
$pref->topic = $topic; $pref->topic = $topic;
$pref->data = $data; $pref->data = DB_DataObject_Cast::blob($data);
$pref->created = common_sql_now(); $pref->created = common_sql_now();
if ($pref->insert() === false) { if ($pref->insert() === false) {

View File

@ -1,9 +1,26 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
/** /**
* Table Definition for notice_source * Table Definition for notice_source
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Notice_source extends Managed_DataObject class Notice_source extends Managed_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
@ -26,7 +43,7 @@ class Notice_source extends Managed_DataObject
'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'source code'), 'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'source code'),
'name' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'name of the source'), 'name' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'name of the source'),
'url' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'url to link to'), 'url' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'url to link to'),
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'date this record was created'), 'notice_id' => array('type' => 'int', 'not null' => true, 'default' => 0, 'description' => 'date this record was created'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'),
), ),

View File

@ -1,9 +1,26 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
/** /**
* Table Definition for oauth_application_user * Table Definition for oauth_application_user
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Oauth_application_user extends Managed_DataObject class Oauth_application_user extends Managed_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
@ -39,7 +56,7 @@ class Oauth_application_user extends Managed_DataObject
); );
} }
static function getByUserAndToken($user, $token) public static function getByUserAndToken($user, $token)
{ {
if (empty($user) || empty($token)) { if (empty($user) || empty($token)) {
return null; return null;
@ -56,7 +73,7 @@ class Oauth_application_user extends Managed_DataObject
return empty($result) ? null : $oau; return empty($result) ? null : $oau;
} }
function updateKeys(&$orig) public function updateKeys(&$orig)
{ {
$this->_connect(); $this->_connect();
$parts = array(); $parts = array();
@ -72,13 +89,11 @@ class Oauth_application_user extends Managed_DataObject
$toupdate = implode(', ', $parts); $toupdate = implode(', ', $parts);
$table = $this->tableName(); $table = $this->tableName();
if(common_config('db','quote_identifiers')) { $tableName = $this->escapedTableName();
$table = '"' . $table . '"'; $qry = 'UPDATE ' . $tableName . ' SET ' . $toupdate .
} ' WHERE profile_id = ' . $orig->profile_id .
$qry = 'UPDATE ' . $table . ' SET ' . $toupdate . ' AND application_id = ' . $orig->application_id .
' WHERE profile_id = ' . $orig->profile_id " AND token = '" . $orig->token . "'";
. ' AND application_id = ' . $orig->application_id
. " AND token = '$orig->token'";
$orig->decache(); $orig->decache();
$result = $this->query($qry); $result = $this->query($qry);
if ($result) { if ($result) {

View File

@ -1,9 +1,26 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
/** /**
* Table Definition for oauth_association * Table Definition for oauth_association
*/ */
require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
class Oauth_token_association extends Managed_DataObject class Oauth_token_association extends Managed_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
@ -19,7 +36,7 @@ class Oauth_token_association extends Managed_DataObject
/* the code above is auto generated do not remove the tag below */ /* the code above is auto generated do not remove the tag below */
###END_AUTOCODE ###END_AUTOCODE
static function getByUserAndToken($user, $token) public static function getByUserAndToken($user, $token)
{ {
if (empty($user) || empty($token)) { if (empty($user) || empty($token)) {
return null; return null;
@ -49,8 +66,8 @@ class Oauth_token_association extends Managed_DataObject
), ),
'primary key' => array('profile_id', 'application_id', 'token'), 'primary key' => array('profile_id', 'application_id', 'token'),
'foreign keys' => array( 'foreign keys' => array(
'oauth_token_association_profile_fkey' => array('profile_id', array('profile' => 'id')), 'oauth_token_association_profile_fkey' => array('profile', array('profile_id' => 'id')),
'oauth_token_association_application_fkey' => array('application_id', array('application' => 'id')), 'oauth_token_association_application_fkey' => array('oauth_application', array('application_id' => 'id')),
) )
); );
} }

View File

@ -1,48 +1,36 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Older-style UI preferences * Older-style UI preferences
* *
* 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 UI * @category UI
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
// This check helps protect against security problems;
// your code file can't be executed directly from the web.
exit(1);
}
/** /**
* Separate table for storing UI preferences * Separate table for storing UI preferences
* *
* @category UI
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class Old_school_prefs extends Managed_DataObject class Old_school_prefs extends Managed_DataObject
@ -60,17 +48,14 @@ class Old_school_prefs extends Managed_DataObject
return array( return array(
'fields' => array( 'fields' => array(
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who has the preference'), 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who has the preference'),
'stream_mode_only' => array('type' => 'int', 'stream_mode_only' => array('type' => 'bool',
'size' => 'tiny', 'default' => true,
'default' => 1,
'description' => 'No conversation streams'), 'description' => 'No conversation streams'),
'conversation_tree' => array('type' => 'int', 'conversation_tree' => array('type' => 'bool',
'size' => 'tiny', 'default' => true,
'default' => 1,
'description' => 'Hierarchical tree view for conversations'), 'description' => 'Hierarchical tree view for conversations'),
'stream_nicknames' => array('type' => 'int', 'stream_nicknames' => array('type' => 'bool',
'size' => 'tiny', 'default' => true,
'default' => 1,
'description' => 'Show nicknames for authors and addressees in streams'), 'description' => 'Show nicknames for authors and addressees in streams'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'),

View File

@ -1,23 +1,25 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008-2011, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>. /**
* @copyright 2008-2011 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Table Definition for profile * Table Definition for profile
@ -202,7 +204,7 @@ class Profile extends Managed_DataObject
* *
* @return string * @return string
*/ */
function getBestName() public function getBestName()
{ {
return ($this->fullname) ? $this->fullname : $this->nickname; return ($this->fullname) ? $this->fullname : $this->nickname;
} }
@ -211,7 +213,7 @@ class Profile extends Managed_DataObject
* Takes the currently scoped profile into account to give a name * Takes the currently scoped profile into account to give a name
* to list in notice streams. Preferences may differ between profiles. * to list in notice streams. Preferences may differ between profiles.
*/ */
function getStreamName() public function getStreamName()
{ {
$user = common_current_user(); $user = common_current_user();
if ($user instanceof User && $user->streamNicknames()) { if ($user instanceof User && $user->streamNicknames()) {
@ -228,7 +230,7 @@ class Profile extends Managed_DataObject
* *
* @return string * @return string
*/ */
function getFancyName() public function getFancyName()
{ {
$uri = null; $uri = null;
try { try {
@ -243,7 +245,7 @@ class Profile extends Managed_DataObject
if (mb_strlen($this->getFullname()) > 0) { if (mb_strlen($this->getFullname()) > 0) {
// TRANS: The "fancy name": Full name of a profile or group (%1$s) followed by some URI (%2$s) in parentheses. // TRANS: The "fancy name": Full name of a profile or group (%1$s) followed by some URI (%2$s) in parentheses.
return sprintf(_m('FANCYNAME','%1$s (%2$s)'), $this->getFullname(), $uri); return sprintf(_m('FANCYNAME', '%1$s (%2$s)'), $this->getFullname(), $uri);
} else { } else {
return $uri; return $uri;
} }
@ -254,7 +256,7 @@ class Profile extends Managed_DataObject
* *
* @return mixed Notice or null * @return mixed Notice or null
*/ */
function getCurrentNotice(Profile $scoped=null) public function getCurrentNotice(Profile $scoped = null)
{ {
try { try {
$notice = $this->getNotices(0, 1, 0, 0, $scoped); $notice = $this->getNotices(0, 1, 0, 0, $scoped);
@ -275,12 +277,12 @@ class Profile extends Managed_DataObject
return null; return null;
} }
function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) public function getReplies($offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $before_id = 0)
{ {
return Reply::stream($this->getID(), $offset, $limit, $since_id, $before_id); return Reply::stream($this->getID(), $offset, $limit, $since_id, $before_id);
} }
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) public function getTaggedNotices($tag, $offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $max_id = 0)
{ {
//FIXME: Get Profile::current() some other way to avoid possible //FIXME: Get Profile::current() some other way to avoid possible
// confusion between current session profile and background processing. // confusion between current session profile and background processing.
@ -289,14 +291,14 @@ class Profile extends Managed_DataObject
return $stream->getNotices($offset, $limit, $since_id, $max_id); return $stream->getNotices($offset, $limit, $since_id, $max_id);
} }
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, Profile $scoped=null) public function getNotices($offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $max_id = 0, Profile $scoped = null)
{ {
$stream = new ProfileNoticeStream($this, $scoped); $stream = new ProfileNoticeStream($this, $scoped);
return $stream->getNotices($offset, $limit, $since_id, $max_id); return $stream->getNotices($offset, $limit, $since_id, $max_id);
} }
function isMember(User_group $group) public function isMember(User_group $group)
{ {
$groups = $this->getGroups(0, null); $groups = $this->getGroups(0, null);
while ($groups instanceof User_group && $groups->fetch()) { while ($groups instanceof User_group && $groups->fetch()) {
@ -307,21 +309,21 @@ class Profile extends Managed_DataObject
return false; return false;
} }
function isAdmin(User_group $group) public function isAdmin(User_group $group)
{ {
$gm = Group_member::pkeyGet(array('profile_id' => $this->id, $gm = Group_member::pkeyGet(array('profile_id' => $this->id,
'group_id' => $group->id)); 'group_id' => $group->id));
return (!empty($gm) && $gm->is_admin); return (!empty($gm) && $gm->is_admin);
} }
function isPendingMember($group) public function isPendingMember($group)
{ {
$request = Group_join_queue::pkeyGet(array('profile_id' => $this->id, $request = Group_join_queue::pkeyGet(array('profile_id' => $this->id,
'group_id' => $group->id)); 'group_id' => $group->id));
return !empty($request); return !empty($request);
} }
function getGroups($offset=0, $limit=PROFILES_PER_PAGE) public function getGroups($offset = 0, $limit = PROFILES_PER_PAGE)
{ {
$ids = array(); $ids = array();
@ -356,14 +358,15 @@ class Profile extends Managed_DataObject
} }
} }
function getGroupCount() { public function getGroupCount()
{
$groups = $this->getGroups(0, null); $groups = $this->getGroups(0, null);
return $groups instanceof User_group return $groups instanceof User_group
? $groups->N ? $groups->N
: 0; : 0;
} }
function isTagged($peopletag) public function isTagged($peopletag)
{ {
$tag = Profile_tag::pkeyGet(array('tagger' => $peopletag->tagger, $tag = Profile_tag::pkeyGet(array('tagger' => $peopletag->tagger,
'tagged' => $this->id, 'tagged' => $this->id,
@ -371,7 +374,7 @@ class Profile extends Managed_DataObject
return !empty($tag); return !empty($tag);
} }
function canTag($tagged) public function canTag($tagged)
{ {
if (empty($tagged)) { if (empty($tagged)) {
return false; return false;
@ -395,16 +398,16 @@ class Profile extends Managed_DataObject
if ($local) { if ($local) {
return true; return true;
} }
} else if ($subs) { } elseif ($subs) {
return (Subscription::exists($this, $tagged) || return (Subscription::exists($this, $tagged) ||
Subscription::exists($tagged, $this)); Subscription::exists($tagged, $this));
} else if ($remote) { } elseif ($remote) {
return true; return true;
} }
return false; return false;
} }
function getLists(Profile $scoped=null, $offset=0, $limit=null, $since_id=0, $max_id=0) public function getLists(Profile $scoped = null, $offset = 0, $limit = null, $since_id = 0, $max_id = 0)
{ {
$ids = array(); $ids = array();
@ -421,15 +424,15 @@ class Profile extends Managed_DataObject
$list->tagger = $this->id; $list->tagger = $this->id;
$list->selectAdd('id as "cursor"'); $list->selectAdd('id as "cursor"');
if ($since_id>0) { if ($since_id > 0) {
$list->whereAdd('id > '.$since_id); $list->whereAdd('id > ' . $since_id);
} }
if ($max_id>0) { if ($max_id > 0) {
$list->whereAdd('id <= '.$max_id); $list->whereAdd('id <= ' . $max_id);
} }
if($offset>=0 && !is_null($limit)) { if ($offset >= 0 && !is_null($limit)) {
$list->limit($offset, $limit); $list->limit($offset, $limit);
} }
@ -452,7 +455,6 @@ class Profile extends Managed_DataObject
$list = Profile_list::getKV('id', $id); $list = Profile_list::getKV('id', $id);
if (!empty($list) && if (!empty($list) &&
($showPrivate || !$list->private)) { ($showPrivate || !$list->private)) {
if (!isset($list->cursor)) { if (!isset($list->cursor)) {
$list->cursor = $list->id; $list->cursor = $list->id;
} }
@ -476,33 +478,47 @@ class Profile extends Managed_DataObject
* @return Profile_list resulting lists * @return Profile_list resulting lists
*/ */
function getOtherTags(Profile $scoped=null, $offset=0, $limit=null, $since_id=0, $max_id=0) public function getOtherTags(Profile $scoped = null, int $offset = 0, ?int $limit = null, int $since = 0, int $upto = 0)
{ {
$list = new Profile_list(); $list = new Profile_list();
$qry = sprintf('select profile_list.*, unix_timestamp(profile_tag.modified) as "cursor" ' . if (common_config('db', 'type') !== 'mysql') {
'from profile_tag join profile_list '. $cursor = sprintf(
'on (profile_tag.tagger = profile_list.tagger ' . '((EXTRACT(DAY %1$s) * 24 + EXTRACT(HOUR %1$s)) * 60 + ' .
' and profile_tag.tag = profile_list.tag) ' . 'EXTRACT(MINUTE %1$s)) * 60 + FLOOR(EXTRACT(SECOND %1$s)) AS "cursor"',
'where profile_tag.tagged = %d ', "FROM (profile_tag.modified - TIMESTAMP '1970-01-01 00:00:00')"
$this->id); );
} else {
// The SQL/Foundation conforming implementation above doesn't work on MariaDB/MySQL
$cursor = "timestampdiff(SECOND, '1970-01-01', profile_tag.modified) AS `cursor`";
}
$qry = sprintf(
'SELECT profile_list.*, ' . $cursor . ' ' .
'FROM profile_tag INNER JOIN profile_list ' .
'ON (profile_tag.tagger = profile_list.tagger ' .
' AND profile_tag.tag = profile_list.tag) ' .
'WHERE profile_tag.tagged = %d ',
$this->id
);
if (!is_null($scoped)) { if (!is_null($scoped)) {
$qry .= sprintf('AND ( ( profile_list.private = false ) ' . $qry .= sprintf(
'AND ( profile_list.private = false ' .
'OR ( profile_list.tagger = %d AND ' . 'OR ( profile_list.tagger = %d AND ' .
'profile_list.private = true ) )', 'profile_list.private = TRUE ) )',
$scoped->getID()); $scoped->getID()
);
} else { } else {
$qry .= 'AND profile_list.private = 0 '; $qry .= 'AND profile_list.private = FALSE ';
} }
if ($since_id > 0) { if ($since > 0) {
$qry .= sprintf('AND (cursor > %d) ', $since_id); $qry .= 'AND cursor > ' . $since . ' ';
} }
if ($max_id > 0) { if ($upto > 0) {
$qry .= sprintf('AND (cursor < %d) ', $max_id); $qry .= 'AND cursor < ' . $upto . ' ';
} }
$qry .= 'ORDER BY profile_tag.modified DESC '; $qry .= 'ORDER BY profile_tag.modified DESC ';
@ -515,21 +531,21 @@ class Profile extends Managed_DataObject
return $list; return $list;
} }
function getPrivateTags($offset=0, $limit=null, $since_id=0, $max_id=0) public function getPrivateTags($offset = 0, $limit = null, $since_id = 0, $max_id = 0)
{ {
$tags = new Profile_list(); $tags = new Profile_list();
$tags->private = true; $tags->private = true;
$tags->tagger = $this->id; $tags->tagger = $this->id;
if ($since_id>0) { if ($since_id > 0) {
$tags->whereAdd('id > '.$since_id); $tags->whereAdd('id > ' . $since_id);
} }
if ($max_id>0) { if ($max_id > 0) {
$tags->whereAdd('id <= '.$max_id); $tags->whereAdd('id <= ' . $max_id);
} }
if($offset>=0 && !is_null($limit)) { if ($offset >= 0 && !is_null($limit)) {
$tags->limit($offset, $limit); $tags->limit($offset, $limit);
} }
@ -539,13 +555,13 @@ class Profile extends Managed_DataObject
return $tags; return $tags;
} }
function hasLocalTags() public function hasLocalTags()
{ {
$tags = new Profile_tag(); $tags = new Profile_tag();
$tags->joinAdd(array('tagger', 'user:id')); $tags->joinAdd(array('tagger', 'user:id'));
$tags->whereAdd('tagged = '.$this->id); $tags->whereAdd('tagged = ' . $this->id);
$tags->whereAdd('tagger != '.$this->id); $tags->whereAdd('tagger <> ' . $this->id);
$tags->limit(0, 1); $tags->limit(0, 1);
$tags->fetch(); $tags->fetch();
@ -553,31 +569,38 @@ class Profile extends Managed_DataObject
return ($tags->N == 0) ? false : true; return ($tags->N == 0) ? false : true;
} }
function getTagSubscriptions($offset=0, $limit=null, $since_id=0, $max_id=0) public function getTagSubscriptions(int $offset = 0, ?int $limit = null, int $since = 0, int $upto = 0)
{ {
$lists = new Profile_list(); $lists = new Profile_list();
$subs = new Profile_tag_subscription(); $subs = new Profile_tag_subscription();
$lists->joinAdd(array('id', 'profile_tag_subscription:profile_tag_id')); $lists->joinAdd(['id', 'profile_tag_subscription:profile_tag_id']);
#@fixme: postgres (round(date_part('epoch', my_date))) if (common_config('db', 'type') !== 'mysql') {
$lists->selectAdd('unix_timestamp(profile_tag_subscription.created) as "cursor"'); $lists->selectAdd(sprintf(
'((EXTRACT(DAY %1$s) * 24 + EXTRACT(HOUR %1$s)) * 60 + ' .
'EXTRACT(MINUTE %1$s)) * 60 + FLOOR(EXTRACT(SECOND %1$s)) AS "cursor"',
"FROM (profile_tag_subscription.created - TIMESTAMP '1970-01-01 00:00:00')"
));
} else {
$lists->selectAdd("timestampdiff(SECOND, '1970-01-01', profile_tag_subscription.created) AS `cursor`");
}
$lists->whereAdd('profile_tag_subscription.profile_id = '.$this->id); $lists->whereAdd('profile_tag_subscription.profile_id = '.$this->id);
if ($since_id>0) { if ($since > 0) {
$lists->whereAdd('cursor > '.$since_id); $lists->whereAdd('cursor > ' . $since);
} }
if ($max_id>0) { if ($upto > 0) {
$lists->whereAdd('cursor <= '.$max_id); $lists->whereAdd('cursor <= ' . $upto);
} }
if($offset>=0 && !is_null($limit)) { if ($offset >= 0 && !is_null($limit)) {
$lists->limit($offset, $limit); $lists->limit($offset, $limit);
} }
$lists->orderBy('"cursor" DESC'); $lists->orderBy('profile_tag_subscription.created DESC');
$lists->find(); $lists->find();
return $lists; return $lists;
@ -590,7 +613,7 @@ class Profile extends Managed_DataObject
* @param User_group $group * @param User_group $group
* @return mixed: Group_member on success, Group_join_queue if pending approval, null on some cancels? * @return mixed: Group_member on success, Group_join_queue if pending approval, null on some cancels?
*/ */
function joinGroup(User_group $group) public function joinGroup(User_group $group)
{ {
$join = null; $join = null;
if ($group->join_policy == User_group::JOIN_POLICY_MODERATE) { if ($group->join_policy == User_group::JOIN_POLICY_MODERATE) {
@ -616,7 +639,7 @@ class Profile extends Managed_DataObject
* *
* @param User_group $group * @param User_group $group
*/ */
function leaveGroup(User_group $group) public function leaveGroup(User_group $group)
{ {
if (Event::handle('StartLeaveGroup', array($group, $this))) { if (Event::handle('StartLeaveGroup', array($group, $this))) {
Group_member::leave($group->id, $this->id); Group_member::leave($group->id, $this->id);
@ -627,12 +650,12 @@ class Profile extends Managed_DataObject
} }
} }
function avatarUrl($size=AVATAR_PROFILE_SIZE) public function avatarUrl($size = AVATAR_PROFILE_SIZE)
{ {
return Avatar::urlByProfile($this, $size); return Avatar::urlByProfile($this, $size);
} }
function getSubscribed($offset=0, $limit=null) public function getSubscribed($offset = 0, $limit = null)
{ {
$subs = Subscription::getSubscribedIDs($this->id, $offset, $limit); $subs = Subscription::getSubscribedIDs($this->id, $offset, $limit);
try { try {
@ -643,7 +666,7 @@ class Profile extends Managed_DataObject
return $profiles; return $profiles;
} }
function getSubscribers($offset=0, $limit=null) public function getSubscribers($offset = 0, $limit = null)
{ {
$subs = Subscription::getSubscriberIDs($this->id, $offset, $limit); $subs = Subscription::getSubscriberIDs($this->id, $offset, $limit);
try { try {
@ -654,7 +677,7 @@ class Profile extends Managed_DataObject
return $profiles; return $profiles;
} }
function getTaggedSubscribers($tag, $offset=0, $limit=null) public function getTaggedSubscribers($tag, $offset = 0, $limit = null)
{ {
$qry = $qry =
'SELECT profile.* ' . 'SELECT profile.* ' .
@ -664,7 +687,7 @@ class Profile extends Managed_DataObject
'AND profile_tag.tagger = subscription.subscribed) ' . 'AND profile_tag.tagger = subscription.subscribed) ' .
'WHERE subscription.subscribed = %d ' . 'WHERE subscription.subscribed = %d ' .
"AND profile_tag.tag = '%s' " . "AND profile_tag.tag = '%s' " .
'AND subscription.subscribed != subscription.subscriber ' . 'AND subscription.subscribed <> subscription.subscriber ' .
'ORDER BY subscription.created DESC '; 'ORDER BY subscription.created DESC ';
if ($offset) { if ($offset) {
@ -678,7 +701,7 @@ class Profile extends Managed_DataObject
return $profile; return $profile;
} }
function getTaggedSubscriptions($tag, $offset=0, $limit=null) public function getTaggedSubscriptions($tag, $offset = 0, $limit = null)
{ {
$qry = $qry =
'SELECT profile.* ' . 'SELECT profile.* ' .
@ -688,7 +711,7 @@ class Profile extends Managed_DataObject
'AND profile_tag.tagger = subscription.subscriber) ' . 'AND profile_tag.tagger = subscription.subscriber) ' .
'WHERE subscription.subscriber = %d ' . 'WHERE subscription.subscriber = %d ' .
"AND profile_tag.tag = '%s' " . "AND profile_tag.tag = '%s' " .
'AND subscription.subscribed != subscription.subscriber ' . 'AND subscription.subscribed <> subscription.subscriber ' .
'ORDER BY subscription.created DESC '; 'ORDER BY subscription.created DESC ';
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
@ -707,7 +730,7 @@ class Profile extends Managed_DataObject
* @param int $limit * @param int $limit
* @return Profile * @return Profile
*/ */
function getRequests($offset=0, $limit=null) public function getRequests($offset = 0, $limit = null)
{ {
// FIXME: mysql only // FIXME: mysql only
$subqueue = new Profile(); $subqueue = new Profile();
@ -721,7 +744,7 @@ class Profile extends Managed_DataObject
return $subqueue; return $subqueue;
} }
function subscriptionCount() public function subscriptionCount()
{ {
$c = Cache::instance(); $c = Cache::instance();
@ -749,7 +772,7 @@ class Profile extends Managed_DataObject
return $cnt; return $cnt;
} }
function subscriberCount() public function subscriberCount()
{ {
$c = Cache::instance(); $c = Cache::instance();
if (!empty($c)) { if (!empty($c)) {
@ -761,8 +784,8 @@ class Profile extends Managed_DataObject
$sub = new Subscription(); $sub = new Subscription();
$sub->subscribed = $this->id; $sub->subscribed = $this->id;
$sub->whereAdd('subscriber != subscribed'); $sub->whereAdd('subscriber <> subscribed');
$cnt = (int) $sub->count('distinct subscriber'); $cnt = (int) $sub->count('DISTINCT subscriber');
if (!empty($c)) { if (!empty($c)) {
$c->set(Cache::key('profile:subscriber_count:'.$this->id), $cnt); $c->set(Cache::key('profile:subscriber_count:'.$this->id), $cnt);
@ -777,12 +800,12 @@ class Profile extends Managed_DataObject
* @param Profile $other * @param Profile $other
* @return boolean * @return boolean
*/ */
function isSubscribed(Profile $other) public function isSubscribed(Profile $other)
{ {
return Subscription::exists($this, $other); return Subscription::exists($this, $other);
} }
function readableBy(Profile $other=null) public function readableBy(Profile $other = null)
{ {
// If it's not a private stream, it's readable by anyone // If it's not a private stream, it's readable by anyone
if (!$this->isPrivateStream()) { if (!$this->isPrivateStream()) {
@ -793,7 +816,7 @@ class Profile extends Managed_DataObject
return is_null($other) ? false : $other->isSubscribed($this); return is_null($other) ? false : $other->isSubscribed($this);
} }
function requiresSubscriptionApproval(Profile $other=null): bool public function requiresSubscriptionApproval(Profile $other = null): bool
{ {
if (!$this->isLocal()) { if (!$this->isLocal()) {
// We don't know for remote users, and we'll always be able to send // We don't know for remote users, and we'll always be able to send
@ -818,7 +841,7 @@ class Profile extends Managed_DataObject
* @param Profile $other * @param Profile $other
* @return boolean * @return boolean
*/ */
function hasPendingSubscription(Profile $other) public function hasPendingSubscription(Profile $other)
{ {
return Subscription_queue::exists($this, $other); return Subscription_queue::exists($this, $other);
} }
@ -829,13 +852,13 @@ class Profile extends Managed_DataObject
* @param Profile $other * @param Profile $other
* @return boolean * @return boolean
*/ */
function mutuallySubscribed(Profile $other) public function mutuallySubscribed(Profile $other)
{ {
return $this->isSubscribed($other) && return $this->isSubscribed($other) &&
$other->isSubscribed($this); $other->isSubscribed($this);
} }
function noticeCount() public function noticeCount()
{ {
$c = Cache::instance(); $c = Cache::instance();
@ -858,7 +881,7 @@ class Profile extends Managed_DataObject
return $cnt; return $cnt;
} }
function blowSubscriberCount() public function blowSubscriberCount()
{ {
$c = Cache::instance(); $c = Cache::instance();
if (!empty($c)) { if (!empty($c)) {
@ -866,7 +889,7 @@ class Profile extends Managed_DataObject
} }
} }
function blowSubscriptionCount() public function blowSubscriptionCount()
{ {
$c = Cache::instance(); $c = Cache::instance();
if (!empty($c)) { if (!empty($c)) {
@ -874,7 +897,7 @@ class Profile extends Managed_DataObject
} }
} }
function blowNoticeCount() public function blowNoticeCount()
{ {
$c = Cache::instance(); $c = Cache::instance();
if (!empty($c)) { if (!empty($c)) {
@ -882,7 +905,7 @@ class Profile extends Managed_DataObject
} }
} }
static function maxBio() public static function maxBio()
{ {
$biolimit = common_config('profile', 'biolimit'); $biolimit = common_config('profile', 'biolimit');
// null => use global limit (distinct from 0!) // null => use global limit (distinct from 0!)
@ -892,13 +915,13 @@ class Profile extends Managed_DataObject
return $biolimit; return $biolimit;
} }
static function bioTooLong($bio) public static function bioTooLong($bio)
{ {
$biolimit = self::maxBio(); $biolimit = self::maxBio();
return ($biolimit > 0 && !empty($bio) && (mb_strlen($bio) > $biolimit)); return ($biolimit > 0 && !empty($bio) && (mb_strlen($bio) > $biolimit));
} }
function update($dataObject=false) public function update($dataObject = false)
{ {
if (is_object($dataObject) && $this->nickname != $dataObject->nickname) { if (is_object($dataObject) && $this->nickname != $dataObject->nickname) {
try { try {
@ -946,7 +969,7 @@ class Profile extends Managed_DataObject
return $relMes; return $relMes;
} }
function delete($useWhere=false) public function delete($useWhere = false)
{ {
$this->_deleteNotices(); $this->_deleteNotices();
$this->_deleteSubscriptions(); $this->_deleteSubscriptions();
@ -957,10 +980,11 @@ class Profile extends Managed_DataObject
// Warning: delete() will run on the batch objects, // Warning: delete() will run on the batch objects,
// not on individual objects. // not on individual objects.
$related = array('Reply', $related = [
'Reply',
'Group_member', 'Group_member',
'Profile_role' 'Profile_role',
); ];
Event::handle('ProfileDeleteRelated', array($this, &$related)); Event::handle('ProfileDeleteRelated', array($this, &$related));
foreach ($related as $cls) { foreach ($related as $cls) {
@ -979,7 +1003,7 @@ class Profile extends Managed_DataObject
return parent::delete($useWhere); return parent::delete($useWhere);
} }
function _deleteNotices() public function _deleteNotices()
{ {
$notice = new Notice(); $notice = new Notice();
$notice->profile_id = $this->id; $notice->profile_id = $this->id;
@ -992,7 +1016,7 @@ class Profile extends Managed_DataObject
} }
} }
function _deleteSubscriptions() public function _deleteSubscriptions()
{ {
$sub = new Subscription(); $sub = new Subscription();
$sub->subscriber = $this->getID(); $sub->subscriber = $this->getID();
@ -1040,14 +1064,14 @@ class Profile extends Managed_DataObject
$self->delete(); $self->delete();
} }
function _deleteTags() public function _deleteTags()
{ {
$tag = new Profile_tag(); $tag = new Profile_tag();
$tag->tagged = $this->id; $tag->tagged = $this->id;
$tag->delete(); $tag->delete();
} }
function _deleteBlocks() public function _deleteBlocks()
{ {
$block = new Profile_block(); $block = new Profile_block();
$block->blocked = $this->id; $block->blocked = $this->id;
@ -1058,7 +1082,7 @@ class Profile extends Managed_DataObject
$block->delete(); $block->delete();
} }
function _deleteAttentions() public function _deleteAttentions()
{ {
$att = new Attention(); $att = new Attention();
$att->profile_id = $this->getID(); $att->profile_id = $this->getID();
@ -1103,7 +1127,7 @@ class Profile extends Managed_DataObject
if ($cfg == 'always') { if ($cfg == 'always') {
return true; return true;
} else if ($cfg == 'never') { } elseif ($cfg == 'never') {
return false; return false;
} else { // user } else { // user
$share = common_config('location', 'sharedefault'); $share = common_config('location', 'sharedefault');
@ -1120,7 +1144,7 @@ class Profile extends Managed_DataObject
} }
} }
function hasRole($name) public function hasRole($name)
{ {
$has_role = false; $has_role = false;
if (Event::handle('StartHasRole', array($this, $name, &$has_role))) { if (Event::handle('StartHasRole', array($this, $name, &$has_role))) {
@ -1132,10 +1156,9 @@ class Profile extends Managed_DataObject
return $has_role; return $has_role;
} }
function grantRole($name) public function grantRole($name)
{ {
if (Event::handle('StartGrantRole', array($this, $name))) { if (Event::handle('StartGrantRole', array($this, $name))) {
$role = new Profile_role(); $role = new Profile_role();
$role->profile_id = $this->id; $role->profile_id = $this->id;
@ -1158,17 +1181,20 @@ class Profile extends Managed_DataObject
return $result; return $result;
} }
function revokeRole($name) public function revokeRole($name)
{ {
if (Event::handle('StartRevokeRole', array($this, $name))) { if (Event::handle('StartRevokeRole', array($this, $name))) {
$role = Profile_role::pkeyGet(array('profile_id' => $this->id, $role = Profile_role::pkeyGet(array('profile_id' => $this->id,
'role' => $name)); 'role' => $name));
if (empty($role)) { if (empty($role)) {
// TRANS: Exception thrown when trying to revoke an existing role for a user that does not exist. // TRANS: Exception thrown when trying to revoke an existing role for a user that does not exist.
// TRANS: %1$s is the role name, %2$s is the user ID (number). // TRANS: %1$s is the role name, %2$s is the user ID (number).
throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; does not exist.'),$name, $this->id)); throw new Exception(sprintf(
_('Cannot revoke role "%1$s" for user #%2$d; does not exist.'),
$name,
$this->id
));
} }
$result = $role->delete(); $result = $role->delete();
@ -1177,7 +1203,11 @@ class Profile extends Managed_DataObject
common_log_db_error($role, 'DELETE', __FILE__); common_log_db_error($role, 'DELETE', __FILE__);
// TRANS: Exception thrown when trying to revoke a role for a user with a failing database query. // TRANS: Exception thrown when trying to revoke a role for a user with a failing database query.
// TRANS: %1$s is the role name, %2$s is the user ID (number). // TRANS: %1$s is the role name, %2$s is the user ID (number).
throw new Exception(sprintf(_('Cannot revoke role "%1$s" for user #%2$d; database error.'),$name, $this->id)); throw new Exception(sprintf(
_('Cannot revoke role "%1$s" for user #%2$d; database error.'),
$name,
$this->id
));
} }
if ($name == 'owner') { if ($name == 'owner') {
@ -1190,27 +1220,27 @@ class Profile extends Managed_DataObject
} }
} }
function isSandboxed() public function isSandboxed()
{ {
return $this->hasRole(Profile_role::SANDBOXED); return $this->hasRole(Profile_role::SANDBOXED);
} }
function isSilenced() public function isSilenced()
{ {
return $this->hasRole(Profile_role::SILENCED); return $this->hasRole(Profile_role::SILENCED);
} }
function sandbox() public function sandbox()
{ {
$this->grantRole(Profile_role::SANDBOXED); $this->grantRole(Profile_role::SANDBOXED);
} }
function unsandbox() public function unsandbox()
{ {
$this->revokeRole(Profile_role::SANDBOXED); $this->revokeRole(Profile_role::SANDBOXED);
} }
function silence() public function silence()
{ {
$this->grantRole(Profile_role::SILENCED); $this->grantRole(Profile_role::SILENCED);
if (common_config('notice', 'hidespam')) { if (common_config('notice', 'hidespam')) {
@ -1218,7 +1248,7 @@ class Profile extends Managed_DataObject
} }
} }
function silenceAs(Profile $actor) public function silenceAs(Profile $actor)
{ {
if (!$actor->hasRight(Right::SILENCEUSER)) { if (!$actor->hasRight(Right::SILENCEUSER)) {
throw new AuthorizationException(_('You cannot silence users on this site.')); throw new AuthorizationException(_('You cannot silence users on this site.'));
@ -1234,7 +1264,7 @@ class Profile extends Managed_DataObject
return $this->silence(); return $this->silence();
} }
function unsilence() public function unsilence()
{ {
$this->revokeRole(Profile_role::SILENCED); $this->revokeRole(Profile_role::SILENCED);
if (common_config('notice', 'hidespam')) { if (common_config('notice', 'hidespam')) {
@ -1242,7 +1272,7 @@ class Profile extends Managed_DataObject
} }
} }
function unsilenceAs(Profile $actor) public function unsilenceAs(Profile $actor)
{ {
if (!$actor->hasRight(Right::SILENCEUSER)) { if (!$actor->hasRight(Right::SILENCEUSER)) {
// TRANS: Client error displayed trying to unsilence a user when the user does not have the right. // TRANS: Client error displayed trying to unsilence a user when the user does not have the right.
@ -1255,7 +1285,7 @@ class Profile extends Managed_DataObject
return $this->unsilence(); return $this->unsilence();
} }
function flushVisibility() public function flushVisibility()
{ {
// Get all notices // Get all notices
$stream = new ProfileNoticeStream($this, $this); $stream = new ProfileNoticeStream($this, $this);
@ -1301,8 +1331,7 @@ class Profile extends Managed_DataObject
} }
if (Event::handle('UserRightsCheck', array($this, $right, &$result))) { if (Event::handle('UserRightsCheck', array($this, $right, &$result))) {
switch ($right) switch ($right) {
{
case Right::DELETEOTHERSNOTICE: case Right::DELETEOTHERSNOTICE:
case Right::MAKEGROUPADMIN: case Right::MAKEGROUPADMIN:
case Right::SANDBOXUSER: case Right::SANDBOXUSER:
@ -1380,7 +1409,7 @@ class Profile extends Managed_DataObject
* *
* @return string * @return string
*/ */
function asAtomAuthor($cur = null) public function asAtomAuthor($cur = null)
{ {
$xs = new XMLStringer(true); $xs = new XMLStringer(true);
@ -1388,7 +1417,7 @@ class Profile extends Managed_DataObject
$xs->element('name', null, $this->nickname); $xs->element('name', null, $this->nickname);
$xs->element('uri', null, $this->getUri()); $xs->element('uri', null, $this->getUri());
if ($cur != null) { if ($cur != null) {
$attrs = Array(); $attrs = [];
$attrs['following'] = $cur->isSubscribed($this) ? 'true' : 'false'; $attrs['following'] = $cur->isSubscribed($this) ? 'true' : 'false';
$attrs['blocking'] = $cur->hasBlocked($this) ? 'true' : 'false'; $attrs['blocking'] = $cur->hasBlocked($this) ? 'true' : 'false';
$xs->element('statusnet:profile_info', $attrs, null); $xs->element('statusnet:profile_info', $attrs, null);
@ -1409,7 +1438,7 @@ class Profile extends Managed_DataObject
* @return array representation of <statusnet:profile_info> element or null * @return array representation of <statusnet:profile_info> element or null
*/ */
function profileInfo(Profile $scoped=null) public function profileInfo(Profile $scoped = null)
{ {
$profileInfoAttr = array('local_id' => $this->id); $profileInfoAttr = array('local_id' => $this->id);
@ -1431,7 +1460,7 @@ class Profile extends Managed_DataObject
* *
* @return string * @return string
*/ */
function asActivityActor() public function asActivityActor()
{ {
return $this->asActivityNoun('actor'); return $this->asActivityNoun('actor');
} }
@ -1447,7 +1476,7 @@ class Profile extends Managed_DataObject
* *
* @return string * @return string
*/ */
function asActivityNoun($element) public function asActivityNoun($element)
{ {
$noun = $this->asActivityObject(); $noun = $this->asActivityObject();
return $noun->asString('activity:' . $element); return $noun->asString('activity:' . $element);
@ -1619,7 +1648,7 @@ class Profile extends Managed_DataObject
return $scheme ? $acct : mb_substr($acct, 5); return $scheme ? $acct : mb_substr($acct, 5);
} }
function hasBlocked(Profile $other) public function hasBlocked(Profile $other)
{ {
$block = Profile_block::exists($this, $other); $block = Profile_block::exists($this, $other);
return !empty($block); return !empty($block);
@ -1652,7 +1681,7 @@ class Profile extends Managed_DataObject
* *
* @param string $uri A unique identifier for a resource (profile/group/whatever) * @param string $uri A unique identifier for a resource (profile/group/whatever)
*/ */
static function fromUri($uri) public static function fromUri($uri)
{ {
$profile = null; $profile = null;
@ -1677,7 +1706,7 @@ class Profile extends Managed_DataObject
return $profile; return $profile;
} }
function canRead(Notice $notice) public function canRead(Notice $notice)
{ {
if ($notice->scope & Notice::SITE_SCOPE) { if ($notice->scope & Notice::SITE_SCOPE) {
$user = $this->getUser(); $user = $this->getUser();
@ -1717,7 +1746,7 @@ class Profile extends Managed_DataObject
return true; return true;
} }
static function current() public static function current()
{ {
$user = common_current_user(); $user = common_current_user();
if (empty($user)) { if (empty($user)) {
@ -1728,7 +1757,7 @@ class Profile extends Managed_DataObject
return $profile; return $profile;
} }
static function ensureCurrent() public static function ensureCurrent()
{ {
$profile = self::current(); $profile = self::current();
if (!$profile instanceof Profile) { if (!$profile instanceof Profile) {
@ -1747,7 +1776,7 @@ class Profile extends Managed_DataObject
* @return array of variable names to include in serialization. * @return array of variable names to include in serialization.
*/ */
function __sleep() public function __sleep()
{ {
$vars = parent::__sleep(); $vars = parent::__sleep();
$skip = array('_user', '_group'); $skip = array('_user', '_group');
@ -1802,11 +1831,13 @@ class Profile extends Managed_DataObject
return !is_null($private_stream) && $private_stream; return !is_null($private_stream) && $private_stream;
} }
public function delPref($namespace, $topic) { public function delPref($namespace, $topic)
{
return Profile_prefs::setData($this, $namespace, $topic, null); return Profile_prefs::setData($this, $namespace, $topic, null);
} }
public function getPref($namespace, $topic, $default=null) { public function getPref($namespace, $topic, $default = null)
{
// If you want an exception to be thrown, call Profile_prefs::getData directly // If you want an exception to be thrown, call Profile_prefs::getData directly
try { try {
return Profile_prefs::getData($this, $namespace, $topic, $default); return Profile_prefs::getData($this, $namespace, $topic, $default);
@ -1821,7 +1852,8 @@ class Profile extends Managed_DataObject
return Profile_prefs::getConfigData($this, $namespace, $topic); return Profile_prefs::getConfigData($this, $namespace, $topic);
} }
public function setPref($namespace, $topic, $data) { public function setPref($namespace, $topic, $data)
{
return Profile_prefs::setData($this, $namespace, $topic, $data); return Profile_prefs::setData($this, $namespace, $topic, $data);
} }

View File

@ -1,27 +1,28 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
*
* 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 Notices * @category Notices
* @package StatusNet * @package GNUsocial
* @author Shashi Gowda <connect2shashi@gmail.com> * @author Shashi Gowda <connect2shashi@gmail.com>
* @license GNU Affero General Public License http://www.gnu.org/licenses/ * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
class Profile_list extends Managed_DataObject class Profile_list extends Managed_DataObject
{ {
@ -30,7 +31,7 @@ class Profile_list extends Managed_DataObject
public $tagger; // int(4) public $tagger; // int(4)
public $tag; // varchar(64) public $tag; // varchar(64)
public $description; // text public $description; // text
public $private; // tinyint(1) public $private; // bool default_false
public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00 public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00
public $modified; // datetime() not_null default_CURRENT_TIMESTAMP public $modified; // datetime() not_null default_CURRENT_TIMESTAMP
public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
@ -46,7 +47,7 @@ class Profile_list extends Managed_DataObject
'tagger' => array('type' => 'int', 'not null' => true, 'description' => 'user making the tag'), 'tagger' => array('type' => 'int', 'not null' => true, 'description' => 'user making the tag'),
'tag' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'people tag'), 'tag' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'people tag'),
'description' => array('type' => 'text', 'description' => 'description of the people tag'), 'description' => array('type' => 'text', 'description' => 'description of the people tag'),
'private' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'is this tag private'), 'private' => array('type' => 'bool', 'default' => false, 'description' => 'is this tag private'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date the tag was added'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date the tag was added'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date the tag was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date the tag was modified'),
@ -58,7 +59,8 @@ class Profile_list extends Managed_DataObject
), ),
'primary key' => array('tagger', 'tag'), 'primary key' => array('tagger', 'tag'),
'unique keys' => array( 'unique keys' => array(
'profile_list_id_key' => array('id') 'profile_list_id_key' => array('id'),
'profile_list_tag_key' => array('tag'),
), ),
'foreign keys' => array( 'foreign keys' => array(
'profile_list_tagger_fkey' => array('profile', array('tagger' => 'id')), 'profile_list_tagger_fkey' => array('profile', array('tagger' => 'id')),
@ -79,7 +81,7 @@ class Profile_list extends Managed_DataObject
* @return Profile the tagger * @return Profile the tagger
*/ */
function getTagger() public function getTagger()
{ {
return Profile::getByID($this->tagger); return Profile::getByID($this->tagger);
} }
@ -91,7 +93,7 @@ class Profile_list extends Managed_DataObject
* @return String * @return String
*/ */
function getBestName() public function getBestName()
{ {
return $this->tag; return $this->tag;
} }
@ -102,15 +104,17 @@ class Profile_list extends Managed_DataObject
* @return String uri * @return String uri
*/ */
function getUri() public function getUri()
{ {
$uri = null; $uri = null;
if (Event::handle('StartProfiletagGetUri', array($this, &$uri))) { if (Event::handle('StartProfiletagGetUri', array($this, &$uri))) {
if (!empty($this->uri)) { if (!empty($this->uri)) {
$uri = $this->uri; $uri = $this->uri;
} else { } else {
$uri = common_local_url('profiletagbyid', $uri = common_local_url(
array('id' => $this->id, 'tagger_id' => $this->tagger)); 'profiletagbyid',
['id' => $this->id, 'tagger_id' => $this->tagger]
);
} }
} }
Event::handle('EndProfiletagGetUri', array($this, &$uri)); Event::handle('EndProfiletagGetUri', array($this, &$uri));
@ -123,7 +127,7 @@ class Profile_list extends Managed_DataObject
* @return String home url * @return String home url
*/ */
function homeUrl() public function homeUrl()
{ {
$url = null; $url = null;
if (Event::handle('StartUserPeopletagHomeUrl', array($this, &$url))) { if (Event::handle('StartUserPeopletagHomeUrl', array($this, &$url))) {
@ -131,9 +135,13 @@ class Profile_list extends Managed_DataObject
if (!empty($this->mainpage)) { if (!empty($this->mainpage)) {
$url = $this->mainpage; $url = $this->mainpage;
} else { } else {
$url = common_local_url('showprofiletag', $url = common_local_url(
array('nickname' => $this->getTagger()->nickname, 'showprofiletag',
'tag' => $this->tag)); [
'nickname' => $this->getTagger()->nickname,
'tag' => $this->tag,
]
);
} }
} }
Event::handle('EndUserPeopletagHomeUrl', array($this, &$url)); Event::handle('EndUserPeopletagHomeUrl', array($this, &$url));
@ -146,12 +154,14 @@ class Profile_list extends Managed_DataObject
* @return String permalink * @return String permalink
*/ */
function permalink() public function permalink()
{ {
$url = null; $url = null;
if (Event::handle('StartProfiletagPermalink', array($this, &$url))) { if (Event::handle('StartProfiletagPermalink', array($this, &$url))) {
$url = common_local_url('profiletagbyid', $url = common_local_url(
array('id' => $this->id)); 'profiletagbyid',
['id' => $this->id]
);
} }
Event::handle('EndProfiletagPermalink', array($this, &$url)); Event::handle('EndProfiletagPermalink', array($this, &$url));
return $url; return $url;
@ -169,7 +179,7 @@ class Profile_list extends Managed_DataObject
* @return Notice the query * @return Notice the query
*/ */
function getNotices($offset, $limit, $since_id=null, $max_id=null) public function getNotices($offset, $limit, $since_id = null, $max_id = null)
{ {
// FIXME: Use something else than Profile::current() to avoid // FIXME: Use something else than Profile::current() to avoid
// possible confusion between session user and queue processing. // possible confusion between session user and queue processing.
@ -190,7 +200,7 @@ class Profile_list extends Managed_DataObject
* @return Profile results * @return Profile results
*/ */
function getSubscribers($offset=0, $limit=null, $since=0, $upto=0) public function getSubscribers(int $offset = 0, ?int $limit = null, int $since = 0, int $upto = 0)
{ {
$subs = new Profile(); $subs = new Profile();
@ -199,8 +209,15 @@ class Profile_list extends Managed_DataObject
); );
$subs->whereAdd('profile_tag_subscription.profile_tag_id = ' . $this->id); $subs->whereAdd('profile_tag_subscription.profile_tag_id = ' . $this->id);
$subs->selectAdd('unix_timestamp(profile_tag_subscription.' . if (common_config('db', 'type') !== 'mysql') {
'created) as "cursor"'); $subs->selectAdd(sprintf(
'((EXTRACT(DAY %1$s) * 24 + EXTRACT(HOUR %1$s)) * 60 + ' .
'EXTRACT(MINUTE %1$s)) * 60 + FLOOR(EXTRACT(SECOND %1$s)) AS "cursor"',
"FROM (profile_tag_subscription.created - TIMESTAMP '1970-01-01 00:00:00')"
));
} else {
$subs->selectAdd("timestampdiff(SECOND, '1970-01-01', profile_tag_subscription.created) AS `cursor`");
}
if ($since != 0) { if ($since != 0) {
$subs->whereAdd('cursor > ' . $since); $subs->whereAdd('cursor > ' . $since);
@ -227,24 +244,22 @@ class Profile_list extends Managed_DataObject
* @return array ids of users * @return array ids of users
*/ */
function getUserSubscribers() public function getUserSubscribers()
{ {
// XXX: cache this // XXX: cache this
$user = new User(); $user = new User();
if(common_config('db','quote_identifiers'))
$user_table = '"user"';
else $user_table = 'user';
$qry = $user->query(sprintf(
'SELECT id ' . 'SELECT id ' .
'FROM '. $user_table .' JOIN profile_tag_subscription '. 'FROM %1$s INNER JOIN profile_tag_subscription ' .
'ON '. $user_table .'.id = profile_tag_subscription.profile_id ' . 'ON %1$s.id = profile_tag_subscription.profile_id ' .
'WHERE profile_tag_subscription.profile_tag_id = %d '; 'WHERE profile_tag_subscription.profile_tag_id = %2$d ',
$user->escapedTableName(),
$this->id
));
$user->query(sprintf($qry, $this->id)); $ids = [];
$ids = array();
while ($user->fetch()) { while ($user->fetch()) {
$ids[] = $user->id; $ids[] = $user->id;
@ -264,7 +279,7 @@ class Profile_list extends Managed_DataObject
* @return boolean subscription status * @return boolean subscription status
*/ */
function hasSubscriber($id) public function hasSubscriber($id)
{ {
if (!is_numeric($id)) { if (!is_numeric($id)) {
$id = $id->id; $id = $id->id;
@ -288,13 +303,21 @@ class Profile_list extends Managed_DataObject
* @return Profile results * @return Profile results
*/ */
function getTagged($offset=0, $limit=null, $since=0, $upto=0) public function getTagged(int $offset = 0, ?int $limit = null, int $since = 0, int $upto = 0)
{ {
$tagged = new Profile(); $tagged = new Profile();
$tagged->joinAdd(array('id', 'profile_tag:tagged')); $tagged->joinAdd(['id', 'profile_tag:tagged']);
if (common_config('db', 'type') !== 'mysql') {
$tagged->selectAdd(sprintf(
'((EXTRACT(DAY %1$s) * 24 + EXTRACT(HOUR %1$s)) * 60 + ' .
'EXTRACT(MINUTE %1$s)) * 60 + FLOOR(EXTRACT(SECOND %1$s)) AS "cursor"',
"FROM (profile_tag.modified - TIMESTAMP '1970-01-01 00:00:00')"
));
} else {
$tagged->selectAdd("timestampdiff(SECOND, '1970-01-01', profile_tag.modified) AS `cursor`");
}
#@fixme: postgres
$tagged->selectAdd('unix_timestamp(profile_tag.modified) as "cursor"');
$tagged->whereAdd('profile_tag.tagger = '.$this->tagger); $tagged->whereAdd('profile_tag.tagger = '.$this->tagger);
$tagged->whereAdd("profile_tag.tag = '{$this->tag}'"); $tagged->whereAdd("profile_tag.tag = '{$this->tag}'");
@ -323,7 +346,7 @@ class Profile_list extends Managed_DataObject
* @return boolean success * @return boolean success
*/ */
function delete($useWhere=false) public function delete($useWhere = false)
{ {
// force delete one item at a time. // force delete one item at a time.
if (empty($this->id)) { if (empty($this->id)) {
@ -350,7 +373,7 @@ class Profile_list extends Managed_DataObject
* @return boolean success * @return boolean success
*/ */
function update($dataObject=false) public function update($dataObject = false)
{ {
if (!is_object($dataObject) && !$dataObject instanceof Profile_list) { if (!is_object($dataObject) && !$dataObject instanceof Profile_list) {
return parent::update($dataObject); return parent::update($dataObject);
@ -361,9 +384,9 @@ class Profile_list extends Managed_DataObject
// if original tag was different // if original tag was different
// check to see if the new tag already exists // check to see if the new tag already exists
// if not, rename the tag correctly // if not, rename the tag correctly
if($dataObject->tag != $this->tag || $dataObject->tagger != $this->tagger) { if ($dataObject->tag != $this->tag || $dataObject->tagger != $this->tagger) {
$existing = Profile_list::getByTaggerAndTag($this->tagger, $this->tag); $existing = Profile_list::getByTaggerAndTag($this->tagger, $this->tag);
if(!empty($existing)) { if (!empty($existing)) {
// TRANS: Server exception. // TRANS: Server exception.
throw new ServerException(_('The tag you are trying to rename ' . throw new ServerException(_('The tag you are trying to rename ' .
'to already exists.')); 'to already exists.'));
@ -382,7 +405,7 @@ class Profile_list extends Managed_DataObject
* @return string atom author element * @return string atom author element
*/ */
function asAtomAuthor() public function asAtomAuthor()
{ {
$xs = new XMLStringer(true); $xs = new XMLStringer(true);
@ -404,7 +427,7 @@ class Profile_list extends Managed_DataObject
* @return string activitystreams noun * @return string activitystreams noun
*/ */
function asActivityNoun($element) public function asActivityNoun($element)
{ {
$noun = ActivityObject::fromPeopletag($this); $noun = ActivityObject::fromPeopletag($this);
return $noun->asString('activity:' . $element); return $noun->asString('activity:' . $element);
@ -419,11 +442,13 @@ class Profile_list extends Managed_DataObject
* @return integer count * @return integer count
*/ */
function taggedCount($recount=false) public function taggedCount($recount = false)
{ {
$keypart = sprintf('profile_list:tagged_count:%d:%s', $keypart = sprintf(
'profile_list:tagged_count:%d:%s',
$this->tagger, $this->tagger,
$this->tag); $this->tag
);
$count = self::cacheGet($keypart); $count = self::cacheGet($keypart);
@ -450,15 +475,16 @@ class Profile_list extends Managed_DataObject
* @return integer count * @return integer count
*/ */
function subscriberCount($recount=false) public function subscriberCount($recount = false)
{ {
$keypart = sprintf('profile_list:subscriber_count:%d', $keypart = sprintf(
$this->id); 'profile_list:subscriber_count:%d',
$this->id
);
$count = self::cacheGet($keypart); $count = self::cacheGet($keypart);
if ($count === false) { if ($count === false) {
$sub = new Profile_tag_subscription(); $sub = new Profile_tag_subscription();
$sub->profile_tag_id = $this->id; $sub->profile_tag_id = $this->id;
$count = (int) $sub->count('distinct profile_id'); $count = (int) $sub->count('distinct profile_id');
@ -478,7 +504,7 @@ class Profile_list extends Managed_DataObject
* @return integer count * @return integer count
*/ */
function blowNoticeStreamCache($all=false) public function blowNoticeStreamCache($all = false)
{ {
self::blow('profile_list:notice_ids:%d', $this->id); self::blow('profile_list:notice_ids:%d', $this->id);
if ($all) { if ($all) {
@ -496,7 +522,7 @@ class Profile_list extends Managed_DataObject
* @return integer count * @return integer count
*/ */
static function getByTaggerAndTag($tagger, $tag) public static function getByTaggerAndTag($tagger, $tag)
{ {
$ptag = Profile_list::pkeyGet(array('tagger' => $tagger, 'tag' => $tag)); $ptag = Profile_list::pkeyGet(array('tagger' => $tagger, 'tag' => $tag));
return $ptag; return $ptag;
@ -514,11 +540,11 @@ class Profile_list extends Managed_DataObject
* @return Profile_list the people tag object * @return Profile_list the people tag object
*/ */
static function ensureTag($tagger, $tag, $description=null, $private=false) public static function ensureTag($tagger, $tag, $description = null, $private = false)
{ {
$ptag = Profile_list::getByTaggerAndTag($tagger, $tag); $ptag = Profile_list::getByTaggerAndTag($tagger, $tag);
if(empty($ptag->id)) { if (empty($ptag->id)) {
$args = array( $args = array(
'tag' => $tag, 'tag' => $tag,
'tagger' => $tagger, 'tagger' => $tagger,
@ -544,7 +570,7 @@ class Profile_list extends Managed_DataObject
* @return integer maximum number of characters * @return integer maximum number of characters
*/ */
static function maxDescription() public static function maxDescription()
{ {
$desclimit = common_config('peopletag', 'desclimit'); $desclimit = common_config('peopletag', 'desclimit');
// null => use global limit (distinct from 0!) // null => use global limit (distinct from 0!)
@ -563,7 +589,7 @@ class Profile_list extends Managed_DataObject
* @return boolean is the descripition too long? * @return boolean is the descripition too long?
*/ */
static function descriptionTooLong($desc) public static function descriptionTooLong($desc)
{ {
$desclimit = self::maxDescription(); $desclimit = self::maxDescription();
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit)); return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
@ -578,7 +604,8 @@ class Profile_list extends Managed_DataObject
* *
* @return mixed Profile_list on success, false on fail * @return mixed Profile_list on success, false on fail
*/ */
static function saveNew(array $fields) { public static function saveNew(array $fields)
{
extract($fields); extract($fields);
$ptag = new Profile_list(); $ptag = new Profile_list();
@ -647,7 +674,7 @@ class Profile_list extends Managed_DataObject
if (!isset($mainpage) || empty($mainpage)) { if (!isset($mainpage) || empty($mainpage)) {
$orig = clone($ptag); $orig = clone($ptag);
$user = User::getKV('id', $ptag->tagger); $user = User::getKV('id', $ptag->tagger);
if(!empty($user)) { if (!empty($user)) {
$ptag->mainpage = common_local_url('showprofiletag', array('tag' => $ptag->tag, 'nickname' => $user->getNickname())); $ptag->mainpage = common_local_url('showprofiletag', array('tag' => $ptag->tag, 'nickname' => $user->getNickname()));
} else { } else {
$ptag->mainpage = $uri; // assume this is a remote peopletag and the uri works $ptag->mainpage = $uri; // assume this is a remote peopletag and the uri works
@ -687,9 +714,9 @@ class Profile_list extends Managed_DataObject
* @returns array (array (mixed items), int next_cursor, int previous_cursor) * @returns array (array (mixed items), int next_cursor, int previous_cursor)
*/ */
// XXX: This should be in Memcached_DataObject... eventually. // XXX: This should be in Memcached_DataObject... eventually
static function getAtCursor($fn, array $args, $cursor, $count=20) public static function getAtCursor($fn, array $args, $cursor, $count = 20)
{ {
$items = array(); $items = array();
@ -698,12 +725,12 @@ class Profile_list extends Managed_DataObject
$next_cursor = 0; $next_cursor = 0;
$prev_cursor = 0; $prev_cursor = 0;
if($cursor > 0) { if ($cursor > 0) {
// if cursor is +ve fetch $count+2 items before cursor starting at cursor // if cursor is +ve fetch $count+2 items before cursor starting at cursor
$max_id = $cursor; $max_id = $cursor;
$fn_args = array_merge($args, array(0, $count+2, 0, $max_id)); $fn_args = array_merge($args, array(0, $count+2, 0, $max_id));
$list = call_user_func_array($fn, $fn_args); $list = call_user_func_array($fn, $fn_args);
while($list->fetch()) { while ($list->fetch()) {
$items[] = clone($list); $items[] = clone($list);
} }
@ -734,15 +761,14 @@ class Profile_list extends Managed_DataObject
$next_cursor = isset($next->cursor) ? $next_cursor = isset($next->cursor) ?
$items[$count-1]->cursor : $items[$count-1]->id; $items[$count-1]->cursor : $items[$count-1]->id;
} }
} elseif ($cursor < -1) {
} else if($cursor < -1) {
// if cursor is -ve fetch $count+2 items created after -$cursor-1 // if cursor is -ve fetch $count+2 items created after -$cursor-1
$cursor = abs($cursor); $cursor = abs($cursor);
$since_id = $cursor-1; $since_id = $cursor-1;
$fn_args = array_merge($args, array(0, $count+2, $since_id)); $fn_args = array_merge($args, array(0, $count+2, $since_id));
$list = call_user_func_array($fn, $fn_args); $list = call_user_func_array($fn, $fn_args);
while($list->fetch()) { while ($list->fetch()) {
$items[] = clone($list); $items[] = clone($list);
} }
@ -755,7 +781,10 @@ class Profile_list extends Managed_DataObject
} else { } else {
$next_cursor = isset($items[$end]->cursor) ? $next_cursor = isset($items[$end]->cursor) ?
$items[$end]->cursor : $items[$end]->id; $items[$end]->cursor : $items[$end]->id;
if ($end > $count) array_pop($items); // excess item. if ($end > $count) {
// excess item
array_pop($items);
}
// check if there are more items for next page // check if there are more items for next page
$fn_args = array_merge($args, array(0, 1, 0, $cursor)); $fn_args = array_merge($args, array(0, 1, 0, $cursor));
@ -771,23 +800,22 @@ class Profile_list extends Managed_DataObject
$prev_cursor = isset($prev->cursor) ? $prev_cursor = isset($prev->cursor) ?
-$items[0]->cursor : -$items[0]->id; -$items[0]->cursor : -$items[0]->id;
} }
} else if($cursor == -1) { } elseif ($cursor == -1) {
$fn_args = array_merge($args, array(0, $count+1)); $fn_args = array_merge($args, array(0, $count+1));
$list = call_user_func_array($fn, $fn_args); $list = call_user_func_array($fn, $fn_args);
while($list->fetch()) { while ($list->fetch()) {
$items[] = clone($list); $items[] = clone($list);
} }
if (count($items)==$count+1) { if (count($items)==$count+1) {
$next = array_pop($items); $next = array_pop($items);
if(isset($next->cursor)) { if (isset($next->cursor)) {
$next_cursor = $items[$count-1]->cursor; $next_cursor = $items[$count-1]->cursor;
} else { } else {
$next_cursor = $items[$count-1]->id; $next_cursor = $items[$count-1]->id;
} }
} }
} }
return array($items, $next_cursor, $prev_cursor); return array($items, $next_cursor, $prev_cursor);
} }
@ -803,7 +831,8 @@ class Profile_list extends Managed_DataObject
* @return boolean success * @return boolean success
*/ */
static function setCache($ckey, &$tag, $offset=0, $limit=null) { public static function setCache($ckey, &$tag, $offset = 0, $limit = null)
{
$cache = Cache::instance(); $cache = Cache::instance();
if (empty($cache)) { if (empty($cache)) {
return false; return false;
@ -834,8 +863,8 @@ class Profile_list extends Managed_DataObject
* @return Profile_list results * @return Profile_list results
*/ */
static function getCached($ckey, $offset=0, $limit=null) { public static function getCached($ckey, $offset = 0, $limit = null)
{
$keys_str = self::cacheGet($ckey); $keys_str = self::cacheGet($ckey);
if ($keys_str === false) { if ($keys_str === false) {
return false; return false;
@ -862,7 +891,8 @@ class Profile_list extends Managed_DataObject
* @return Profile_list results * @return Profile_list results
*/ */
static function getByKeys(array $keys) { public static function getByKeys(array $keys)
{
$cache = Cache::instance(); $cache = Cache::instance();
if (!empty($cache)) { if (!empty($cache)) {
@ -910,7 +940,7 @@ class Profile_list extends Managed_DataObject
} }
} }
function insert() public function insert()
{ {
$result = parent::insert(); $result = parent::insert();
if ($result) { if ($result) {

View File

@ -1,32 +1,31 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Data class for Profile preferences * Data class for Profile preferences
* *
* 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 Data * @category Data
* @package GNUsocial * @package GNUsocial
* @author Mikael Nordfeldth <mmn@hethane.se> * @author Mikael Nordfeldth <mmn@hethane.se>
* @copyright 2013 Free Software Foundation, Inc. * @copyright 2013 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://www.gnu.org/software/social/
*/ */
defined('GNUSOCIAL') || die();
class Profile_prefs extends Managed_DataObject class Profile_prefs extends Managed_DataObject
{ {
public $__table = 'profile_prefs'; // table name public $__table = 'profile_prefs'; // table name
@ -58,7 +57,7 @@ class Profile_prefs extends Managed_DataObject
); );
} }
static function getNamespacePrefs(Profile $profile, $namespace, array $topic=array()) public static function getNamespacePrefs(Profile $profile, $namespace, array $topic = [])
{ {
if (empty($topic)) { if (empty($topic)) {
$prefs = new Profile_prefs(); $prefs = new Profile_prefs();
@ -76,13 +75,13 @@ class Profile_prefs extends Managed_DataObject
return $prefs; return $prefs;
} }
static function getNamespace(Profile $profile, $namespace, array $topic=array()) public static function getNamespace(Profile $profile, $namespace, array $topic = [])
{ {
$prefs = self::getNamespacePrefs($profile, $namespace, $topic); $prefs = self::getNamespacePrefs($profile, $namespace, $topic);
return $prefs->fetchAll(); return $prefs->fetchAll();
} }
static function getAll(Profile $profile) public static function getAll(Profile $profile)
{ {
try { try {
$prefs = self::listFind('profile_id', array($profile->getID())); $prefs = self::listFind('profile_id', array($profile->getID()));
@ -100,13 +99,15 @@ class Profile_prefs extends Managed_DataObject
return $list; return $list;
} }
static function getTopic(Profile $profile, $namespace, $topic) { public static function getTopic(Profile $profile, $namespace, $topic)
{
return Profile_prefs::getByPK(array('profile_id' => $profile->getID(), return Profile_prefs::getByPK(array('profile_id' => $profile->getID(),
'namespace' => $namespace, 'namespace' => $namespace,
'topic' => $topic)); 'topic' => $topic));
} }
static function getData(Profile $profile, $namespace, $topic, $def=null) { public static function getData(Profile $profile, $namespace, $topic, $def = null)
{
try { try {
$pref = self::getTopic($profile, $namespace, $topic); $pref = self::getTopic($profile, $namespace, $topic);
} catch (NoResultException $e) { } catch (NoResultException $e) {
@ -120,7 +121,8 @@ class Profile_prefs extends Managed_DataObject
return $pref->data; return $pref->data;
} }
static function getConfigData(Profile $profile, $namespace, $topic) { public static function getConfigData(Profile $profile, $namespace, $topic)
{
try { try {
$data = self::getData($profile, $namespace, $topic); $data = self::getData($profile, $namespace, $topic);
} catch (NoResultException $e) { } catch (NoResultException $e) {
@ -140,14 +142,15 @@ class Profile_prefs extends Managed_DataObject
* @return true if changes are made, false if no action taken * @return true if changes are made, false if no action taken
* @throws ServerException if preference could not be saved * @throws ServerException if preference could not be saved
*/ */
static function setData(Profile $profile, $namespace, $topic, $data=null) { public static function setData(Profile $profile, $namespace, $topic, $data = null)
{
try { try {
$pref = self::getTopic($profile, $namespace, $topic); $pref = self::getTopic($profile, $namespace, $topic);
if (is_null($data)) { if (is_null($data)) {
$pref->delete(); $pref->delete();
} else { } else {
$orig = clone($pref); $orig = clone($pref);
$pref->data = $data; $pref->data = DB_DataObject_Cast::blob($data);
$pref->update($orig); $pref->update($orig);
} }
return true; return true;
@ -161,7 +164,7 @@ class Profile_prefs extends Managed_DataObject
$pref->profile_id = $profile->getID(); $pref->profile_id = $profile->getID();
$pref->namespace = $namespace; $pref->namespace = $namespace;
$pref->topic = $topic; $pref->topic = $topic;
$pref->data = $data; $pref->data = DB_DataObject_Cast::blob($data);
$pref->created = common_sql_now(); $pref->created = common_sql_now();
if ($pref->insert() === false) { if ($pref->insert() === false) {

View File

@ -1,8 +1,24 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
/** /**
* Table Definition for profile_tag * Table Definition for profile_tag
*/ */
class Profile_tag extends Managed_DataObject class Profile_tag extends Managed_DataObject
{ {
public $__table = 'profile_tag'; // table name public $__table = 'profile_tag'; // table name
@ -35,35 +51,34 @@ class Profile_tag extends Managed_DataObject
); );
} }
function links() public function links()
{ {
return array('tagger,tag' => 'profile_list:tagger,tag'); return array('tagger,tag' => 'profile_list:tagger,tag');
} }
function getMeta() public function getMeta()
{ {
return Profile_list::pkeyGet(array('tagger' => $this->tagger, 'tag' => $this->tag)); return Profile_list::pkeyGet(array('tagger' => $this->tagger, 'tag' => $this->tag));
} }
static function getSelfTagsArray(Profile $target) public static function getSelfTagsArray(Profile $target)
{ {
return self::getTagsArray($target->getID(), $target->getID(), $target); return self::getTagsArray($target->getID(), $target->getID(), $target);
} }
static function setSelfTags(Profile $target, array $newtags, array $privacy=array()) public static function setSelfTags(Profile $target, array $newtags, array $privacy = [])
{ {
return self::setTags($target->getID(), $target->getID(), $newtags, $privacy); return self::setTags($target->getID(), $target->getID(), $newtags, $privacy);
} }
static function getTags($tagger, $tagged, $auth_user=null) { public static function getTags($tagger, $tagged, $auth_user = null)
{
$profile_list = new Profile_list(); $profile_list = new Profile_list();
$include_priv = 1; $include_priv = 1;
if (!($auth_user instanceof User || if (!($auth_user instanceof User ||
$auth_user instanceof Profile) || $auth_user instanceof Profile) ||
($auth_user->id !== $tagger)) { ($auth_user->id !== $tagger)) {
$profile_list->private = false; $profile_list->private = false;
$include_priv = 0; $include_priv = 0;
} }
@ -81,7 +96,7 @@ class Profile_tag extends Managed_DataObject
$qry = sprintf($qry, $tagger, $tagged); $qry = sprintf($qry, $tagger, $tagged);
if (!$include_priv) { if (!$include_priv) {
$qry .= ' and profile_list.private = 0'; $qry .= ' AND profile_list.private = FALSE';
} }
$profile_list->query($qry); $profile_list->query($qry);
@ -91,20 +106,23 @@ class Profile_tag extends Managed_DataObject
return $profile_list; return $profile_list;
} }
static function getTagsArray($tagger, $tagged, Profile $scoped=null) public static function getTagsArray($tagger, $tagged, Profile $scoped = null)
{ {
$ptag = new Profile_tag(); $ptag = new Profile_tag();
$qry = sprintf('select profile_tag.tag '. $qry = sprintf(
'from profile_tag join profile_list '. 'SELECT profile_tag.tag '.
' on (profile_tag.tagger = profile_list.tagger ' . 'FROM profile_tag INNER JOIN profile_list '.
' ON (profile_tag.tagger = profile_list.tagger ' .
' and profile_tag.tag = profile_list.tag) ' . ' and profile_tag.tag = profile_list.tag) ' .
'where profile_tag.tagger = %d ' . 'WHERE profile_tag.tagger = %d ' .
'and profile_tag.tagged = %d ', 'AND profile_tag.tagged = %d ',
$tagger, $tagged); $tagger,
$tagged
);
if (!$scoped instanceof Profile || $scoped->getID() !== $tagger) { if (!$scoped instanceof Profile || $scoped->getID() !== $tagger) {
$qry .= 'and profile_list.private = 0'; $qry .= 'AND profile_list.private = FALSE';
} }
$tags = array(); $tags = array();
@ -118,8 +136,8 @@ class Profile_tag extends Managed_DataObject
return $tags; return $tags;
} }
static function setTags($tagger, $tagged, array $newtags, array $privacy=array()) { public static function setTags($tagger, $tagged, array $newtags, array $privacy = [])
{
$newtags = array_unique($newtags); $newtags = array_unique($newtags);
$oldtags = self::getTagsArray($tagger, $tagged, Profile::getByID($tagger)); $oldtags = self::getTagsArray($tagger, $tagged, Profile::getByID($tagger));
@ -145,8 +163,8 @@ class Profile_tag extends Managed_DataObject
} }
# set a single tag # set a single tag
static function setTag($tagger, $tagged, $tag, $desc=null, $private=false) { public static function setTag($tagger, $tagged, $tag, $desc=null, $private = false)
{
$ptag = Profile_tag::pkeyGet(array('tagger' => $tagger, $ptag = Profile_tag::pkeyGet(array('tagger' => $tagger,
'tagged' => $tagged, 'tagged' => $tagged,
'tag' => $tag)); 'tag' => $tag));
@ -160,7 +178,6 @@ class Profile_tag extends Managed_DataObject
$tagged_profile = Profile::getByID($tagged); $tagged_profile = Profile::getByID($tagged);
if (Event::handle('StartTagProfile', array($tagger_profile, $tagged_profile, $tag))) { if (Event::handle('StartTagProfile', array($tagger_profile, $tagged_profile, $tag))) {
if (!$tagger_profile->canTag($tagged_profile)) { if (!$tagger_profile->canTag($tagged_profile)) {
// TRANS: Client exception thrown trying to set a tag for a user that cannot be tagged. // TRANS: Client exception thrown trying to set a tag for a user that cannot be tagged.
throw new ClientException(_('You cannot tag this user.')); throw new ClientException(_('You cannot tag this user.'));
@ -172,10 +189,12 @@ class Profile_tag extends Managed_DataObject
if ($count >= common_config('peopletag', 'maxtags')) { if ($count >= common_config('peopletag', 'maxtags')) {
// TRANS: Client exception thrown trying to set more tags than allowed. // TRANS: Client exception thrown trying to set more tags than allowed.
throw new ClientException(sprintf(_('You already have created %d or more tags ' . throw new ClientException(sprintf(
_('You already have created %d or more tags ' .
'which is the maximum allowed number of tags. ' . 'which is the maximum allowed number of tags. ' .
'Try using or deleting some existing tags.'), 'Try using or deleting some existing tags.'),
common_config('peopletag', 'maxtags'))); common_config('peopletag', 'maxtags')
));
} }
$plist = new Profile_list(); $plist = new Profile_list();
@ -185,10 +204,13 @@ class Profile_tag extends Managed_DataObject
if ($profile_list->taggedCount() >= common_config('peopletag', 'maxpeople')) { if ($profile_list->taggedCount() >= common_config('peopletag', 'maxpeople')) {
// TRANS: Client exception thrown when trying to add more people than allowed to a list. // TRANS: Client exception thrown when trying to add more people than allowed to a list.
throw new ClientException(sprintf(_('You already have %1$d or more people in list %2$s, ' . throw new ClientException(sprintf(
_('You already have %1$d or more people in list %2$s, ' .
'which is the maximum allowed number. ' . 'which is the maximum allowed number. ' .
'Try unlisting others first.'), 'Try unlisting others first.'),
common_config('peopletag', 'maxpeople'), $tag)); common_config('peopletag', 'maxpeople'),
$tag
));
} }
$newtag = new Profile_tag(); $newtag = new Profile_tag();
@ -221,7 +243,8 @@ class Profile_tag extends Managed_DataObject
return $newtag; return $newtag;
} }
static function unTag($tagger, $tagged, $tag) { public static function unTag($tagger, $tagged, $tag)
{
$ptag = Profile_tag::pkeyGet(array('tagger' => $tagger, $ptag = Profile_tag::pkeyGet(array('tagger' => $tagger,
'tagged' => $tagged, 'tagged' => $tagged,
'tag' => $tag)); 'tag' => $tag));
@ -247,13 +270,14 @@ class Profile_tag extends Managed_DataObject
} }
// @fixme: move this to Profile_list? // @fixme: move this to Profile_list?
static function cleanup($profile_list) { public static function cleanup($profile_list)
{
$ptag = new Profile_tag(); $ptag = new Profile_tag();
$ptag->tagger = $profile_list->tagger; $ptag->tagger = $profile_list->tagger;
$ptag->tag = $profile_list->tag; $ptag->tag = $profile_list->tag;
$ptag->find(); $ptag->find();
while($ptag->fetch()) { while ($ptag->fetch()) {
if (Event::handle('StartUntagProfile', array($ptag))) { if (Event::handle('StartUntagProfile', array($ptag))) {
$orig = clone($ptag); $orig = clone($ptag);
$result = $ptag->delete(); $result = $ptag->delete();
@ -266,17 +290,18 @@ class Profile_tag extends Managed_DataObject
} }
// move a tag! // move a tag!
static function moveTag($orig, $new) { public static function moveTag($orig, $new)
{
$tags = new Profile_tag(); $tags = new Profile_tag();
$qry = 'UPDATE profile_tag SET ' . $qry = "UPDATE profile_tag SET tag = '%s', tagger = '%s' " .
'tag = "%s", tagger = "%s" ' . "WHERE tag = '%s' AND tagger = '%s'";
'WHERE tag = "%s" ' . $result = $tags->query(sprintf(
'AND tagger = "%s"'; $qry,
$result = $tags->query(sprintf($qry,
$tags->escape($new->tag), $tags->escape($new->tag),
$tags->escape($new->tagger), $tags->escape($new->tagger),
$tags->escape($orig->tag), $tags->escape($orig->tag),
$tags->escape($orig->tagger))); $tags->escape($orig->tagger)
));
if ($result === false) { if ($result === false) {
common_log_db_error($tags, 'UPDATE', __FILE__); common_log_db_error($tags, 'UPDATE', __FILE__);
@ -285,7 +310,8 @@ class Profile_tag extends Managed_DataObject
return $result; return $result;
} }
static function blowCaches($tagger, $tagged) { public static function blowCaches($tagger, $tagged)
{
foreach (array(0, 1) as $perm) { foreach (array(0, 1) as $perm) {
self::blow(sprintf('profile_tag:tagger_tagged_privacy:%d-%d-%d', $tagger, $tagged, $perm)); self::blow(sprintf('profile_tag:tagger_tagged_privacy:%d-%d-%d', $tagger, $tagged, $perm));
} }
@ -293,38 +319,43 @@ class Profile_tag extends Managed_DataObject
} }
// Return profiles with a given tag // Return profiles with a given tag
static function getTagged($tagger, $tag) { public static function getTagged($tagger, $tag)
{
$profile = new Profile(); $profile = new Profile();
$profile->query('SELECT profile.* ' . $profile->query('SELECT profile.* ' .
'FROM profile JOIN profile_tag ' . 'FROM profile JOIN profile_tag ' .
'ON profile.id = profile_tag.tagged ' . 'ON profile.id = profile_tag.tagged ' .
'WHERE profile_tag.tagger = ' . $profile->escape($tagger) . ' ' . 'WHERE profile_tag.tagger = ' . $profile->escape($tagger) . ' ' .
'AND profile_tag.tag = "' . $profile->escape($tag) . '" '); "AND profile_tag.tag = '" . $profile->escape($tag) . "' ");
$tagged = array(); $tagged = [];
while ($profile->fetch()) { while ($profile->fetch()) {
$tagged[] = clone($profile); $tagged[] = clone($profile);
} }
return true; return true;
} }
function insert() public function insert()
{ {
$result = parent::insert(); $result = parent::insert();
if ($result) { if ($result) {
self::blow('profile_list:tagged_count:%d:%s', self::blow(
'profile_list:tagged_count:%d:%s',
$this->tagger, $this->tagger,
$this->tag); $this->tag
);
} }
return $result; return $result;
} }
function delete($useWhere=false) public function delete($useWhere = false)
{ {
$result = parent::delete($useWhere); $result = parent::delete($useWhere);
if ($result !== false) { if ($result !== false) {
self::blow('profile_list:tagged_count:%d:%s', self::blow(
'profile_list:tagged_count:%d:%s',
$this->tagger, $this->tagger,
$this->tag); $this->tag
);
} }
return $result; return $result;
} }

View File

@ -1,23 +1,25 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>. /**
* @copyright 2008, 2009, StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Table Definition for subscription * Table Definition for subscription
@ -30,8 +32,8 @@ class Subscription extends Managed_DataObject
public $__table = 'subscription'; // table name public $__table = 'subscription'; // table name
public $subscriber; // int(4) primary_key not_null public $subscriber; // int(4) primary_key not_null
public $subscribed; // int(4) primary_key not_null public $subscribed; // int(4) primary_key not_null
public $jabber; // tinyint(1) default_1 public $jabber; // bool default_true
public $sms; // tinyint(1) default_1 public $sms; // bool default_true
public $token; // varchar(191) not 255 because utf8mb4 takes more space public $token; // varchar(191) not 255 because utf8mb4 takes more space
public $secret; // varchar(191) not 255 because utf8mb4 takes more space public $secret; // varchar(191) not 255 because utf8mb4 takes more space
public $uri; // varchar(191) not 255 because utf8mb4 takes more space public $uri; // varchar(191) not 255 because utf8mb4 takes more space
@ -44,8 +46,8 @@ class Subscription extends Managed_DataObject
'fields' => array( 'fields' => array(
'subscriber' => array('type' => 'int', 'not null' => true, 'description' => 'profile listening'), 'subscriber' => array('type' => 'int', 'not null' => true, 'description' => 'profile listening'),
'subscribed' => array('type' => 'int', 'not null' => true, 'description' => 'profile being listened to'), 'subscribed' => array('type' => 'int', 'not null' => true, 'description' => 'profile being listened to'),
'jabber' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'deliver jabber messages'), 'jabber' => array('type' => 'bool', 'default' => true, 'description' => 'deliver jabber messages'),
'sms' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'deliver sms messages'), 'sms' => array('type' => 'bool', 'default' => true, 'description' => 'deliver sms messages'),
'token' => array('type' => 'varchar', 'length' => 191, 'description' => 'authorization token'), 'token' => array('type' => 'varchar', 'length' => 191, 'description' => 'authorization token'),
'secret' => array('type' => 'varchar', 'length' => 191, 'description' => 'token secret'), 'secret' => array('type' => 'varchar', 'length' => 191, 'description' => 'token secret'),
'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier'), 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier'),
@ -74,7 +76,7 @@ class Subscription extends Managed_DataObject
* @return mixed Subscription or Subscription_queue: new subscription info * @return mixed Subscription or Subscription_queue: new subscription info
*/ */
static function start(Profile $subscriber, Profile $other, $force=false) public static function start(Profile $subscriber, Profile $other, $force = false)
{ {
if (!$subscriber->hasRight(Right::SUBSCRIBE)) { if (!$subscriber->hasRight(Right::SUBSCRIBE)) {
// TRANS: Exception thrown when trying to subscribe while being banned from subscribing. // TRANS: Exception thrown when trying to subscribe while being banned from subscribing.
@ -117,7 +119,6 @@ class Subscription extends Managed_DataObject
$otherUser->autosubscribe && $otherUser->autosubscribe &&
!self::exists($other, $subscriber) && !self::exists($other, $subscriber) &&
!$subscriber->hasBlocked($other)) { !$subscriber->hasBlocked($other)) {
try { try {
self::start($other, $subscriber); self::start($other, $subscriber);
} catch (AlreadyFulfilledException $e) { } catch (AlreadyFulfilledException $e) {
@ -137,7 +138,7 @@ class Subscription extends Managed_DataObject
return $sub; return $sub;
} }
static function ensureStart(Profile $subscriber, Profile $other, $force=false) public static function ensureStart(Profile $subscriber, Profile $other, $force = false)
{ {
try { try {
$sub = self::start($subscriber, $other, $force); $sub = self::start($subscriber, $other, $force);
@ -157,12 +158,14 @@ class Subscription extends Managed_DataObject
$sub->subscriber = $subscriber->getID(); $sub->subscriber = $subscriber->getID();
$sub->subscribed = $other->getID(); $sub->subscribed = $other->getID();
$sub->jabber = 1; $sub->jabber = true;
$sub->sms = 1; $sub->sms = true;
$sub->created = common_sql_now(); $sub->created = common_sql_now();
$sub->uri = self::newUri($subscriber, $sub->uri = self::newUri(
$subscriber,
$other, $other,
$sub->created); $sub->created
);
$result = $sub->insert(); $result = $sub->insert();
@ -175,7 +178,7 @@ class Subscription extends Managed_DataObject
return $sub; return $sub;
} }
function notify() public function notify()
{ {
// XXX: add other notifications (Jabber, SMS) here // XXX: add other notifications (Jabber, SMS) here
// XXX: queue this and handle it offline // XXX: queue this and handle it offline
@ -184,12 +187,11 @@ class Subscription extends Managed_DataObject
$this->notifyEmail(); $this->notifyEmail();
} }
function notifyEmail() public function notifyEmail()
{ {
$subscribedUser = User::getKV('id', $this->subscribed); $subscribedUser = User::getKV('id', $this->subscribed);
if ($subscribedUser instanceof User) { if ($subscribedUser instanceof User) {
$subscriber = Profile::getKV('id', $this->subscriber); $subscriber = Profile::getKV('id', $this->subscriber);
mail_subscribe_notify_profile($subscribedUser, $subscriber); mail_subscribe_notify_profile($subscribedUser, $subscriber);
@ -200,7 +202,7 @@ class Subscription extends Managed_DataObject
* Cancel a subscription * Cancel a subscription
* *
*/ */
static function cancel(Profile $subscriber, Profile $other) public static function cancel(Profile $subscriber, Profile $other)
{ {
if (!self::exists($subscriber, $other)) { if (!self::exists($subscriber, $other)) {
// TRANS: Exception thrown when trying to unsibscribe without a subscription. // TRANS: Exception thrown when trying to unsibscribe without a subscription.
@ -215,7 +217,6 @@ class Subscription extends Managed_DataObject
} }
if (Event::handle('StartUnsubscribe', array($subscriber, $other))) { if (Event::handle('StartUnsubscribe', array($subscriber, $other))) {
$sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id, $sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id,
'subscribed' => $other->id)); 'subscribed' => $other->id));
@ -245,7 +246,7 @@ class Subscription extends Managed_DataObject
return; return;
} }
static function exists(Profile $subscriber, Profile $other) public static function exists(Profile $subscriber, Profile $other)
{ {
try { try {
$sub = self::getSubscription($subscriber, $other); $sub = self::getSubscription($subscriber, $other);
@ -256,7 +257,7 @@ class Subscription extends Managed_DataObject
return true; return true;
} }
static function getSubscription(Profile $subscriber, Profile $other) public static function getSubscription(Profile $subscriber, Profile $other)
{ {
// This is essentially a pkeyGet but we have an object to return in NoResultException // This is essentially a pkeyGet but we have an object to return in NoResultException
$sub = new Subscription(); $sub = new Subscription();
@ -278,7 +279,7 @@ class Subscription extends Managed_DataObject
return Profile::getByID($this->subscribed); return Profile::getByID($this->subscribed);
} }
function asActivity() public function asActivity()
{ {
$subscriber = $this->getSubscriber(); $subscriber = $this->getSubscriber();
$subscribed = $this->getSubscribed(); $subscribed = $this->getSubscribed();
@ -293,19 +294,25 @@ class Subscription extends Managed_DataObject
$act->time = strtotime($this->created); $act->time = strtotime($this->created);
// TRANS: Activity title when subscribing to another person. // TRANS: Activity title when subscribing to another person.
$act->title = _m('TITLE','Follow'); $act->title = _m('TITLE', 'Follow');
// TRANS: Notification given when one person starts following another. // TRANS: Notification given when one person starts following another.
// TRANS: %1$s is the subscriber, %2$s is the subscribed. // TRANS: %1$s is the subscriber, %2$s is the subscribed.
$act->content = sprintf(_('%1$s is now following %2$s.'), $act->content = sprintf(
_('%1$s is now following %2$s.'),
$subscriber->getBestName(), $subscriber->getBestName(),
$subscribed->getBestName()); $subscribed->getBestName()
);
$act->actor = $subscriber->asActivityObject(); $act->actor = $subscriber->asActivityObject();
$act->objects[] = $subscribed->asActivityObject(); $act->objects[] = $subscribed->asActivityObject();
$url = common_local_url('AtomPubShowSubscription', $url = common_local_url(
array('subscriber' => $subscriber->id, 'AtomPubShowSubscription',
'subscribed' => $subscribed->id)); [
'subscriber' => $subscriber->id,
'subscribed' => $subscribed->id,
]
);
$act->selfLink = $url; $act->selfLink = $url;
$act->editLink = $url; $act->editLink = $url;
@ -356,11 +363,13 @@ class Subscription extends Managed_DataObject
// The following are helper functions to the subscription lists, // The following are helper functions to the subscription lists,
// notably the public ones get used in places such as Profile // notably the public ones get used in places such as Profile
public static function getSubscribedIDs($profile_id, $offset, $limit) { public static function getSubscribedIDs($profile_id, $offset, $limit)
{
return self::getSubscriptionIDs('subscribed', $profile_id, $offset, $limit); return self::getSubscriptionIDs('subscribed', $profile_id, $offset, $limit);
} }
public static function getSubscriberIDs($profile_id, $offset, $limit) { public static function getSubscriberIDs($profile_id, $offset, $limit)
{
return self::getSubscriptionIDs('subscriber', $profile_id, $offset, $limit); return self::getSubscriptionIDs('subscriber', $profile_id, $offset, $limit);
} }
@ -397,7 +406,7 @@ class Subscription extends Managed_DataObject
$sub = new Subscription(); $sub = new Subscription();
$sub->$by_type = $profile_id; $sub->$by_type = $profile_id;
$sub->selectAdd($get_type); $sub->selectAdd($get_type);
$sub->whereAdd("{$get_type} != {$profile_id}"); $sub->whereAdd($get_type . ' <> ' . $profile_id);
$sub->orderBy('created DESC'); $sub->orderBy('created DESC');
$sub->limit($queryoffset, $querylimit); $sub->limit($queryoffset, $querylimit);
@ -426,7 +435,7 @@ class Subscription extends Managed_DataObject
* *
* @return boolean success flag. * @return boolean success flag.
*/ */
function update($dataObject=false) public function update($dataObject = false)
{ {
self::blow('subscription:by-subscriber:'.$this->subscriber); self::blow('subscription:by-subscriber:'.$this->subscriber);
self::blow('subscription:by-subscribed:'.$this->subscribed); self::blow('subscription:by-subscribed:'.$this->subscribed);

View File

@ -1,23 +1,20 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Table Definition for user * Table Definition for user
@ -37,24 +34,24 @@ class User extends Managed_DataObject
public $password; // varchar(191) not 255 because utf8mb4 takes more space public $password; // varchar(191) not 255 because utf8mb4 takes more space
public $email; // varchar(191) unique_key not 255 because utf8mb4 takes more space public $email; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $incomingemail; // varchar(191) unique_key not 255 because utf8mb4 takes more space public $incomingemail; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $emailnotifysub; // tinyint(1) default_1 public $emailnotifysub; // bool default_true
public $emailnotifyfav; // tinyint(1) default_1 public $emailnotifyfav; // tinyint(1) default_null
public $emailnotifynudge; // tinyint(1) default_1 public $emailnotifynudge; // bool default_true
public $emailnotifymsg; // tinyint(1) default_1 public $emailnotifymsg; // bool default_true
public $emailnotifyattn; // tinyint(1) default_1 public $emailnotifyattn; // bool default_true
public $language; // varchar(50) public $language; // varchar(50)
public $timezone; // varchar(50) public $timezone; // varchar(50)
public $emailpost; // tinyint(1) default_1 public $emailpost; // bool default_true
public $sms; // varchar(64) unique_key public $sms; // varchar(64) unique_key
public $carrier; // int(4) public $carrier; // int(4)
public $smsnotify; // tinyint(1) public $smsnotify; // bool default_false
public $smsreplies; // tinyint(1) public $smsreplies; // bool default_false
public $smsemail; // varchar(191) not 255 because utf8mb4 takes more space public $smsemail; // varchar(191) not 255 because utf8mb4 takes more space
public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $autosubscribe; // tinyint(1) public $autosubscribe; // bool default_false
public $subscribe_policy; // tinyint(1) public $subscribe_policy; // tinyint(1)
public $urlshorteningservice; // varchar(50) default_ur1.ca public $urlshorteningservice; // varchar(50) default_ur1.ca
public $private_stream; // tinyint(1) default_0 public $private_stream; // bool default_false
public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00 public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00
public $modified; // datetime() not_null default_CURRENT_TIMESTAMP public $modified; // datetime() not_null default_CURRENT_TIMESTAMP
@ -71,24 +68,24 @@ class User extends Managed_DataObject
'password' => array('type' => 'varchar', 'length' => 191, 'description' => 'salted password, can be null for OpenID users'), 'password' => array('type' => 'varchar', 'length' => 191, 'description' => 'salted password, can be null for OpenID users'),
'email' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for password recovery etc.'), 'email' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for password recovery etc.'),
'incomingemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for post-by-email'), 'incomingemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for post-by-email'),
'emailnotifysub' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of subscriptions'), 'emailnotifysub' => array('type' => 'bool', 'default' => true, 'description' => 'Notify by email of subscriptions'),
'emailnotifyfav' => array('type' => 'int', 'size' => 'tiny', 'default' => null, 'description' => 'Notify by email of favorites'), 'emailnotifyfav' => array('type' => 'int', 'size' => 'tiny', 'default' => null, 'description' => 'Notify by email of favorites'),
'emailnotifynudge' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of nudges'), 'emailnotifynudge' => array('type' => 'bool', 'default' => true, 'description' => 'Notify by email of nudges'),
'emailnotifymsg' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of direct messages'), 'emailnotifymsg' => array('type' => 'bool', 'default' => true, 'description' => 'Notify by email of direct messages'),
'emailnotifyattn' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of @-replies'), 'emailnotifyattn' => array('type' => 'bool', 'default' => true, 'description' => 'Notify by email of @-replies'),
'language' => array('type' => 'varchar', 'length' => 50, 'description' => 'preferred language'), 'language' => array('type' => 'varchar', 'length' => 50, 'description' => 'preferred language'),
'timezone' => array('type' => 'varchar', 'length' => 50, 'description' => 'timezone'), 'timezone' => array('type' => 'varchar', 'length' => 50, 'description' => 'timezone'),
'emailpost' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Post by email'), 'emailpost' => array('type' => 'bool', 'default' => true, 'description' => 'Post by email'),
'sms' => array('type' => 'varchar', 'length' => 64, 'description' => 'sms phone number'), 'sms' => array('type' => 'varchar', 'length' => 64, 'description' => 'sms phone number'),
'carrier' => array('type' => 'int', 'description' => 'foreign key to sms_carrier'), 'carrier' => array('type' => 'int', 'description' => 'foreign key to sms_carrier'),
'smsnotify' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to send notices to SMS'), 'smsnotify' => array('type' => 'bool', 'default' => false, 'description' => 'whether to send notices to SMS'),
'smsreplies' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to send notices to SMS on replies'), 'smsreplies' => array('type' => 'bool', 'default' => false, 'description' => 'whether to send notices to SMS on replies'),
'smsemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'built from sms and carrier'), 'smsemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'built from sms and carrier'),
'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'), 'uri' => array('type' => 'varchar', 'length' => 191, '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'), 'autosubscribe' => array('type' => 'bool', 'default' => false, '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'), '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'), 'urlshorteningservice' => array('type' => 'varchar', 'length' => 50, 'default' => 'internal', 'description' => 'service to use for auto-shortening URLs'),
'private_stream' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to limit all notices to followers only'), 'private_stream' => array('type' => 'bool', 'default' => false, 'description' => 'whether to limit all notices to followers only'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'),
), ),
@ -144,7 +141,7 @@ class User extends Managed_DataObject
return $this->getProfile()->getNickname(); return $this->getProfile()->getNickname();
} }
static function getByNickname($nickname) public static function getByNickname($nickname)
{ {
$user = User::getKV('nickname', $nickname); $user = User::getKV('nickname', $nickname);
if (!$user instanceof User) { if (!$user instanceof User) {
@ -154,12 +151,12 @@ class User extends Managed_DataObject
return $user; return $user;
} }
function isSubscribed(Profile $other) public function isSubscribed(Profile $other)
{ {
return $this->getProfile()->isSubscribed($other); return $this->getProfile()->isSubscribed($other);
} }
function hasPendingSubscription(Profile $other) public function hasPendingSubscription(Profile $other)
{ {
return $this->getProfile()->hasPendingSubscription($other); return $this->getProfile()->hasPendingSubscription($other);
} }
@ -169,17 +166,17 @@ class User extends Managed_DataObject
* *
* @return mixed Notice or null * @return mixed Notice or null
*/ */
function getCurrentNotice() public function getCurrentNotice()
{ {
return $this->getProfile()->getCurrentNotice(); return $this->getProfile()->getCurrentNotice();
} }
function getCarrier() public function getCarrier()
{ {
return Sms_carrier::getKV('id', $this->carrier); return Sms_carrier::getKV('id', $this->carrier);
} }
function hasBlocked(Profile $other) public function hasBlocked(Profile $other)
{ {
return $this->getProfile()->hasBlocked($other); return $this->getProfile()->hasBlocked($other);
} }
@ -206,10 +203,9 @@ class User extends Managed_DataObject
* @return User object * @return User object
* @throws Exception on failure * @throws Exception on failure
*/ */
static function register(array $fields, $accept_email_fail=false) { public static function register(array $fields, $accept_email_fail = false)
{
// MAGICALLY put fields into current scope // MAGICALLY put fields into current scope
extract($fields); extract($fields);
$profile = new Profile(); $profile = new Profile();
@ -262,23 +258,22 @@ class User extends Managed_DataObject
} }
} }
if(isset($email_confirmed) && $email_confirmed) { if (isset($email_confirmed) && $email_confirmed) {
$user->email = $email; $user->email = $email;
} }
// Set default-on options here, otherwise they'll be disabled // Set default-on options here, otherwise they'll be disabled
// initially for sites using caching, since the initial encache // initially for sites using caching, since the initial encache
// doesn't know about the defaults in the database. // doesn't know about the defaults in the database.
$user->emailnotifysub = 1; $user->emailnotifysub = true;
$user->emailnotifynudge = 1; $user->emailnotifynudge = true;
$user->emailnotifymsg = 1; $user->emailnotifymsg = true;
$user->emailnotifyattn = 1; $user->emailnotifyattn = true;
$user->emailpost = 1; $user->emailpost = true;
$user->created = common_sql_now(); $user->created = common_sql_now();
if (Event::handle('StartUserRegister', array($profile))) { if (Event::handle('StartUserRegister', array($profile))) {
$profile->query('BEGIN'); $profile->query('BEGIN');
$id = $profile->insert(); $id = $profile->insert();
@ -367,8 +362,11 @@ class User extends Managed_DataObject
if (!empty($defnick)) { if (!empty($defnick)) {
$defuser = User::getKV('nickname', $defnick); $defuser = User::getKV('nickname', $defnick);
if (empty($defuser)) { if (empty($defuser)) {
common_log(LOG_WARNING, sprintf("Default user %s does not exist.", $defnick), common_log(
__FILE__); LOG_WARNING,
sprintf('Default user %s does not exist.', $defnick),
__FILE__
);
} else { } else {
Subscription::ensureStart($profile, $defuser->getProfile()); Subscription::ensureStart($profile, $defuser->getProfile());
} }
@ -394,16 +392,23 @@ class User extends Managed_DataObject
if (!empty($welcome)) { if (!empty($welcome)) {
$welcomeuser = User::getKV('nickname', $welcome); $welcomeuser = User::getKV('nickname', $welcome);
if (empty($welcomeuser)) { if (empty($welcomeuser)) {
common_log(LOG_WARNING, sprintf("Welcome user %s does not exist.", $defnick), common_log(
__FILE__); LOG_WARNING,
sprintf('Welcome user %s does not exist.', $defnick),
__FILE__
);
} else { } else {
$notice = Notice::saveNew($welcomeuser->id, $notice = Notice::saveNew(
$welcomeuser->id,
// TRANS: Notice given on user registration. // TRANS: Notice given on user registration.
// TRANS: %1$s is the sitename, $2$s is the registering user's nickname. // TRANS: %1$s is the sitename, $2$s is the registering user's nickname.
sprintf(_('Welcome to %1$s, @%2$s!'), sprintf(
_('Welcome to %1$s, @%2$s!'),
common_config('site', 'name'), common_config('site', 'name'),
$profile->getNickname()), $profile->getNickname()
'system'); ),
'system'
);
} }
} }
@ -418,9 +423,8 @@ class User extends Managed_DataObject
} }
// Things we do when the email changes // Things we do when the email changes
function emailChanged() public function emailChanged()
{ {
$invites = new Invitation(); $invites = new Invitation();
$invites->address = $this->email; $invites->address = $this->email;
$invites->address_type = 'email'; $invites->address_type = 'email';
@ -441,48 +445,53 @@ class User extends Managed_DataObject
} }
} }
function mutuallySubscribed(Profile $other) public function mutuallySubscribed(Profile $other)
{ {
return $this->getProfile()->mutuallySubscribed($other); return $this->getProfile()->mutuallySubscribed($other);
} }
function mutuallySubscribedUsers() public function mutuallySubscribedUsers()
{ {
// 3-way join; probably should get cached
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
$qry = "SELECT $UT.* " .
"FROM subscription sub1 JOIN $UT ON sub1.subscribed = $UT.id " .
"JOIN subscription sub2 ON $UT.id = sub2.subscriber " .
'WHERE sub1.subscriber = %d and sub2.subscribed = %d ' .
"ORDER BY $UT.nickname";
$user = new User(); $user = new User();
$user->query(sprintf($qry, $this->id, $this->id));
// 3-way join; probably should get cached
$user->query(sprintf(
'SELECT %1$s.* ' .
'FROM subscription AS sub1 INNER JOIN %1$s ON sub1.subscribed = %1$s.id ' .
'INNER JOIN subscription AS sub2 ON %1$s.id = sub2.subscriber ' .
'WHERE sub1.subscriber = %2$d AND sub2.subscribed = %2$d ' .
'ORDER BY %1$s.nickname',
$user->escapedTableName(),
$this->id
));
return $user; return $user;
} }
function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) public function getReplies($offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $before_id = 0)
{ {
return $this->getProfile()->getReplies($offset, $limit, $since_id, $before_id); return $this->getProfile()->getReplies($offset, $limit, $since_id, $before_id);
} }
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) { public function getTaggedNotices($tag, $offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $before_id = 0)
{
return $this->getProfile()->getTaggedNotices($tag, $offset, $limit, $since_id, $before_id); return $this->getProfile()->getTaggedNotices($tag, $offset, $limit, $since_id, $before_id);
} }
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) public function getNotices($offset = 0, $limit = NOTICES_PER_PAGE, $since_id = 0, $before_id = 0)
{ {
return $this->getProfile()->getNotices($offset, $limit, $since_id, $before_id); return $this->getProfile()->getNotices($offset, $limit, $since_id, $before_id);
} }
function block(Profile $other) public function block(Profile $other)
{ {
// Add a new block record // Add a new block record
// no blocking (and thus unsubbing from) yourself // no blocking (and thus unsubbing from) yourself
if ($this->id == $other->id) { if ($this->id == $other->id) {
common_log(LOG_WARNING, common_log(
LOG_WARNING,
sprintf( sprintf(
"Profile ID %d (%s) tried to block themself.", "Profile ID %d (%s) tried to block themself.",
$this->id, $this->id,
@ -521,7 +530,7 @@ class User extends Managed_DataObject
return true; return true;
} }
function unblock(Profile $other) public function unblock(Profile $other)
{ {
// Get the block record // Get the block record
@ -541,17 +550,17 @@ class User extends Managed_DataObject
return true; return true;
} }
function isMember(User_group $group) public function isMember(User_group $group)
{ {
return $this->getProfile()->isMember($group); return $this->getProfile()->isMember($group);
} }
function isAdmin(User_group $group) public function isAdmin(User_group $group)
{ {
return $this->getProfile()->isAdmin($group); return $this->getProfile()->isAdmin($group);
} }
function getGroups($offset=0, $limit=null) public function getGroups($offset = 0, $limit = null)
{ {
return $this->getProfile()->getGroups($offset, $limit); return $this->getProfile()->getGroups($offset, $limit);
} }
@ -563,7 +572,7 @@ class User extends Managed_DataObject
* @param User_group $group * @param User_group $group
* @return Group_member * @return Group_member
*/ */
function joinGroup(User_group $group) public function joinGroup(User_group $group)
{ {
return $this->getProfile()->joinGroup($group); return $this->getProfile()->joinGroup($group);
} }
@ -573,37 +582,37 @@ class User extends Managed_DataObject
* *
* @param User_group $group * @param User_group $group
*/ */
function leaveGroup(User_group $group) public function leaveGroup(User_group $group)
{ {
return $this->getProfile()->leaveGroup($group); return $this->getProfile()->leaveGroup($group);
} }
function getSubscribed($offset=0, $limit=null) public function getSubscribed($offset = 0, $limit = null)
{ {
return $this->getProfile()->getSubscribed($offset, $limit); return $this->getProfile()->getSubscribed($offset, $limit);
} }
function getSubscribers($offset=0, $limit=null) public function getSubscribers($offset = 0, $limit = null)
{ {
return $this->getProfile()->getSubscribers($offset, $limit); return $this->getProfile()->getSubscribers($offset, $limit);
} }
function getTaggedSubscribers($tag, $offset=0, $limit=null) public function getTaggedSubscribers($tag, $offset = 0, $limit = null)
{ {
return $this->getProfile()->getTaggedSubscribers($tag, $offset, $limit); return $this->getProfile()->getTaggedSubscribers($tag, $offset, $limit);
} }
function getTaggedSubscriptions($tag, $offset=0, $limit=null) public function getTaggedSubscriptions($tag, $offset = 0, $limit = null)
{ {
return $this->getProfile()->getTaggedSubscriptions($tag, $offset, $limit); return $this->getProfile()->getTaggedSubscriptions($tag, $offset, $limit);
} }
function hasRight($right) public function hasRight($right)
{ {
return $this->getProfile()->hasRight($right); return $this->getProfile()->hasRight($right);
} }
function delete($useWhere=false) public function delete($useWhere = false)
{ {
if (empty($this->id)) { if (empty($this->id)) {
common_log(LOG_WARNING, "Ambiguous User->delete(); skipping related tables."); common_log(LOG_WARNING, "Ambiguous User->delete(); skipping related tables.");
@ -640,14 +649,14 @@ class User extends Managed_DataObject
return parent::delete($useWhere); return parent::delete($useWhere);
} }
function _deleteTags() public function _deleteTags()
{ {
$tag = new Profile_tag(); $tag = new Profile_tag();
$tag->tagger = $this->id; $tag->tagger = $this->id;
$tag->delete(); $tag->delete();
} }
function _deleteBlocks() public function _deleteBlocks()
{ {
$block = new Profile_block(); $block = new Profile_block();
$block->blocker = $this->id; $block->blocker = $this->id;
@ -655,32 +664,32 @@ class User extends Managed_DataObject
// XXX delete group block? Reset blocker? // XXX delete group block? Reset blocker?
} }
function hasRole($name) public function hasRole($name)
{ {
return $this->getProfile()->hasRole($name); return $this->getProfile()->hasRole($name);
} }
function grantRole($name) public function grantRole($name)
{ {
return $this->getProfile()->grantRole($name); return $this->getProfile()->grantRole($name);
} }
function revokeRole($name) public function revokeRole($name)
{ {
return $this->getProfile()->revokeRole($name); return $this->getProfile()->revokeRole($name);
} }
function isSandboxed() public function isSandboxed()
{ {
return $this->getProfile()->isSandboxed(); return $this->getProfile()->isSandboxed();
} }
function isSilenced() public function isSilenced()
{ {
return $this->getProfile()->isSilenced(); return $this->getProfile()->isSilenced();
} }
function receivesEmailNotifications() public function receivesEmailNotifications()
{ {
// We could do this in one large if statement, but that's not as easy to read // We could do this in one large if statement, but that's not as easy to read
// Don't send notifications if we don't know the user's email address or it is // Don't send notifications if we don't know the user's email address or it is
@ -695,7 +704,7 @@ class User extends Managed_DataObject
return true; return true;
} }
function repeatedByMe($offset=0, $limit=20, $since_id=null, $max_id=null) public function repeatedByMe($offset = 0, $limit = 20, $since_id = null, $max_id = null)
{ {
// FIXME: Use another way to get Profile::current() since we // FIXME: Use another way to get Profile::current() since we
// want to avoid confusion between session user and queue processing. // want to avoid confusion between session user and queue processing.
@ -704,7 +713,7 @@ class User extends Managed_DataObject
} }
function repeatsOfMe($offset=0, $limit=20, $since_id=null, $max_id=null) public function repeatsOfMe($offset = 0, $limit = 20, $since_id = null, $max_id = null)
{ {
// FIXME: Use another way to get Profile::current() since we // FIXME: Use another way to get Profile::current() since we
// want to avoid confusion between session user and queue processing. // want to avoid confusion between session user and queue processing.
@ -712,7 +721,7 @@ class User extends Managed_DataObject
return $stream->getNotices($offset, $limit, $since_id, $max_id); return $stream->getNotices($offset, $limit, $since_id, $max_id);
} }
public function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null) public function repeatedToMe($offset = 0, $limit = 20, $since_id = null, $max_id = null)
{ {
return $this->getProfile()->repeatedToMe($offset, $limit, $since_id, $max_id); return $this->getProfile()->repeatedToMe($offset, $limit, $since_id, $max_id);
} }
@ -791,7 +800,7 @@ class User extends Managed_DataObject
* @throws ServerException if no valid single user account is present * @throws ServerException if no valid single user account is present
* @throws ServerException if called when not in single-user mode * @throws ServerException if called when not in single-user mode
*/ */
static function singleUserNickname() public static function singleUserNickname()
{ {
try { try {
$user = User::singleUser(); $user = User::singleUser();
@ -828,7 +837,7 @@ class User extends Managed_DataObject
* Get a list of OAuth client applications that have access to this * Get a list of OAuth client applications that have access to this
* user's account. * user's account.
*/ */
function getConnectedApps($offset = 0, $limit = null) public function getConnectedApps($offset = 0, $limit = null)
{ {
$qry = $qry =
'SELECT u.* ' . 'SELECT u.* ' .
@ -839,11 +848,7 @@ class User extends Managed_DataObject
'ORDER BY u.created DESC '; 'ORDER BY u.created DESC ';
if ($offset > 0) { if ($offset > 0) {
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
} }
$apps = new Oauth_application_user(); $apps = new Oauth_application_user();
@ -863,14 +868,14 @@ class User extends Managed_DataObject
* @return array of variable names to include in serialization. * @return array of variable names to include in serialization.
*/ */
function __sleep() public function __sleep()
{ {
$vars = parent::__sleep(); $vars = parent::__sleep();
$skip = array('_profile'); $skip = array('_profile');
return array_diff($vars, $skip); return array_diff($vars, $skip);
} }
static function recoverPassword($nore) public static function recoverPassword($nore)
{ {
require_once INSTALLDIR . '/lib/util/mail.php'; require_once INSTALLDIR . '/lib/util/mail.php';
@ -951,8 +956,10 @@ class User extends Managed_DataObject
$body .= "\n\n"; $body .= "\n\n";
$body .= 'If it was you, and you want to confirm, use the URL below:'; $body .= 'If it was you, and you want to confirm, use the URL below:';
$body .= "\n\n"; $body .= "\n\n";
$body .= "\t".common_local_url('recoverpassword', $body .= "\t" . common_local_url(
array('code' => $confirm->code)); 'recoverpassword',
['code' => $confirm->code]
);
$body .= "\n\n"; $body .= "\n\n";
$body .= 'If not, just ignore this message.'; $body .= 'If not, just ignore this message.';
$body .= "\n\n"; $body .= "\n\n";
@ -966,7 +973,7 @@ class User extends Managed_DataObject
mail_to_user($user, _('Password recovery requested'), $body, $headers, $confirm->address); mail_to_user($user, _('Password recovery requested'), $body, $headers, $confirm->address);
} }
function streamModeOnly() public function streamModeOnly()
{ {
if (common_config('oldschool', 'enabled')) { if (common_config('oldschool', 'enabled')) {
$osp = Old_school_prefs::getKV('user_id', $this->id); $osp = Old_school_prefs::getKV('user_id', $this->id);
@ -978,7 +985,7 @@ class User extends Managed_DataObject
return false; return false;
} }
function streamNicknames() public function streamNicknames()
{ {
if (common_config('oldschool', 'enabled')) { if (common_config('oldschool', 'enabled')) {
$osp = Old_school_prefs::getKV('user_id', $this->id); $osp = Old_school_prefs::getKV('user_id', $this->id);
@ -989,7 +996,7 @@ class User extends Managed_DataObject
return false; return false;
} }
function registrationActivity() public function registrationActivity()
{ {
$profile = $this->getProfile(); $profile = $this->getProfile();
@ -1007,16 +1014,20 @@ class User extends Managed_DataObject
$act->objects[] = $service; $act->objects[] = $service;
$act->id = TagURI::mint('user:register:%d', $act->id = TagURI::mint(
$this->id); 'user:register:%d',
$this->id
);
$act->time = strtotime($this->created); $act->time = strtotime($this->created);
$act->title = _("Register"); $act->title = _("Register");
$act->content = sprintf(_('%1$s joined %2$s.'), $act->content = sprintf(
_('%1$s joined %2$s.'),
$profile->getBestName(), $profile->getBestName(),
$service->title); $service->title
);
return $act; return $act;
} }

View File

@ -1,8 +1,24 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
/** /**
* Table Definition for user_group * Table Definition for user_group
*/ */
class User_group extends Managed_DataObject class User_group extends Managed_DataObject
{ {
const JOIN_POLICY_OPEN = 0; const JOIN_POLICY_OPEN = 0;
@ -118,40 +134,38 @@ class User_group extends Managed_DataObject
return Theme::path('default-avatar-'.$sizenames[$size].'.png'); return Theme::path('default-avatar-'.$sizenames[$size].'.png');
} }
function homeUrl() public function homeUrl()
{ {
return $this->getProfile()->getUrl(); return $this->getProfile()->getUrl();
} }
function getUri() public function getUri()
{ {
$uri = null; $uri = null;
if (Event::handle('StartUserGroupGetUri', array($this, &$uri))) { if (Event::handle('StartUserGroupGetUri', array($this, &$uri))) {
if (!empty($this->uri)) { if (!empty($this->uri)) {
$uri = $this->uri; $uri = $this->uri;
} elseif ($this->isLocal()) { } elseif ($this->isLocal()) {
$uri = common_local_url('groupbyid', $uri = common_local_url('groupbyid', ['id' => $this->id]);
array('id' => $this->id));
} }
} }
Event::handle('EndUserGroupGetUri', array($this, &$uri)); Event::handle('EndUserGroupGetUri', array($this, &$uri));
return $uri; return $uri;
} }
function permalink() public function permalink()
{ {
$url = null; $url = null;
if (Event::handle('StartUserGroupPermalink', array($this, &$url))) { if (Event::handle('StartUserGroupPermalink', array($this, &$url))) {
if ($this->isLocal()) { if ($this->isLocal()) {
$url = common_local_url('groupbyid', $url = common_local_url('groupbyid', ['id' => $this->id]);
array('id' => $this->id));
} }
} }
Event::handle('EndUserGroupPermalink', array($this, &$url)); Event::handle('EndUserGroupPermalink', array($this, &$url));
return $url; return $url;
} }
function getNotices($offset, $limit, $since_id=null, $max_id=null) public function getNotices($offset, $limit, $since_id = null, $max_id = null)
{ {
// FIXME: Get the Profile::current() some other way, to avoid // FIXME: Get the Profile::current() some other way, to avoid
// possible confusion between current session and queue process. // possible confusion between current session and queue process.
@ -160,29 +174,26 @@ class User_group extends Managed_DataObject
return $stream->getNotices($offset, $limit, $since_id, $max_id); return $stream->getNotices($offset, $limit, $since_id, $max_id);
} }
function getMembers($offset=0, $limit=null) { public function getMembers($offset = 0, $limit = null)
{
$ids = null; $ids = null;
if (is_null($limit) || $offset + $limit > User_group::CACHE_WINDOW) { if (is_null($limit) || $offset + $limit > User_group::CACHE_WINDOW) {
$ids = $this->getMemberIDs($offset, $ids = $this->getMemberIDs($offset, $limit);
$limit);
} else { } else {
$key = sprintf('group:member_ids:%d', $this->id); $key = sprintf('group:member_ids:%d', $this->id);
$window = self::cacheGet($key); $window = self::cacheGet($key);
if ($window === false) { if ($window === false) {
$window = $this->getMemberIDs(0, $window = $this->getMemberIDs(0, User_group::CACHE_WINDOW);
User_group::CACHE_WINDOW);
self::cacheSet($key, $window); self::cacheSet($key, $window);
} }
$ids = array_slice($window, $ids = array_slice($window, $offset, $limit);
$offset,
$limit);
} }
return Profile::multiGet('id', $ids); return Profile::multiGet('id', $ids);
} }
function getMemberIDs($offset=0, $limit=null) public function getMemberIDs($offset = 0, $limit = null)
{ {
$gm = new Group_member(); $gm = new Group_member();
@ -215,7 +226,7 @@ class User_group extends Managed_DataObject
* @param int $limit * @param int $limit
* @return Profile * @return Profile
*/ */
function getRequests($offset=0, $limit=null) public function getRequests($offset = 0, $limit = null)
{ {
$rq = new Group_join_queue(); $rq = new Group_join_queue();
$rq->group_id = $this->id; $rq->group_id = $this->id;
@ -237,7 +248,7 @@ class User_group extends Managed_DataObject
{ {
$block = new Group_member(); $block = new Group_member();
$block->group_id = $this->id; $block->group_id = $this->id;
$block->is_admin = 1; $block->is_admin = true;
return $block->count(); return $block->count();
} }
@ -264,7 +275,7 @@ class User_group extends Managed_DataObject
return $cnt; return $cnt;
} }
function getBlockedCount() public function getBlockedCount()
{ {
// XXX: WORM cache this // XXX: WORM cache this
@ -274,7 +285,7 @@ class User_group extends Managed_DataObject
return $block->count(); return $block->count();
} }
function getQueueCount() public function getQueueCount()
{ {
// XXX: WORM cache this // XXX: WORM cache this
@ -284,11 +295,12 @@ class User_group extends Managed_DataObject
return $queue->count(); return $queue->count();
} }
function getAdmins($offset=null, $limit=null) // offset is null because DataObject wants it, 0 would mean no results // offset is null because DataObject wants it, 0 would mean no results
public function getAdmins($offset = null, $limit = null)
{ {
$admins = new Profile(); $admins = new Profile();
$admins->joinAdd(array('id', 'group_member:profile_id')); $admins->joinAdd(array('id', 'group_member:profile_id'));
$admins->whereAdd(sprintf('group_member.group_id = %u AND group_member.is_admin = 1', $this->id)); $admins->whereAdd('group_member.group_id = ' . $this->id . ' AND group_member.is_admin = true');
$admins->orderBy('group_member.modified ASC'); $admins->orderBy('group_member.modified ASC');
$admins->limit($offset, $limit); $admins->limit($offset, $limit);
$admins->find(); $admins->find();
@ -296,7 +308,8 @@ class User_group extends Managed_DataObject
return $admins; return $admins;
} }
function getBlocked($offset=null, $limit=null) // offset is null because DataObject wants it, 0 would mean no results // offset is null because DataObject wants it, 0 would mean no results
public function getBlocked($offset = null, $limit = null)
{ {
$blocked = new Profile(); $blocked = new Profile();
$blocked->joinAdd(array('id', 'group_block:blocked')); $blocked->joinAdd(array('id', 'group_block:blocked'));
@ -308,7 +321,7 @@ class User_group extends Managed_DataObject
return $blocked; return $blocked;
} }
function setOriginal($filename) public function setOriginal($filename)
{ {
// This should be handled by the Profile->setOriginal function so user and group avatars are handled the same // This should be handled by the Profile->setOriginal function so user and group avatars are handled the same
$imagefile = new ImageFile(null, Avatar::path($filename)); $imagefile = new ImageFile(null, Avatar::path($filename));
@ -320,8 +333,12 @@ class User_group extends Managed_DataObject
$orig = clone($this); $orig = clone($this);
$this->original_logo = Avatar::url($filename); $this->original_logo = Avatar::url($filename);
foreach ($sizes as $name=>$size) { foreach ($sizes as $name=>$size) {
$filename = Avatar::filename($this->profile_id, image_type_to_extension($imagefile->preferredType()), $filename = Avatar::filename(
$size, common_timestamp()); $this->profile_id,
image_type_to_extension($imagefile->preferredType()),
$size,
common_timestamp()
);
$imagefile->resizeTo(Avatar::path($filename), array('width'=>$size, 'height'=>$size)); $imagefile->resizeTo(Avatar::path($filename), array('width'=>$size, 'height'=>$size));
$this->$name = Avatar::url($filename); $this->$name = Avatar::url($filename);
} }
@ -329,7 +346,7 @@ class User_group extends Managed_DataObject
return $this->update($orig); return $this->update($orig);
} }
function getBestName() public function getBestName()
{ {
return ($this->fullname) ? $this->fullname : $this->nickname; return ($this->fullname) ? $this->fullname : $this->nickname;
} }
@ -340,17 +357,17 @@ class User_group extends Managed_DataObject
* *
* @return string * @return string
*/ */
function getFancyName() public function getFancyName()
{ {
if ($this->fullname) { if ($this->fullname) {
// TRANS: Full name of a profile or group followed by nickname in parens // TRANS: Full name of a profile or group followed by nickname in parens
return sprintf(_m('FANCYNAME','%1$s (%2$s)'), $this->fullname, $this->nickname); return sprintf(_m('FANCYNAME', '%1$s (%2$s)'), $this->fullname, $this->nickname);
} else { } else {
return $this->nickname; return $this->nickname;
} }
} }
function getAliases() public function getAliases()
{ {
$aliases = array(); $aliases = array();
@ -371,8 +388,8 @@ class User_group extends Managed_DataObject
return $aliases; return $aliases;
} }
function setAliases($newaliases) { public function setAliases($newaliases)
{
$newaliases = array_unique($newaliases); $newaliases = array_unique($newaliases);
$oldaliases = $this->getAliases(); $oldaliases = $this->getAliases();
@ -413,7 +430,7 @@ class User_group extends Managed_DataObject
return true; return true;
} }
static function getForNickname($nickname, Profile $profile=null) public static function getForNickname($nickname, Profile $profile = null)
{ {
$nickname = Nickname::normalize($nickname); $nickname = Nickname::normalize($nickname);
@ -440,24 +457,21 @@ class User_group extends Managed_DataObject
return null; return null;
} }
function getUserMembers() public function getUserMembers()
{ {
// XXX: cache this // XXX: cache this
$user = new User(); $user = new User();
if(common_config('db','quote_identifiers'))
$user_table = '"user"';
else $user_table = 'user';
$qry = $user->query(sprintf(
'SELECT id ' . 'SELECT id FROM %1$s INNER JOIN group_member ' .
'FROM '. $user_table .' JOIN group_member '. 'ON %1$s.id = group_member.profile_id ' .
'ON '. $user_table .'.id = group_member.profile_id ' . 'WHERE group_member.group_id = %2$d ',
'WHERE group_member.group_id = %d '; $user->escapedTableName(),
$this->id
));
$user->query(sprintf($qry, $this->id)); $ids = [];
$ids = array();
while ($user->fetch()) { while ($user->fetch()) {
$ids[] = $user->id; $ids[] = $user->id;
@ -468,7 +482,7 @@ class User_group extends Managed_DataObject
return $ids; return $ids;
} }
static function maxDescription() public static function maxDescription()
{ {
$desclimit = common_config('group', 'desclimit'); $desclimit = common_config('group', 'desclimit');
// null => use global limit (distinct from 0!) // null => use global limit (distinct from 0!)
@ -478,13 +492,13 @@ class User_group extends Managed_DataObject
return $desclimit; return $desclimit;
} }
static function descriptionTooLong($desc) public static function descriptionTooLong($desc)
{ {
$desclimit = self::maxDescription(); $desclimit = self::maxDescription();
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit)); return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
} }
function asAtomEntry($namespace=false, $source=false) public function asAtomEntry($namespace = false, $source = false)
{ {
$xs = new XMLStringer(true); $xs = new XMLStringer(true);
@ -528,7 +542,7 @@ class User_group extends Managed_DataObject
return $xs->getString(); return $xs->getString();
} }
function asAtomAuthor() public function asAtomAuthor()
{ {
$xs = new XMLStringer(true); $xs = new XMLStringer(true);
@ -551,20 +565,21 @@ class User_group extends Managed_DataObject
* *
* @return string * @return string
*/ */
function asActivityNoun($element) public function asActivityNoun($element)
{ {
$noun = ActivityObject::fromGroup($this); $noun = ActivityObject::fromGroup($this);
return $noun->asString('activity:' . $element); return $noun->asString('activity:' . $element);
} }
function getAvatar() public function getAvatar()
{ {
return empty($this->homepage_logo) return empty($this->homepage_logo)
? User_group::defaultLogo(AVATAR_PROFILE_SIZE) ? User_group::defaultLogo(AVATAR_PROFILE_SIZE)
: $this->homepage_logo; : $this->homepage_logo;
} }
static function register($fields) { public static function register($fields)
{
if (!empty($fields['userid'])) { if (!empty($fields['userid'])) {
$profile = Profile::getKV('id', $fields['userid']); $profile = Profile::getKV('id', $fields['userid']);
if ($profile && !$profile->hasRight(Right::CREATEGROUP)) { if ($profile && !$profile->hasRight(Right::CREATEGROUP)) {
@ -580,15 +595,17 @@ class User_group extends Managed_DataObject
// MAGICALLY put fields into current scope // MAGICALLY put fields into current scope
// @fixme kill extract(); it makes debugging absurdly hard // @fixme kill extract(); it makes debugging absurdly hard
$defaults = array('nickname' => null, $defaults = [
'nickname' => null,
'fullname' => null, 'fullname' => null,
'homepage' => null, 'homepage' => null,
'description' => null, 'description' => null,
'location' => null, 'location' => null,
'uri' => null, 'uri' => null,
'mainpage' => null, 'mainpage' => null,
'aliases' => array(), 'aliases' => [],
'userid' => null); 'userid' => null,
];
$fields = array_merge($defaults, $fields); $fields = array_merge($defaults, $fields);
@ -645,7 +662,6 @@ class User_group extends Managed_DataObject
} }
if (Event::handle('StartGroupSave', array(&$group))) { if (Event::handle('StartGroupSave', array(&$group))) {
$result = $group->insert(); $result = $group->insert();
if ($result === false) { if ($result === false) {
@ -676,7 +692,7 @@ class User_group extends Managed_DataObject
$member->group_id = $group->id; $member->group_id = $group->id;
$member->profile_id = $userid; $member->profile_id = $userid;
$member->is_admin = 1; $member->is_admin = true;
$member->created = $group->created; $member->created = $group->created;
$result = $member->insert(); $result = $member->insert();
@ -721,7 +737,7 @@ class User_group extends Managed_DataObject
* are not de-cached in the UI, including the sidebar lists on * are not de-cached in the UI, including the sidebar lists on
* GroupsAction * GroupsAction
*/ */
function delete($useWhere=false) public function delete($useWhere = false)
{ {
if (empty($this->id)) { if (empty($this->id)) {
common_log(LOG_WARNING, "Ambiguous User_group->delete(); skipping related tables."); common_log(LOG_WARNING, "Ambiguous User_group->delete(); skipping related tables.");
@ -813,7 +829,7 @@ class User_group extends Managed_DataObject
return parent::update($dataObject); return parent::update($dataObject);
} }
function isPrivate() public function isPrivate()
{ {
return ($this->join_policy == self::JOIN_POLICY_MODERATE && return ($this->join_policy == self::JOIN_POLICY_MODERATE &&
intval($this->force_scope) === 1); intval($this->force_scope) === 1);
@ -825,14 +841,16 @@ class User_group extends Managed_DataObject
return ($local instanceof Local_group); return ($local instanceof Local_group);
} }
static function groupsFromText($text, Profile $profile) public static function groupsFromText($text, Profile $profile)
{ {
$groups = array(); $groups = array();
/* extract all !group */ /* extract all !group */
$count = preg_match_all('/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/', $count = preg_match_all(
'/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/',
strtolower($text), strtolower($text),
$match); $match
);
if (!$count) { if (!$count) {
return $groups; return $groups;
@ -848,7 +866,7 @@ class User_group extends Managed_DataObject
return $groups; return $groups;
} }
static function idsFromText($text, Profile $profile) public static function idsFromText($text, Profile $profile)
{ {
$ids = array(); $ids = array();
$groups = self::groupsFromText($text, $profile); $groups = self::groupsFromText($text, $profile);

View File

@ -1,32 +1,31 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Data class for user IM preferences * Data class for user IM preferences
* *
* 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 Data * @category Data
* @package StatusNet * @package GNUsocial
* @author Craig Andrews <candrews@integralblue.com> * @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 StatusNet Inc. * @copyright 2009 StatusNet Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
defined('GNUSOCIAL') || die();
require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class User_im_prefs extends Managed_DataObject class User_im_prefs extends Managed_DataObject
@ -38,9 +37,9 @@ class User_im_prefs extends Managed_DataObject
public $user_id; // int(4) primary_key not_null public $user_id; // int(4) primary_key not_null
public $screenname; // varchar(191) not_null not 255 because utf8mb4 takes more space public $screenname; // varchar(191) not_null not 255 because utf8mb4 takes more space
public $transport; // varchar(191) not_null not 255 because utf8mb4 takes more space public $transport; // varchar(191) not_null not 255 because utf8mb4 takes more space
public $notify; // tinyint(1) public $notify; // bool not_null default_false
public $replies; // tinyint(1) public $replies; // bool not_null default_false
public $updatefrompresence; // tinyint(1) public $updatefrompresence; // bool not_null default_false
public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00 public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00
public $modified; // datetime() not_null default_CURRENT_TIMESTAMP public $modified; // datetime() not_null default_CURRENT_TIMESTAMP
@ -54,9 +53,9 @@ class User_im_prefs extends Managed_DataObject
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user'), 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user'),
'screenname' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'screenname on this service'), 'screenname' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'screenname on this service'),
'transport' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'transport (ex xmpp, aim)'), 'transport' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'transport (ex xmpp, aim)'),
'notify' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Notify when a new notice is sent'), 'notify' => array('type' => 'bool', 'not null' => true, 'default' => false, 'description' => 'Notify when a new notice is sent'),
'replies' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Send replies from people not subscribed to'), 'replies' => array('type' => 'bool', 'not null' => true, 'default' => false, 'description' => 'Send replies from people not subscribed to'),
'updatefrompresence' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Send replies from people not subscribed to.'), 'updatefrompresence' => array('type' => 'bool', 'not null' => true, 'default' => false, 'description' => 'Update from presence.'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'),
), ),
@ -69,5 +68,4 @@ class User_im_prefs extends Managed_DataObject
), ),
); );
} }
} }

View File

@ -1,30 +1,27 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Data class for user location preferences * Data class for user location preferences
* *
* 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 Data * @category Data
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet Inc. * @copyright 2009 StatusNet Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
@ -36,7 +33,7 @@ class User_location_prefs extends Managed_DataObject
public $__table = 'user_location_prefs'; // table name public $__table = 'user_location_prefs'; // table name
public $user_id; // int(4) primary_key not_null public $user_id; // int(4) primary_key not_null
public $share_location; // tinyint(1) default_1 public $share_location; // bool default_true
public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00 public $created; // datetime() not_null default_0000-00-00%2000%3A00%3A00
public $modified; // datetime() not_null default_CURRENT_TIMESTAMP public $modified; // datetime() not_null default_CURRENT_TIMESTAMP
@ -48,7 +45,7 @@ class User_location_prefs extends Managed_DataObject
return array( return array(
'fields' => array( 'fields' => array(
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who has the preference'), 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who has the preference'),
'share_location' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Whether to share location data'), 'share_location' => array('type' => 'bool', 'default' => true, 'description' => 'Whether to share location data'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'),
), ),

View File

@ -1,9 +1,26 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
defined('GNUSOCIAL') || die();
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
/** /**
* Table Definition for user_username * Table Definition for user_username
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class User_username extends Managed_DataObject class User_username extends Managed_DataObject
{ {
###START_AUTOCODE ###START_AUTOCODE
@ -23,8 +40,8 @@ class User_username extends Managed_DataObject
{ {
return array( return array(
'fields' => array( 'fields' => array(
'provider_name' => array('type' => 'varchar', 'length' => 191, 'description' => 'provider name'), 'provider_name' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'provider name'),
'username' => array('type' => 'varchar', 'length' => 191, 'description' => 'username'), 'username' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'username'),
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice id this title relates to'), 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice id this title relates to'),
'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'default' => '0000-00-00 00:00:00', 'description' => 'date this record was created'),
'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'), 'modified' => array('type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'),
@ -46,7 +63,7 @@ class User_username extends Managed_DataObject
* @param provider_name string name of the provider * @param provider_name string name of the provider
* @return mixed User_username instance if the registration succeeded, false if it did not * @return mixed User_username instance if the registration succeeded, false if it did not
*/ */
static function register($user, $username, $provider_name) public static function register($user, $username, $provider_name)
{ {
$user_username = new User_username(); $user_username = new User_username();
$user_username->user_id = $user->id; $user_username->user_id = $user->id;
@ -54,9 +71,9 @@ class User_username extends Managed_DataObject
$user_username->username = $username; $user_username->username = $username;
$user_username->created = common_sql_now(); $user_username->created = common_sql_now();
if($user_username->insert()){ if ($user_username->insert()) {
return $user_username; return $user_username;
}else{ } else {
return false; return false;
} }
} }

View File

@ -1,13 +1,23 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* *
* Some notes... * Some notes...
* *
* Drupal docs don't list a bool type, but it might be nice to use rather than 'tinyint'
* Note however that we use bitfields and things as well in tinyints, and PG's
* "bool" type isn't 100% compatible with 0/1 checks. Just keeping tinyints. :)
*
* decimal <-> numeric * decimal <-> numeric
* *
* MySQL 'timestamp' columns were formerly used for 'modified' files for their * MySQL 'timestamp' columns were formerly used for 'modified' files for their
@ -29,24 +39,29 @@
* double-check what we've been doing on postgres? * double-check what we've been doing on postgres?
*/ */
$classes = array('Schema_version', defined('GNUSOCIAL') || die();
$classes = [
'Schema_version',
'Profile', 'Profile',
'Avatar', 'Avatar',
'Sms_carrier', 'Sms_carrier',
'User', 'User',
'User_group',
'Subscription', 'Subscription',
'Group_join_queue', 'Group_join_queue',
'Subscription_queue', 'Subscription_queue',
'Consumer',
'Oauth_application',
'Oauth_token_association', 'Oauth_token_association',
'Conversation',
'Notice', 'Notice',
'Notice_location', 'Notice_location',
'Notice_source', 'Notice_source',
'Notice_prefs', 'Notice_prefs',
'Reply', 'Reply',
'Consumer',
'Token', 'Token',
'Nonce', 'Nonce',
'Oauth_application',
'Oauth_application_user', 'Oauth_application_user',
'Confirm_address', 'Confirm_address',
'Remember_me', 'Remember_me',
@ -58,11 +73,10 @@ $classes = array('Schema_version',
'Foreign_subscription', 'Foreign_subscription',
'Invitation', 'Invitation',
'Profile_prefs', 'Profile_prefs',
'Profile_tag',
'Profile_list', 'Profile_list',
'Profile_tag',
'Profile_tag_subscription', 'Profile_tag_subscription',
'Profile_block', 'Profile_block',
'User_group',
'Related_group', 'Related_group',
'Group_inbox', 'Group_inbox',
'Group_member', 'Group_member',
@ -79,14 +93,13 @@ $classes = array('Schema_version',
'Login_token', 'Login_token',
'User_location_prefs', 'User_location_prefs',
'User_im_prefs', 'User_im_prefs',
'Conversation',
'Local_group', 'Local_group',
'User_urlshortener_prefs', 'User_urlshortener_prefs',
'Old_school_prefs', 'Old_school_prefs',
'User_username', 'User_username',
'Attention', 'Attention'
); ];
foreach ($classes as $cls) { foreach ($classes as $cls) {
$schema[strtolower($cls)] = call_user_func(array($cls, 'schemaDef')); $schema[strtolower($cls)] = call_user_func([$cls, 'schemaDef']);
} }

View File

@ -36,7 +36,7 @@ VALUES
(100088, 'Orange (Poland)', '%s@orange.pl', now()), (100088, 'Orange (Poland)', '%s@orange.pl', now()),
(100089, 'Personal (Argentina)', '%s@personal-net.com.ar', now()), (100089, 'Personal (Argentina)', '%s@personal-net.com.ar', now()),
(100090, 'Plus GSM (Poland)', '%s@text.plusgsm.pl', now()), (100090, 'Plus GSM (Poland)', '%s@text.plusgsm.pl', now()),
(100091, 'President\'s Choice (Canada)', '%s@txt.bell.ca', now()), (100091, 'President''s Choice (Canada)', '%s@txt.bell.ca', now()),
(100092, 'Qwest', '%s@qwestmp.com', now()), (100092, 'Qwest', '%s@qwestmp.com', now()),
(100093, 'Rogers (Canada)', '%s@pcs.rogers.com', now()), (100093, 'Rogers (Canada)', '%s@pcs.rogers.com', now()),
(100094, 'Sasktel (Canada)', '%s@sms.sasktel.com', now()), (100094, 'Sasktel (Canada)', '%s@sms.sasktel.com', now()),

View File

@ -1787,12 +1787,34 @@ class DB_DataObject extends DB_DataObject_Overload
// note: we dont declare this to keep the print_r size down. // note: we dont declare this to keep the print_r size down.
$_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid] = array_flip(array_keys($array)); $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid] = array_flip(array_keys($array));
} }
$dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'];
if ($dbtype === 'pgsql') {
if (($_DB_DATAOBJECT['CONFIG']['db_driver'] ?? 'DB') === 'DB') {
$tableInfo = $result->tableInfo();
} elseif ($result->db->supports('result_introspection')) { // MDB2
$result->db->loadModule('Reverse', null, true);
$tableInfo = $result->db->reverse->tableInfo($result);
}
}
$replace = array('.', ' '); $replace = array('.', ' ');
foreach ($array as $k => $v) { foreach (array_keys($array) as $i => $k) {
// use strpos as str_replace is slow. // use strpos as str_replace is slow.
$kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ? $kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ?
$k : str_replace($replace, '_', $k); $k : str_replace($replace, '_', $k);
if ($dbtype === 'pgsql') {
switch ($tableInfo[$i]['type']) {
case 'bool':
$array[$k] = str_replace(['t', 'f'], ['1', '0'], $array[$k]);
break;
case 'bytea':
$array[$k] = pg_unescape_bytea($array[$k]);
break;
}
}
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
$this->debug("$kk = " . $array[$k], "fetchrow LINE", 3); $this->debug("$kk = " . $array[$k], "fetchrow LINE", 3);
} }
@ -2418,7 +2440,7 @@ class DB_DataObject extends DB_DataObject_Overload
case 'pgsql': case 'pgsql':
if (!$seq) { if (!$seq) {
$seq = $DB->getSequenceName(strtolower($this->tableName())); $seq = $DB->getSequenceName(strtolower($this->tableName() . '_' . $key));
} }
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver']; $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
$method = ($db_driver == 'DB') ? 'getOne' : 'queryOne'; $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
@ -2949,12 +2971,34 @@ class DB_DataObject extends DB_DataObject_Overload
$this->raiseError("fetchrow: No results available", DB_DATAOBJECT_ERROR_NODATA); $this->raiseError("fetchrow: No results available", DB_DATAOBJECT_ERROR_NODATA);
return false; return false;
} }
$dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype'];
if ($dbtype === 'pgsql') {
if (($_DB_DATAOBJECT['CONFIG']['db_driver'] ?? 'DB') === 'DB') {
$tableInfo = $result->tableInfo();
} elseif ($result->db->supports('result_introspection')) { // MDB2
$result->db->loadModule('Reverse', null, true);
$tableInfo = $result->db->reverse->tableInfo($result);
}
}
$replace = array('.', ' '); $replace = array('.', ' ');
foreach ($array as $k => $v) { foreach (array_keys($array) as $i => $k) {
// use strpos as str_replace is slow. // use strpos as str_replace is slow.
$kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ? $kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ?
$k : str_replace($replace, '_', $k); $k : str_replace($replace, '_', $k);
if ($dbtype === 'pgsql') {
switch ($tableInfo[$i]['type']) {
case 'bool':
$array[$k] = str_replace(['t', 'f'], ['1', '0'], $array[$k]);
break;
case 'bytea':
$array[$k] = pg_unescape_bytea($array[$k]);
break;
}
}
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) { if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
$this->debug("$kk = " . $array[$k], "fetchrow LINE", 3); $this->debug("$kk = " . $array[$k], "fetchrow LINE", 3);
} }

View File

@ -1,36 +1,31 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Base class for all actions (~views) * Base class for all actions (~views)
* *
* 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 Action * @category Action
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Sarven Capadisli <csarven@status.net> * @author Sarven Capadisli <csarven@status.net>
* @copyright 2008 StatusNet, Inc. * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Base class for all actions * Base class for all actions
@ -42,11 +37,8 @@ if (!defined('GNUSOCIAL')) {
* model classes to read and write to the database; and doing ouput. * model classes to read and write to the database; and doing ouput.
* *
* @category Output * @category Output
* @package StatusNet * @copyright 2008 StatusNet, Inc.
* @author Evan Prodromou <evan@status.net> * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @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 HTMLOutputter * @see HTMLOutputter
*/ */
@ -1566,19 +1558,6 @@ class Action extends HTMLOutputter // lawsuit
// needs to be defined by the class // needs to be defined by the class
} }
/**
* This is a cheap hack to avoid a bug in DB_DataObject
* where '' is non-type-aware compared to 0, which means it
* will always be true for values like false and 0 too...
*
* Upstream bug is::
* https://pear.php.net/bugs/bug.php?id=20291
*/
public function booleanintstring($key, $def = false)
{
return $this->boolean($key, $def) ? '1' : '0';
}
/** /**
* Integer value of an argument * Integer value of an argument
* *

View File

@ -38,21 +38,20 @@ defined('GNUSOCIAL') || die();
*/ */
class MysqlSchema extends Schema class MysqlSchema extends Schema
{ {
static $_single = null; public static $_single = null;
protected $conn = null;
/** /**
* Main public entry point. Use this to get * Main public entry point. Use this to get
* the singleton object. * the singleton object.
* *
* @param null $conn * @param object|null $conn
* @param string|null dummy param
* @return Schema the (single) Schema object * @return Schema the (single) Schema object
*/ */
public static function get($conn = null, $_ = 'mysql')
static function get($conn = null)
{ {
if (empty(self::$_single)) { if (empty(self::$_single)) {
self::$_single = new Schema($conn); self::$_single = new Schema($conn, 'mysql');
} }
return self::$_single; return self::$_single;
} }
@ -69,7 +68,6 @@ class MysqlSchema extends Schema
* @throws PEAR_Exception * @throws PEAR_Exception
* @throws SchemaTableMissingException * @throws SchemaTableMissingException
*/ */
public function getTableDef($table) public function getTableDef($table)
{ {
$def = []; $def = [];
@ -82,7 +80,6 @@ class MysqlSchema extends Schema
} }
foreach ($columns as $row) { foreach ($columns as $row) {
$name = $row['COLUMN_NAME']; $name = $row['COLUMN_NAME'];
$field = []; $field = [];
@ -109,14 +106,16 @@ class MysqlSchema extends Schema
$field['not null'] = true; $field['not null'] = true;
} }
if ($row['COLUMN_DEFAULT'] !== null) { if ($row['COLUMN_DEFAULT'] !== null) {
// Hack for timestamp cols // Hack for timestamp columns
if ($type == 'timestamp' && $row['COLUMN_DEFAULT'] == 'CURRENT_TIMESTAMP') { if ($row['COLUMN_DEFAULT'] === 'current_timestamp()') {
// skip because timestamp is numerical, but it accepts datetime strings as well // skip timestamp columns as they get a CURRENT_TIMESTAMP default implicitly
if ($type !== 'timestamp') {
$field['default'] = 'CURRENT_TIMESTAMP';
}
} elseif ($this->isNumericType($type)) {
$field['default'] = intval($row['COLUMN_DEFAULT']);
} else { } else {
$field['default'] = $row['COLUMN_DEFAULT']; $field['default'] = $row['COLUMN_DEFAULT'];
if ($this->isNumericType($type)) {
$field['default'] = intval($field['default']);
}
} }
} }
if ($row['COLUMN_KEY'] !== null) { if ($row['COLUMN_KEY'] !== null) {
@ -166,9 +165,9 @@ class MysqlSchema extends Schema
if ($name == 'PRIMARY') { if ($name == 'PRIMARY') {
$type = 'primary key'; $type = 'primary key';
} else if ($row['Non_unique'] == 0) { } elseif ($row['Non_unique'] == 0) {
$type = 'unique keys'; $type = 'unique keys';
} else if ($row['Index_type'] == 'FULLTEXT') { } elseif ($row['Index_type'] === 'FULLTEXT') {
$type = 'fulltext indexes'; $type = 'fulltext indexes';
} else { } else {
$type = 'indexes'; $type = 'indexes';
@ -198,8 +197,7 @@ class MysqlSchema extends Schema
* @throws PEAR_Exception * @throws PEAR_Exception
* @throws SchemaTableMissingException * @throws SchemaTableMissingException
*/ */
public function getTableProperties($table, $props)
function getTableProperties($table, $props)
{ {
$data = $this->fetchMetaInfo($table, 'TABLES'); $data = $this->fetchMetaInfo($table, 'TABLES');
if ($data) { if ($data) {
@ -218,7 +216,7 @@ class MysqlSchema extends Schema
* @return array of arrays * @return array of arrays
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function fetchMetaInfo($table, $infoTable, $orderBy = null) public function fetchMetaInfo($table, $infoTable, $orderBy = null)
{ {
$query = "SELECT * FROM INFORMATION_SCHEMA.%s " . $query = "SELECT * FROM INFORMATION_SCHEMA.%s " .
"WHERE TABLE_SCHEMA='%s' AND TABLE_NAME='%s'"; "WHERE TABLE_SCHEMA='%s' AND TABLE_NAME='%s'";
@ -237,7 +235,7 @@ class MysqlSchema extends Schema
* @return array of arrays * @return array of arrays
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function fetchIndexInfo($table) public function fetchIndexInfo($table)
{ {
$query = "SHOW INDEX FROM `%s`"; $query = "SHOW INDEX FROM `%s`";
$sql = sprintf($query, $table); $sql = sprintf($query, $table);
@ -253,7 +251,7 @@ class MysqlSchema extends Schema
* @param string $name * @param string $name
* @param array $def * @param array $def
*/ */
function appendCreateFulltextIndex(array &$statements, $table, $name, array $def) public function appendCreateFulltextIndex(array &$statements, $table, $name, array $def)
{ {
$statements[] = "CREATE FULLTEXT INDEX $name ON $table " . $this->buildIndexList($def); $statements[] = "CREATE FULLTEXT INDEX $name ON $table " . $this->buildIndexList($def);
} }
@ -266,13 +264,13 @@ class MysqlSchema extends Schema
* @return string; * @return string;
* *
*/ */
function endCreateTable($name, array $def) public function endCreateTable($name, array $def)
{ {
$engine = $this->preferredEngine($def); $engine = $this->preferredEngine($def);
return ") ENGINE=$engine CHARACTER SET utf8mb4 COLLATE utf8mb4_bin"; return ") ENGINE=$engine CHARACTER SET utf8mb4 COLLATE utf8mb4_bin";
} }
function preferredEngine($def) public function preferredEngine($def)
{ {
/* MyISAM is no longer required for fulltext indexes, fortunately /* MyISAM is no longer required for fulltext indexes, fortunately
if (!empty($def['fulltext indexes'])) { if (!empty($def['fulltext indexes'])) {
@ -288,7 +286,7 @@ class MysqlSchema extends Schema
* @param $columnName * @param $columnName
* @return string * @return string
*/ */
function _uniqueKey($tableName, $columnName) public function _uniqueKey($tableName, $columnName)
{ {
return $this->_key($tableName, $columnName); return $this->_key($tableName, $columnName);
} }
@ -299,7 +297,7 @@ class MysqlSchema extends Schema
* @param $columnName * @param $columnName
* @return string * @return string
*/ */
function _key($tableName, $columnName) public function _key($tableName, $columnName)
{ {
return "{$tableName}_{$columnName}_idx"; return "{$tableName}_{$columnName}_idx";
} }
@ -310,7 +308,7 @@ class MysqlSchema extends Schema
* *
* @param array $phrase * @param array $phrase
*/ */
function appendAlterDropPrimary(array &$phrase) public function appendAlterDropPrimary(array &$phrase, string $tableName)
{ {
$phrase[] = 'DROP PRIMARY KEY'; $phrase[] = 'DROP PRIMARY KEY';
} }
@ -322,7 +320,7 @@ class MysqlSchema extends Schema
* @param array $phrase * @param array $phrase
* @param string $keyName MySQL * @param string $keyName MySQL
*/ */
function appendAlterDropUnique(array &$phrase, $keyName) public function appendAlterDropUnique(array &$phrase, $keyName)
{ {
$phrase[] = 'DROP INDEX ' . $keyName; $phrase[] = 'DROP INDEX ' . $keyName;
} }
@ -335,7 +333,7 @@ class MysqlSchema extends Schema
* @param array $def * @param array $def
* @throws Exception * @throws Exception
*/ */
function appendAlterExtras(array &$phrase, $tableName, array $def) public function appendAlterExtras(array &$phrase, $tableName, array $def)
{ {
// Check for table properties: make sure we're using a sane // Check for table properties: make sure we're using a sane
// engine type and charset/collation. // engine type and charset/collation.
@ -370,15 +368,15 @@ class MysqlSchema extends Schema
* Appropriate for use in CREATE TABLE or * Appropriate for use in CREATE TABLE or
* ALTER TABLE statements. * ALTER TABLE statements.
* *
* @param string $name column name to create
* @param array $cd column to create * @param array $cd column to create
* *
* @return string correct SQL for that column * @return string correct SQL for that column
*/ */
public function columnSql(string $name, array $cd)
function columnSql(array $cd)
{ {
$line = []; $line = [];
$line[] = parent::columnSql($cd); $line[] = parent::columnSql($name, $cd);
// This'll have been added from our transform of 'serial' type // This'll have been added from our transform of 'serial' type
if (!empty($cd['auto_increment'])) { if (!empty($cd['auto_increment'])) {
@ -393,12 +391,12 @@ class MysqlSchema extends Schema
return implode(' ', $line); return implode(' ', $line);
} }
function mapType($column) public function mapType($column)
{ {
$map = [ $map = [
'serial' => 'int',
'integer' => 'int', 'integer' => 'int',
'numeric' => 'decimal' 'bool' => 'tinyint',
'numeric' => 'decimal',
]; ];
$type = $column['type']; $type = $column['type'];
@ -411,7 +409,9 @@ class MysqlSchema extends Schema
if ($type == 'int' && if ($type == 'int' &&
in_array($size, ['tiny', 'small', 'medium', 'big'])) { in_array($size, ['tiny', 'small', 'medium', 'big'])) {
$type = $size . $type; $type = $size . $type;
} else if (in_array($type, ['blob', 'text']) && } elseif ($type == 'float' && $size == 'big') {
$type = 'double';
} elseif (in_array($type, ['blob', 'text']) &&
in_array($size, ['tiny', 'medium', 'long'])) { in_array($size, ['tiny', 'medium', 'long'])) {
$type = $size . $type; $type = $size . $type;
} }
@ -420,13 +420,15 @@ class MysqlSchema extends Schema
return $type; return $type;
} }
function typeAndSize($column) public function typeAndSize(string $name, array $column)
{ {
if ($column['type'] == 'enum') { if ($column['type'] === 'enum') {
$vals = array_map([$this, 'quote'], $column['enum']); foreach ($column['enum'] as &$val) {
$vals[] = "'" . $val . "'";
}
return 'enum(' . implode(',', $vals) . ')'; return 'enum(' . implode(',', $vals) . ')';
} else if ($this->_isString($column)) { } elseif ($this->_isString($column)) {
$col = parent::typeAndSize($column); $col = parent::typeAndSize($name, $column);
if (!empty($column['charset'])) { if (!empty($column['charset'])) {
$col .= ' CHARSET ' . $column['charset']; $col .= ' CHARSET ' . $column['charset'];
} }
@ -435,7 +437,7 @@ class MysqlSchema extends Schema
} }
return $col; return $col;
} else { } else {
return parent::typeAndSize($column); return parent::typeAndSize($name, $column);
} }
} }
@ -449,7 +451,7 @@ class MysqlSchema extends Schema
* @param array $tableDef * @param array $tableDef
* @return array * @return array
*/ */
function filterDef(array $tableDef) public function filterDef(array $tableDef)
{ {
$version = $this->conn->getVersion(); $version = $this->conn->getVersion();
foreach ($tableDef['fields'] as $name => &$col) { foreach ($tableDef['fields'] as $name => &$col) {

View File

@ -40,6 +40,23 @@ defined('GNUSOCIAL') || die();
*/ */
class PgsqlSchema extends Schema class PgsqlSchema extends Schema
{ {
public static $_single = null;
/**
* Main public entry point. Use this to get
* the singleton object.
*
* @param object|null $conn
* @param string|null dummy param
* @return Schema the (single) Schema object
*/
public static function get($conn = null, $_ = 'pgsql')
{
if (empty(self::$_single)) {
self::$_single = new Schema($conn, 'pgsql');
}
return self::$_single;
}
/** /**
* Returns a table definition array for the table * Returns a table definition array for the table
@ -52,7 +69,6 @@ class PgsqlSchema extends Schema
* @return array tabledef for that table. * @return array tabledef for that table.
* @throws SchemaTableMissingException * @throws SchemaTableMissingException
*/ */
public function getTableDef($table) public function getTableDef($table)
{ {
$def = []; $def = [];
@ -68,14 +84,13 @@ class PgsqlSchema extends Schema
$orderedFields = []; $orderedFields = [];
foreach ($columns as $row) { foreach ($columns as $row) {
$name = $row['column_name']; $name = $row['column_name'];
$orderedFields[$row['ordinal_position']] = $name; $orderedFields[$row['ordinal_position']] = $name;
$field = []; $field = [];
$field['type'] = $type = $row['udt_name']; $field['type'] = $type = $row['udt_name'];
if ($type == 'char' || $type == 'varchar') { if (in_array($type, ['char', 'bpchar', 'varchar'])) {
if ($row['character_maximum_length'] !== null) { if ($row['character_maximum_length'] !== null) {
$field['length'] = intval($row['character_maximum_length']); $field['length'] = intval($row['character_maximum_length']);
} }
@ -106,7 +121,8 @@ class PgsqlSchema extends Schema
// Pulling index info from pg_class & pg_index // Pulling index info from pg_class & pg_index
// This can give us primary & unique key info, but not foreign key constraints // This can give us primary & unique key info, but not foreign key constraints
// so we exclude them and pick them up later. // so we exclude them and pick them up later.
$indexInfo = $this->getIndexInfo($table); $indexInfo = $this->fetchIndexInfo($table);
foreach ($indexInfo as $row) { foreach ($indexInfo as $row) {
$keyName = $row['key_name']; $keyName = $row['key_name'];
@ -146,8 +162,8 @@ class PgsqlSchema extends Schema
// name hack -- is this reliable? // name hack -- is this reliable?
if ($keyName == "{$table}_pkey") { if ($keyName == "{$table}_pkey") {
$def['primary key'] = $cols; $def['primary key'] = $cols;
} else if (preg_match("/^{$table}_(.*)_fkey$/", $keyName, $matches)) { } elseif (preg_match("/^{$table}_(.*)_fkey$/", $keyName, $matches)) {
$fkey = $this->getForeignKeyInfo($table, $keyName); $fkey = $this->fetchForeignKeyInfo($table, $keyName);
$colMap = array_combine($cols, $fkey['col_names']); $colMap = array_combine($cols, $fkey['col_names']);
$def['foreign keys'][$keyName] = [$fkey['table_name'], $colMap]; $def['foreign keys'][$keyName] = [$fkey['table_name'], $colMap];
} else { } else {
@ -166,7 +182,7 @@ class PgsqlSchema extends Schema
* @return array of arrays * @return array of arrays
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function fetchMetaInfo($table, $infoTable, $orderBy = null) public function fetchMetaInfo($table, $infoTable, $orderBy = null)
{ {
$query = "SELECT * FROM information_schema.%s " . $query = "SELECT * FROM information_schema.%s " .
"WHERE table_name='%s'"; "WHERE table_name='%s'";
@ -183,47 +199,42 @@ class PgsqlSchema extends Schema
* @return array of arrays * @return array of arrays
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function getIndexInfo($table) public function fetchIndexInfo(string $table): array
{ {
$query = 'SELECT ' . $query = 'SELECT indexname AS key_name, indexdef AS key_def, pg_index.* ' .
'(SELECT relname FROM pg_class WHERE oid=indexrelid) AS key_name, ' . 'FROM pg_index INNER JOIN pg_indexes ON pg_index.indexrelid = CAST(pg_indexes.indexname AS regclass) ' .
'* FROM pg_index ' . 'WHERE tablename = \'%s\' AND indisprimary = FALSE AND indisunique = FALSE ' .
'WHERE indrelid=(SELECT oid FROM pg_class WHERE relname=\'%s\') ' .
'AND indisprimary=\'f\' AND indisunique=\'f\' ' .
'ORDER BY indrelid, indexrelid'; 'ORDER BY indrelid, indexrelid';
$sql = sprintf($query, $table); $sql = sprintf($query, $table);
return $this->fetchQueryData($sql); return $this->fetchQueryData($sql);
} }
/** /**
* Column names from the foreign table can be resolved with a call to getTableColumnNames()
* @param string $table * @param string $table
* @param $constraint_name * @param string $constraint_name
* @return array array of rows with keys: fkey_name, table_name, table_id, col_names (array of strings) * @return array array of rows with keys: table_name, col_names (array of strings)
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function getForeignKeyInfo($table, $constraint_name) public function fetchForeignKeyInfo(string $table, string $constraint_name): array
{ {
// In a sane world, it'd be easier to query the column names directly. // In a sane world, it'd be easier to query the column names directly.
// But it's pretty hard to work with arrays such as col_indexes in direct SQL here. // But it's pretty hard to work with arrays such as col_indexes in direct SQL here.
$query = 'SELECT ' . $query = 'SELECT ' .
'(SELECT relname FROM pg_class WHERE oid=confrelid) AS table_name, ' . '(SELECT relname FROM pg_class WHERE oid = confrelid) AS table_name, ' .
'confrelid AS table_id, ' . 'confrelid AS table_id, ' .
'(SELECT indkey FROM pg_index WHERE indexrelid=conindid) AS col_indexes ' . '(SELECT indkey FROM pg_index WHERE indexrelid = conindid) AS col_indices ' .
'FROM pg_constraint ' . 'FROM pg_constraint ' .
'WHERE conrelid=(SELECT oid FROM pg_class WHERE relname=\'%s\') ' . 'WHERE conrelid = CAST(\'%s\' AS regclass) AND conname = \'%s\' AND contype = \'f\'';
'AND conname=\'%s\' ' .
'AND contype=\'f\'';
$sql = sprintf($query, $table, $constraint_name); $sql = sprintf($query, $table, $constraint_name);
$data = $this->fetchQueryData($sql); $data = $this->fetchQueryData($sql);
if (count($data) < 1) { if (count($data) < 1) {
throw new Exception("Could not find foreign key " . $constraint_name . " on table " . $table); throw new Exception('Could not find foreign key ' . $constraint_name . ' on table ' . $table);
} }
$row = $data[0]; $row = $data[0];
return [ return [
'table_name' => $row['table_name'], 'table_name' => $row['table_name'],
'col_names' => $this->getTableColumnNames($row['table_id'], $row['col_indexes']) 'col_names' => $this->getTableColumnNames($row['table_id'], $row['col_indices'])
]; ];
} }
@ -234,7 +245,7 @@ class PgsqlSchema extends Schema
* @return array of strings * @return array of strings
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function getTableColumnNames($table_id, $col_indexes) public function getTableColumnNames($table_id, $col_indexes)
{ {
$indexes = array_map('intval', explode(' ', $col_indexes)); $indexes = array_map('intval', explode(' ', $col_indexes));
$query = 'SELECT attnum AS col_index, attname AS col_name ' . $query = 'SELECT attnum AS col_index, attname AS col_name ' .
@ -255,23 +266,6 @@ class PgsqlSchema extends Schema
return $out; return $out;
} }
/**
* Translate the (mostly) mysql-ish column types into somethings more standard
* @param string column type
*
* @return string postgres happy column type
*/
private function _columnTypeTranslation($type)
{
$map = [
'datetime' => 'timestamp',
];
if (!empty($map[$type])) {
return $map[$type];
}
return $type;
}
/** /**
* Return the proper SQL for creating or * Return the proper SQL for creating or
* altering a column. * altering a column.
@ -279,15 +273,15 @@ class PgsqlSchema extends Schema
* Appropriate for use in CREATE TABLE or * Appropriate for use in CREATE TABLE or
* ALTER TABLE statements. * ALTER TABLE statements.
* *
* @param string $name column name to create
* @param array $cd column to create * @param array $cd column to create
* *
* @return string correct SQL for that column * @return string correct SQL for that column
*/ */
public function columnSql(string $name, array $cd)
function columnSql(array $cd)
{ {
$line = []; $line = [];
$line[] = parent::columnSql($cd); $line[] = parent::columnSql($name, $cd);
/* /*
if ($table['foreign keys'][$name]) { if ($table['foreign keys'][$name]) {
@ -299,6 +293,16 @@ class PgsqlSchema extends Schema
} }
*/ */
// This'll have been added from our transform of 'serial' type
if (!empty($cd['auto_increment'])) {
$line[] = 'GENERATED BY DEFAULT AS IDENTITY';
} elseif (!empty($cd['enum'])) {
foreach ($cd['enum'] as &$val) {
$vals[] = "'" . $val . "'";
}
$line[] = 'CHECK (' . $name . ' IN (' . implode(',', $vals) . '))';
}
return implode(' ', $line); return implode(' ', $line);
} }
@ -311,29 +315,35 @@ class PgsqlSchema extends Schema
* @param array $old previous column definition as found in DB * @param array $old previous column definition as found in DB
* @param array $cd current column definition * @param array $cd current column definition
*/ */
function appendAlterModifyColumn(array &$phrase, $columnName, array $old, array $cd) public function appendAlterModifyColumn(array &$phrase, $columnName, array $old, array $cd)
{ {
$prefix = 'ALTER COLUMN ' . $this->quoteIdentifier($columnName) . ' '; $prefix = 'ALTER COLUMN ' . $this->quoteIdentifier($columnName) . ' ';
$oldType = $this->mapType($old); $oldType = $this->typeAndSize($columnName, $old);
$newType = $this->mapType($cd); $newType = $this->typeAndSize($columnName, $cd);
if ($oldType != $newType) { if ($oldType != $newType) {
$phrase[] = $prefix . 'TYPE ' . $newType; $phrase[] = $prefix . 'TYPE ' . $newType;
} }
if (!empty($old['not null']) && empty($cd['not null'])) { if (!empty($old['not null']) && empty($cd['not null'])) {
$phrase[] = $prefix . 'DROP NOT NULL'; $phrase[] = $prefix . 'DROP NOT NULL';
} else if (empty($old['not null']) && !empty($cd['not null'])) { } elseif (empty($old['not null']) && !empty($cd['not null'])) {
$phrase[] = $prefix . 'SET NOT NULL'; $phrase[] = $prefix . 'SET NOT NULL';
} }
if (isset($old['default']) && !isset($cd['default'])) { if (isset($old['default']) && !isset($cd['default'])) {
$phrase[] = $prefix . 'DROP DEFAULT'; $phrase[] = $prefix . 'DROP DEFAULT';
} else if (!isset($old['default']) && isset($cd['default'])) { } elseif (!isset($old['default']) && isset($cd['default'])) {
$phrase[] = $prefix . 'SET DEFAULT ' . $this->quoteDefaultValue($cd); $phrase[] = $prefix . 'SET DEFAULT ' . $this->quoteDefaultValue($cd);
} }
} }
public function appendAlterDropPrimary(array &$phrase, string $tableName)
{
// name hack -- is this reliable?
$phrase[] = 'DROP CONSTRAINT ' . $this->quoteIdentifier($tableName . '_pkey');
}
/** /**
* Append an SQL statement to drop an index from a table. * Append an SQL statement to drop an index from a table.
* Note that in PostgreSQL, index names are DB-unique. * Note that in PostgreSQL, index names are DB-unique.
@ -342,29 +352,19 @@ class PgsqlSchema extends Schema
* @param string $table * @param string $table
* @param string $name * @param string $name
*/ */
function appendDropIndex(array &$statements, $table, $name) public function appendDropIndex(array &$statements, $table, $name)
{ {
$statements[] = "DROP INDEX $name"; $statements[] = "DROP INDEX $name";
} }
/** public function mapType($column)
* Quote a db/table/column identifier if necessary.
*
* @param string $name
* @return string
*/
function quoteIdentifier($name)
{
return $this->conn->quoteIdentifier($name);
}
function mapType($column)
{ {
$map = [ $map = [
'serial' => 'bigserial', // FIXME: creates the wrong name for the sequence for some internal sequence-lookup function, so better fix this to do the real 'create sequence' dance. 'integer' => 'int',
'numeric' => 'decimal', 'char' => 'bpchar',
'datetime' => 'timestamp', 'datetime' => 'timestamp',
'blob' => 'bytea' 'blob' => 'bytea',
'enum' => 'text',
]; ];
$type = $column['type']; $type = $column['type'];
@ -372,32 +372,22 @@ class PgsqlSchema extends Schema
$type = $map[$type]; $type = $map[$type];
} }
if ($type == 'int') { $size = $column['size'] ?? null;
if (!empty($column['size'])) { if ($type === 'int') {
$size = $column['size']; if (in_array($size, ['tiny', 'small'])) {
if ($size == 'small') { $type = 'int2';
return 'int2'; } elseif ($size === 'big') {
} else if ($size == 'big') { $type = 'int8';
return 'int8'; } else {
$type = 'int4';
} }
} } elseif ($type === 'float') {
return 'int4'; $type = ($size !== 'big') ? 'float4' : 'float8';
} }
return $type; return $type;
} }
// @fixme need name... :P
function typeAndSize($column)
{
if ($column['type'] == 'enum') {
$vals = array_map([$this, 'quote'], $column['enum']);
return "text check ($name in " . implode(',', $vals) . ')';
} else {
return parent::typeAndSize($column);
}
}
/** /**
* Filter the given table definition array to match features available * Filter the given table definition array to match features available
* in this database. * in this database.
@ -408,23 +398,39 @@ class PgsqlSchema extends Schema
* @param array $tableDef * @param array $tableDef
* @return array * @return array
*/ */
function filterDef(array $tableDef) public function filterDef(array $tableDef)
{ {
foreach ($tableDef['fields'] as $name => &$col) { foreach ($tableDef['fields'] as $name => &$col) {
// No convenient support for field descriptions // No convenient support for field descriptions
unset($col['description']); unset($col['description']);
/* switch ($col['type']) {
if (isset($col['size'])) { case 'serial':
// Don't distinguish between tinyint and int. $col['type'] = 'int';
if ($col['size'] == 'tiny' && $col['type'] == 'int') { $col['auto_increment'] = true;
unset($col['size']); break;
case 'datetime':
// Replace archaic MySQL-specific zero-dates with NULL
if (($col['default'] ?? null) === '0000-00-00 00:00:00') {
$col['default'] = null;
$col['not null'] = false;
} }
break;
case 'timestamp':
// In MariaDB: If the column does not permit NULL values,
// assigning NULL (or not referencing the column at all
// when inserting) will set the column to CURRENT_TIMESTAMP
// FIXME: ON UPDATE CURRENT_TIMESTAMP
if ($col['not null'] && !isset($col['default'])) {
$col['default'] = 'CURRENT_TIMESTAMP';
} }
*/ break;
}
$col['type'] = $this->mapType($col); $col['type'] = $this->mapType($col);
unset($col['size']); unset($col['size']);
} }
if (!empty($tableDef['primary key'])) { if (!empty($tableDef['primary key'])) {
$tableDef['primary key'] = $this->filterKeyDef($tableDef['primary key']); $tableDef['primary key'] = $this->filterKeyDef($tableDef['primary key']);
} }
@ -443,7 +449,7 @@ class PgsqlSchema extends Schema
* @param array $def * @param array $def
* @return array * @return array
*/ */
function filterKeyDef(array $def) public function filterKeyDef(array $def)
{ {
// PostgreSQL doesn't like prefix lengths specified on keys...? // PostgreSQL doesn't like prefix lengths specified on keys...?
foreach ($def as $i => $item) { foreach ($def as $i => $item) {

View File

@ -39,14 +39,13 @@ defined('GNUSOCIAL') || die();
*/ */
class Schema class Schema
{ {
static $_static = null; public static $_static = null;
protected $conn = null; protected $conn = null;
/** /**
* Constructor. Only run once for singleton object. * Constructor. Only run once for singleton object.
* @param null $conn * @param null $conn
*/ */
protected function __construct($conn = null) protected function __construct($conn = null)
{ {
if (is_null($conn)) { if (is_null($conn)) {
@ -64,11 +63,11 @@ class Schema
* Main public entry point. Use this to get * Main public entry point. Use this to get
* the schema object. * the schema object.
* *
* @param null $conn * @param object|null $conn
* @param string|null Force a database type (necessary for installation purposes in which we don't have a config.php)
* @return Schema the Schema object for the connection * @return Schema the Schema object for the connection
*/ */
public static function get($conn = null, $dbtype = null)
static function get($conn = null)
{ {
if (is_null($conn)) { if (is_null($conn)) {
$key = 'default'; $key = 'default';
@ -76,9 +75,11 @@ class Schema
$key = md5(serialize($conn->dsn)); $key = md5(serialize($conn->dsn));
} }
$type = common_config('db', 'type'); if (is_null($dbtype)) {
$dbtype = common_config('db', 'type');
}
if (empty(self::$_static[$key])) { if (empty(self::$_static[$key])) {
$schemaClass = ucfirst($type) . 'Schema'; $schemaClass = ucfirst($dbtype) . 'Schema';
self::$_static[$key] = new $schemaClass($conn); self::$_static[$key] = new $schemaClass($conn);
} }
return self::$_static[$key]; return self::$_static[$key];
@ -95,7 +96,6 @@ class Schema
* @return ColumnDef definition of the column or null * @return ColumnDef definition of the column or null
* if not found. * if not found.
*/ */
public function getColumnDef($table, $column) public function getColumnDef($table, $column)
{ {
$td = $this->getTableDef($table); $td = $this->getTableDef($table);
@ -120,7 +120,6 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function createTable($tableName, $def) public function createTable($tableName, $def)
{ {
$statements = $this->buildCreateTable($tableName, $def); $statements = $this->buildCreateTable($tableName, $def);
@ -194,7 +193,7 @@ class Schema
* @param array $def table definition * @param array $def table definition
* @return string * @return string
*/ */
function startCreateTable($name, array $def) public function startCreateTable($name, array $def)
{ {
return 'CREATE TABLE ' . $this->quoteIdentifier($name) . ' ('; return 'CREATE TABLE ' . $this->quoteIdentifier($name) . ' (';
} }
@ -206,7 +205,7 @@ class Schema
* @param array $def table definition * @param array $def table definition
* @return string * @return string
*/ */
function endCreateTable($name, array $def) public function endCreateTable($name, array $def)
{ {
return ')'; return ')';
} }
@ -218,9 +217,9 @@ class Schema
* @param string $name * @param string $name
* @param array $def * @param array $def
*/ */
function appendColumnDef(array &$sql, $name, array $def) public function appendColumnDef(array &$sql, string $name, array $def)
{ {
$sql[] = "$name " . $this->columnSql($def); $sql[] = $name . ' ' . $this->columnSql($name, $def);
} }
/** /**
@ -230,7 +229,7 @@ class Schema
* @param array $sql * @param array $sql
* @param array $def * @param array $def
*/ */
function appendPrimaryKeyDef(array &$sql, array $def) public function appendPrimaryKeyDef(array &$sql, array $def)
{ {
$sql[] = "PRIMARY KEY " . $this->buildIndexList($def); $sql[] = "PRIMARY KEY " . $this->buildIndexList($def);
} }
@ -243,7 +242,7 @@ class Schema
* @param string $name * @param string $name
* @param array $def * @param array $def
*/ */
function appendUniqueKeyDef(array &$sql, $name, array $def) public function appendUniqueKeyDef(array &$sql, $name, array $def)
{ {
$sql[] = "CONSTRAINT $name UNIQUE " . $this->buildIndexList($def); $sql[] = "CONSTRAINT $name UNIQUE " . $this->buildIndexList($def);
} }
@ -257,7 +256,7 @@ class Schema
* @param array $def * @param array $def
* @throws Exception * @throws Exception
*/ */
function appendForeignKeyDef(array &$sql, $name, array $def) public function appendForeignKeyDef(array &$sql, $name, array $def)
{ {
if (count($def) != 2) { if (count($def) != 2) {
throw new Exception("Invalid foreign key def for $name: " . var_export($def, true)); throw new Exception("Invalid foreign key def for $name: " . var_export($def, true));
@ -265,11 +264,11 @@ class Schema
list($refTable, $map) = $def; list($refTable, $map) = $def;
$srcCols = array_keys($map); $srcCols = array_keys($map);
$refCols = array_values($map); $refCols = array_values($map);
$sql[] = "CONSTRAINT $name FOREIGN KEY " . $sql[] = 'CONSTRAINT ' . $this->quoteIdentifier($name) . ' FOREIGN KEY ' .
$this->buildIndexList($srcCols) . $this->buildIndexList($srcCols) .
" REFERENCES " . ' REFERENCES ' .
$this->quoteIdentifier($refTable) . $this->quoteIdentifier($refTable) .
" " . ' ' .
$this->buildIndexList($refCols); $this->buildIndexList($refCols);
} }
@ -282,9 +281,10 @@ class Schema
* @param string $name * @param string $name
* @param array $def * @param array $def
*/ */
function appendCreateIndex(array &$statements, $table, $name, array $def) public function appendCreateIndex(array &$statements, $table, $name, array $def)
{ {
$statements[] = "CREATE INDEX $name ON $table " . $this->buildIndexList($def); $statements[] = 'CREATE INDEX ' . $name . ' ON ' .
$this->quoteIdentifier($table) . ' ' . $this->buildIndexList($def);
} }
/** /**
@ -297,7 +297,7 @@ class Schema
* @param array $def * @param array $def
* @throws Exception * @throws Exception
*/ */
function appendCreateFulltextIndex(array &$statements, $table, $name, array $def) public function appendCreateFulltextIndex(array &$statements, $table, $name, array $def)
{ {
throw new Exception("Fulltext index not supported in this database"); throw new Exception("Fulltext index not supported in this database");
} }
@ -309,18 +309,18 @@ class Schema
* @param string $table * @param string $table
* @param string $name * @param string $name
*/ */
function appendDropIndex(array &$statements, $table, $name) public function appendDropIndex(array &$statements, $table, $name)
{ {
$statements[] = "DROP INDEX $name ON " . $this->quoteIdentifier($table); $statements[] = "DROP INDEX $name ON " . $this->quoteIdentifier($table);
} }
function buildIndexList(array $def) public function buildIndexList(array $def)
{ {
// @fixme // @fixme
return '(' . implode(',', array_map([$this, 'buildIndexItem'], $def)) . ')'; return '(' . implode(',', array_map([$this, 'buildIndexItem'], $def)) . ')';
} }
function buildIndexItem($def) public function buildIndexItem($def)
{ {
if (is_array($def)) { if (is_array($def)) {
list($name, $size) = $def; list($name, $size) = $def;
@ -339,12 +339,11 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function dropTable($name) public function dropTable($name)
{ {
global $_PEAR; global $_PEAR;
$res = $this->conn->query("DROP TABLE $name"); $res = $this->conn->query('DROP TABLE ' . $this->quoteIdentifier($name));
if ($_PEAR->isError($res)) { if ($_PEAR->isError($res)) {
PEAR_ErrorToPEAR_Exception($res); PEAR_ErrorToPEAR_Exception($res);
@ -369,11 +368,12 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function createIndex($table, $columnNames, $name = null) public function createIndex($table, $columnNames, $name = null)
{ {
global $_PEAR; global $_PEAR;
$qry = [];
if (!is_array($columnNames)) { if (!is_array($columnNames)) {
$columnNames = [$columnNames]; $columnNames = [$columnNames];
} }
@ -382,9 +382,9 @@ class Schema
$name = "{$table}_" . implode("_", $columnNames) . "_idx"; $name = "{$table}_" . implode("_", $columnNames) . "_idx";
} }
$res = $this->conn->query("ALTER TABLE $table " . $this->appendCreateIndex($qry, $table, $name, $columnNames);
"ADD INDEX $name (" .
implode(",", $columnNames) . ")"); $res = $this->conn->query(implode('; ', $qry));
if ($_PEAR->isError($res)) { if ($_PEAR->isError($res)) {
PEAR_ErrorToPEAR_Exception($res); PEAR_ErrorToPEAR_Exception($res);
@ -402,12 +402,14 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function dropIndex($table, $name) public function dropIndex($table, $name)
{ {
global $_PEAR; global $_PEAR;
$res = $this->conn->query("ALTER TABLE $table DROP INDEX $name"); $res = $this->conn->query(
'ALTER TABLE ' . $this->quoteIdentifier($table) .
' DROP INDEX ' . $name
);
if ($_PEAR->isError($res)) { if ($_PEAR->isError($res)) {
PEAR_ErrorToPEAR_Exception($res); PEAR_ErrorToPEAR_Exception($res);
@ -426,12 +428,12 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function addColumn($table, $columndef) public function addColumn($table, $columndef)
{ {
global $_PEAR; global $_PEAR;
$sql = "ALTER TABLE $table ADD COLUMN " . $this->_columnSql($columndef); $sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
' ADD COLUMN ' . $this->columnSql($name, $columndef);
$res = $this->conn->query($sql); $res = $this->conn->query($sql);
@ -453,13 +455,12 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function modifyColumn($table, $columndef) public function modifyColumn($table, $columndef)
{ {
global $_PEAR; global $_PEAR;
$sql = "ALTER TABLE $table MODIFY COLUMN " . $sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
$this->_columnSql($columndef); ' MODIFY COLUMN ' . $this->columnSql($name, $columndef);
$res = $this->conn->query($sql); $res = $this->conn->query($sql);
@ -481,12 +482,12 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function dropColumn($table, $columnName) public function dropColumn($table, $columnName)
{ {
global $_PEAR; global $_PEAR;
$sql = "ALTER TABLE $table DROP COLUMN $columnName"; $sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
' DROP COLUMN ' . $columnName;
$res = $this->conn->query($sql); $res = $this->conn->query($sql);
@ -511,7 +512,6 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
public function ensureTable($tableName, $def) public function ensureTable($tableName, $def)
{ {
$statements = $this->buildEnsureTable($tableName, $def); $statements = $this->buildEnsureTable($tableName, $def);
@ -527,7 +527,7 @@ class Schema
* @return bool success flag * @return bool success flag
* @throws PEAR_Exception * @throws PEAR_Exception
*/ */
function runSqlSet(array $statements) public function runSqlSet(array $statements)
{ {
global $_PEAR; global $_PEAR;
@ -561,8 +561,7 @@ class Schema
* @return array of SQL statements * @return array of SQL statements
* @throws Exception * @throws Exception
*/ */
public function buildEnsureTable($tableName, array $def)
function buildEnsureTable($tableName, array $def)
{ {
try { try {
$old = $this->getTableDef($tableName); $old = $this->getTableDef($tableName);
@ -606,18 +605,24 @@ class Schema
} }
if (isset($old['primary key']) && (!isset($def['primary key']) || $def['primary key'] != $old['primary key'])) { if (isset($old['primary key']) && (!isset($def['primary key']) || $def['primary key'] != $old['primary key'])) {
$this->appendAlterDropPrimary($phrase); $this->appendAlterDropPrimary($phrase, $tableName);
} }
foreach ($fields['add'] as $columnName) { foreach ($fields['add'] as $columnName) {
$this->appendAlterAddColumn($phrase, $columnName, $this->appendAlterAddColumn(
$def['fields'][$columnName]); $phrase,
$columnName,
$def['fields'][$columnName]
);
} }
foreach ($fields['mod'] as $columnName) { foreach ($fields['mod'] as $columnName) {
$this->appendAlterModifyColumn($phrase, $columnName, $this->appendAlterModifyColumn(
$phrase,
$columnName,
$old['fields'][$columnName], $old['fields'][$columnName],
$def['fields'][$columnName]); $def['fields'][$columnName]
);
} }
foreach ($fields['del'] as $columnName) { foreach ($fields['del'] as $columnName) {
@ -639,7 +644,8 @@ class Schema
$this->appendAlterExtras($phrase, $tableName, $def); $this->appendAlterExtras($phrase, $tableName, $def);
if (count($phrase) > 0) { if (count($phrase) > 0) {
$sql = 'ALTER TABLE ' . $tableName . ' ' . implode(",\n", $phrase); $sql = 'ALTER TABLE ' . $this->quoteIdentifier($tableName) .
' ' . implode(",\n", $phrase);
$statements[] = $sql; $statements[] = $sql;
} }
@ -656,7 +662,7 @@ class Schema
return $statements; return $statements;
} }
function diffArrays($oldDef, $newDef, $section, $compareCallback = null) public function diffArrays($oldDef, $newDef, $section, $compareCallback = null)
{ {
$old = isset($oldDef[$section]) ? $oldDef[$section] : []; $old = isset($oldDef[$section]) ? $oldDef[$section] : [];
$new = isset($newDef[$section]) ? $newDef[$section] : []; $new = isset($newDef[$section]) ? $newDef[$section] : [];
@ -701,12 +707,12 @@ class Schema
* @param string $columnName * @param string $columnName
* @param array $cd * @param array $cd
*/ */
function appendAlterAddColumn(array &$phrase, $columnName, array $cd) public function appendAlterAddColumn(array &$phrase, string $columnName, array $cd)
{ {
$phrase[] = 'ADD COLUMN ' . $phrase[] = 'ADD COLUMN ' .
$this->quoteIdentifier($columnName) . $this->quoteIdentifier($columnName) .
' ' . ' ' .
$this->columnSql($cd); $this->columnSql($columnName, $cd);
} }
/** /**
@ -718,12 +724,12 @@ class Schema
* @param array $old previous column definition as found in DB * @param array $old previous column definition as found in DB
* @param array $cd current column definition * @param array $cd current column definition
*/ */
function appendAlterModifyColumn(array &$phrase, $columnName, array $old, array $cd) public function appendAlterModifyColumn(array &$phrase, string $columnName, array $old, array $cd)
{ {
$phrase[] = 'MODIFY COLUMN ' . $phrase[] = 'MODIFY COLUMN ' .
$this->quoteIdentifier($columnName) . $this->quoteIdentifier($columnName) .
' ' . ' ' .
$this->columnSql($cd); $this->columnSql($columnName, $cd);
} }
/** /**
@ -733,12 +739,12 @@ class Schema
* @param array $phrase * @param array $phrase
* @param string $columnName * @param string $columnName
*/ */
function appendAlterDropColumn(array &$phrase, $columnName) public function appendAlterDropColumn(array &$phrase, $columnName)
{ {
$phrase[] = 'DROP COLUMN ' . $this->quoteIdentifier($columnName); $phrase[] = 'DROP COLUMN ' . $this->quoteIdentifier($columnName);
} }
function appendAlterAddUnique(array &$phrase, $keyName, array $def) public function appendAlterAddUnique(array &$phrase, $keyName, array $def)
{ {
$sql = []; $sql = [];
$sql[] = 'ADD'; $sql[] = 'ADD';
@ -746,7 +752,7 @@ class Schema
$phrase[] = implode(' ', $sql); $phrase[] = implode(' ', $sql);
} }
function appendAlterAddForeign(array &$phrase, $keyName, array $def) public function appendAlterAddForeign(array &$phrase, $keyName, array $def)
{ {
$sql = []; $sql = [];
$sql[] = 'ADD'; $sql[] = 'ADD';
@ -754,7 +760,7 @@ class Schema
$phrase[] = implode(' ', $sql); $phrase[] = implode(' ', $sql);
} }
function appendAlterAddPrimary(array &$phrase, array $def) public function appendAlterAddPrimary(array &$phrase, array $def)
{ {
$sql = []; $sql = [];
$sql[] = 'ADD'; $sql[] = 'ADD';
@ -762,22 +768,22 @@ class Schema
$phrase[] = implode(' ', $sql); $phrase[] = implode(' ', $sql);
} }
function appendAlterDropPrimary(array &$phrase) public function appendAlterDropPrimary(array &$phrase, string $tableName)
{ {
$phrase[] = 'DROP CONSTRAINT PRIMARY KEY'; $phrase[] = 'DROP CONSTRAINT PRIMARY KEY';
} }
function appendAlterDropUnique(array &$phrase, $keyName) public function appendAlterDropUnique(array &$phrase, $keyName)
{ {
$phrase[] = 'DROP CONSTRAINT ' . $keyName; $phrase[] = 'DROP CONSTRAINT ' . $keyName;
} }
function appendAlterDropForeign(array &$phrase, $keyName) public function appendAlterDropForeign(array &$phrase, $keyName)
{ {
$phrase[] = 'DROP FOREIGN KEY ' . $keyName; $phrase[] = 'DROP FOREIGN KEY ' . $keyName;
} }
function appendAlterExtras(array &$phrase, $tableName, array $def) public function appendAlterExtras(array &$phrase, $tableName, array $def)
{ {
// no-op // no-op
} }
@ -788,21 +794,21 @@ class Schema
* @param string $name * @param string $name
* @return string * @return string
*/ */
function quoteIdentifier($name) public function quoteIdentifier($name)
{ {
return $name; return $this->conn->quoteIdentifier($name);
} }
function quoteDefaultValue($cd) public function quoteDefaultValue($cd)
{ {
if (($cd['type'] == 'datetime' || $cd['type'] == 'timestamp') && $cd['default'] == 'CURRENT_TIMESTAMP') { if (in_array($cd['type'], ['datetime', 'timestamp']) && $cd['default'] === 'CURRENT_TIMESTAMP') {
return $cd['default']; return $cd['default'];
} else { } else {
return $this->quoteValue($cd['default']); return $this->quoteValue($cd['default']);
} }
} }
function quoteValue($val) public function quoteValue($val)
{ {
return $this->conn->quoteSmart($val); return $this->conn->quoteSmart($val);
} }
@ -816,7 +822,7 @@ class Schema
* @param array $b * @param array $b
* @return bool * @return bool
*/ */
function columnsEqual(array $a, array $b) public function columnsEqual(array $a, array $b)
{ {
return !array_diff_assoc($a, $b) && !array_diff_assoc($b, $a); return !array_diff_assoc($a, $b) && !array_diff_assoc($b, $a);
} }
@ -829,7 +835,6 @@ class Schema
* *
* @return array strings for name values * @return array strings for name values
*/ */
protected function _names($cds) protected function _names($cds)
{ {
$names = []; $names = [];
@ -850,7 +855,6 @@ class Schema
* *
* @return ColumnDef matching item or null if no match. * @return ColumnDef matching item or null if no match.
*/ */
protected function _byName($cds, $name) protected function _byName($cds, $name)
{ {
foreach ($cds as $cd) { foreach ($cds as $cd) {
@ -869,20 +873,20 @@ class Schema
* Appropriate for use in CREATE TABLE or * Appropriate for use in CREATE TABLE or
* ALTER TABLE statements. * ALTER TABLE statements.
* *
* @param string $name column name to create
* @param array $cd column to create * @param array $cd column to create
* *
* @return string correct SQL for that column * @return string correct SQL for that column
*/ */
public function columnSql(string $name, array $cd)
function columnSql(array $cd)
{ {
$line = []; $line = [];
$line[] = $this->typeAndSize($cd); $line[] = $this->typeAndSize($name, $cd);
if (isset($cd['default'])) { if (isset($cd['default'])) {
$line[] = 'default'; $line[] = 'default';
$line[] = $this->quoteDefaultValue($cd); $line[] = $this->quoteDefaultValue($cd);
} else if (!empty($cd['not null'])) { } elseif (!empty($cd['not null'])) {
// Can't have both not null AND default! // Can't have both not null AND default!
$line[] = 'not null'; $line[] = 'not null';
} }
@ -895,14 +899,14 @@ class Schema
* @param string $column canonical type name in defs * @param string $column canonical type name in defs
* @return string native DB type name * @return string native DB type name
*/ */
function mapType($column) public function mapType($column)
{ {
return $column; return $column;
} }
function typeAndSize($column) public function typeAndSize(string $name, array $column)
{ {
//$type = $this->mapType($column); //$type = $this->mapType($column)['type'];
$type = $column['type']; $type = $column['type'];
if (isset($column['size'])) { if (isset($column['size'])) {
$type = $column['size'] . $type; $type = $column['size'] . $type;
@ -914,7 +918,7 @@ class Schema
if (isset($column['scale'])) { if (isset($column['scale'])) {
$lengths[] = $column['scale']; $lengths[] = $column['scale'];
} }
} else if (isset($column['length'])) { } elseif (isset($column['length'])) {
$lengths[] = $column['length']; $lengths[] = $column['length'];
} }
@ -977,12 +981,12 @@ class Schema
$table['primary key'] = []; $table['primary key'] = [];
} }
$table['primary key'][] = $cd->name; $table['primary key'][] = $cd->name;
} else if ($cd->key == 'MUL') { } elseif ($cd->key === 'MUL') {
// Individual multiple-value indexes are only per-column // Individual multiple-value indexes are only per-column
// using the old ColumnDef syntax. // using the old ColumnDef syntax.
$idx = "{$tableName}_{$cd->name}_idx"; $idx = "{$tableName}_{$cd->name}_idx";
$table['indexes'][$idx] = [$cd->name]; $table['indexes'][$idx] = [$cd->name];
} else if ($cd->key == 'UNI') { } elseif ($cd->key === 'UNI') {
// Individual unique-value indexes are only per-column // Individual unique-value indexes are only per-column
// using the old ColumnDef syntax. // using the old ColumnDef syntax.
$idx = "{$tableName}_{$cd->name}_idx"; $idx = "{$tableName}_{$cd->name}_idx";
@ -1003,7 +1007,7 @@ class Schema
* @param array $tableDef * @param array $tableDef
* @return array * @return array
*/ */
function filterDef(array $tableDef) public function filterDef(array $tableDef)
{ {
return $tableDef; return $tableDef;
} }
@ -1019,7 +1023,7 @@ class Schema
* *
* @throws Exception on wildly invalid input * @throws Exception on wildly invalid input
*/ */
function validateDef($tableName, array $def) public function validateDef($tableName, array $def)
{ {
if (isset($def[0]) && $def[0] instanceof ColumnDef) { if (isset($def[0]) && $def[0] instanceof ColumnDef) {
$def = $this->oldToNew($tableName, $def); $def = $this->oldToNew($tableName, $def);
@ -1033,7 +1037,7 @@ class Schema
return $def; return $def;
} }
function isNumericType($type) public function isNumericType($type)
{ {
$type = strtolower($type); $type = strtolower($type);
$known = ['int', 'serial', 'numeric']; $known = ['int', 'serial', 'numeric'];
@ -1074,20 +1078,21 @@ class Schema
$this->getTableDef($new_name); $this->getTableDef($new_name);
// New table exists, can't work // New table exists, can't work
throw new ServerException("Both table {$old_name} and {$new_name} exist. You're on your own."); throw new ServerException("Both table {$old_name} and {$new_name} exist. You're on your own.");
} catch(SchemaTableMissingException $e) { } catch (SchemaTableMissingException $e) {
// New table doesn't exist, carry on // New table doesn't exist, carry on
} }
} catch(SchemaTableMissingException $e) { } catch (SchemaTableMissingException $e) {
// Already renamed, or no previous table, so we're done // Already renamed, or no previous table, so we're done
return true; return true;
} }
return $this->runSqlSet(["ALTER TABLE {$old_name} RENAME TO {$new_name};"]); return $this->runSqlSet([
'ALTER TABLE ' . $this->quoteIdentifier($old_name) .
' RENAME TO ' . $this->quoteIdentifier($new_name) . ';',
]);
} }
} }
class SchemaTableMissingException extends Exception class SchemaTableMissingException extends Exception
{ {
// no-op // no-op
} }

View File

@ -1,77 +1,60 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Groups with the most members section * Groups with the most members section
* *
* 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 Widget * @category Widget
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Groups with the most members section * Groups with the most members section
* *
* @category Widget * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @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 GroupsByMembersSection extends GroupSection class GroupsByMembersSection extends GroupSection
{ {
function getGroups() public function getGroups()
{ {
$qry = 'SELECT user_group.*, count(*) as value ' .
'FROM user_group JOIN group_member '.
'ON user_group.id = group_member.group_id ' .
'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified ' .
'ORDER BY value DESC ';
$limit = GROUPS_PER_SECTION; $limit = GROUPS_PER_SECTION;
$offset = 0;
if (common_config('db','type') == 'pgsql') { $qry = 'SELECT user_group.*, COUNT(*) AS value ' .
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; 'FROM user_group INNER JOIN group_member '.
} else { 'ON user_group.id = group_member.group_id ' .
$qry .= ' LIMIT ' . $offset . ', ' . $limit; 'GROUP BY user_group.id, user_group.nickname, user_group.fullname, user_group.homepage, user_group.description, user_group.location, user_group.original_logo, user_group.homepage_logo, user_group.stream_logo, user_group.mini_logo, user_group.created, user_group.modified ' .
} 'ORDER BY value DESC LIMIT ' . $limit;
$group = Memcached_DataObject::cachedQuery('User_group', $group = Memcached_DataObject::cachedQuery('User_group', $qry, 3600);
$qry,
3600);
return $group; return $group;
} }
function title() public function title()
{ {
// TRANS: Title for groups with the most members section. // TRANS: Title for groups with the most members section.
return _('Popular groups'); return _('Popular groups');
} }
function divId() public function divId()
{ {
return 'top_groups_by_member'; return 'top_groups_by_member';
} }

View File

@ -44,20 +44,13 @@ class GroupsByPostsSection extends GroupSection
{ {
function getGroups() function getGroups()
{ {
$limit = GROUPS_PER_SECTION;
$qry = 'SELECT user_group.*, count(*) as value ' . $qry = 'SELECT user_group.*, count(*) as value ' .
'FROM user_group JOIN group_inbox '. 'FROM user_group JOIN group_inbox '.
'ON user_group.id = group_inbox.group_id ' . 'ON user_group.id = group_inbox.group_id ' .
'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified ' . 'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified ' .
'ORDER BY value DESC '; 'ORDER BY value DESC LIMIT ' . $limit;
$limit = GROUPS_PER_SECTION;
$offset = 0;
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$group = Memcached_DataObject::cachedQuery('User_group', $group = Memcached_DataObject::cachedQuery('User_group',
$qry, $qry,

View File

@ -1,51 +1,40 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Stream of notices for a profile's "all" feed * Stream of notices for a profile's "all" feed
* *
* 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 NoticeStream * @category NoticeStream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Mikael Nordfeldth <mmn@hethane.se> * @author Mikael Nordfeldth <mmn@hethane.se>
* @author Alexei Sorokin <sor.alexei@meowr.ru> * @author Alexei Sorokin <sor.alexei@meowr.ru>
* @author Stephane Berube <chimo@chromic.org>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @copyright 2014 Free Software Foundation, Inc. * @copyright 2014 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Stream of notices for a profile's "all" feed
*
* @category General * @category General
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Mikael Nordfeldth <mmn@hethane.se>
* @author Alexei Sorokin <sor.alexei@meowr.ru>
* @author chimo <chimo@chromic.org>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @copyright 2014 Free Software Foundation, Inc. * @copyright 2014 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class InboxNoticeStream extends ScopingNoticeStream class InboxNoticeStream extends ScopingNoticeStream
{ {
@ -65,13 +54,9 @@ class InboxNoticeStream extends ScopingNoticeStream
* Raw stream of notices for the target's inbox * Raw stream of notices for the target's inbox
* *
* @category General * @category General
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Mikael Nordfeldth <mmn@hethane.se>
* @author Alexei Sorokin <sor.alexei@meowr.ru>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @copyright 2014 Free Software Foundation, Inc http://www.fsf.org
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
class RawInboxNoticeStream extends FullNoticeStream class RawInboxNoticeStream extends FullNoticeStream
{ {
@ -104,33 +89,39 @@ class RawInboxNoticeStream extends FullNoticeStream
$notice = new Notice(); $notice = new Notice();
$notice->selectAdd(); $notice->selectAdd();
$notice->selectAdd('id'); $notice->selectAdd('id');
$notice->whereAdd(sprintf('notice.created > "%s"', $notice->escape($this->target->created)));
// Reply:: is a table of mentions // Reply:: is a table of mentions
// Subscription:: is a table of subscriptions (every user is subscribed to themselves) // Subscription:: is a table of subscriptions (every user is subscribed to themselves)
// Sort in descending order as id will give us even really old posts, $notice->_join .= sprintf(
// which were recently imported. For example, if a remote instance had "\n" . 'NATURAL INNER JOIN (' .
// problems and just managed to post here. '(SELECT id FROM notice WHERE profile_id IN (SELECT subscribed FROM subscription WHERE subscriber = %1$d)) ' .
$notice->whereAdd( 'UNION (SELECT notice_id AS id FROM reply WHERE profile_id = %1$d) ' .
sprintf('id IN (SELECT DISTINCT id FROM (' . 'UNION (SELECT notice_id AS id FROM attention WHERE profile_id = %1$d) ' .
'(SELECT id FROM notice WHERE profile_id IN (SELECT subscribed FROM subscription WHERE subscriber = %1$d)) UNION ' . 'UNION (SELECT notice_id AS id FROM group_inbox WHERE group_id IN (SELECT group_id FROM group_member WHERE profile_id = %1$d))' .
'(SELECT notice_id AS id FROM reply WHERE profile_id = %1$d) UNION ' . ') AS t1',
'(SELECT notice_id AS id FROM attention WHERE profile_id = %1$d) UNION ' . $this->target->getID()
'(SELECT notice_id AS id FROM group_inbox WHERE group_id IN (SELECT group_id FROM group_member WHERE profile_id = %1$d)) ' .
'ORDER BY id DESC) AS T)',
$this->target->getID())
); );
$notice->whereAdd(sprintf(
"notice.created > TIMESTAMP '%s'",
$notice->escape($this->target->created)
));
if (!empty($since_id)) { if (!empty($since_id)) {
$notice->whereAdd(sprintf('notice.id > %d', $since_id)); $notice->whereAdd('id > ' . $since_id);
} }
if (!empty($max_id)) { if (!empty($max_id)) {
$notice->whereAdd(sprintf('notice.id <= %d', $max_id)); $notice->whereAdd('id <= ' . $max_id);
} }
$notice->whereAdd('scope != ' . Notice::MESSAGE_SCOPE); $notice->whereAdd('scope <> ' . Notice::MESSAGE_SCOPE);
self::filterVerbs($notice, $this->selectVerbs); self::filterVerbs($notice, $this->selectVerbs);
// notice.id will give us even really old posts, which were recently
// imported. For example if a remote instance had problems and just
// managed to post here.
$notice->orderBy('id DESC');
$notice->limit($offset, $limit); $notice->limit($offset, $limit);
if (!$notice->find()) { if (!$notice->find()) {

View File

@ -1,31 +1,54 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/**
* Raw public stream
*
* @category Stream
* @package GNUsocial
* @author Evan Prodromou <evan@status.net>
* @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
class NetworkPublicNoticeStream extends ModeratedNoticeStream class NetworkPublicNoticeStream extends ModeratedNoticeStream
{ {
function __construct(Profile $scoped=null) public function __construct(Profile $scoped = null)
{ {
parent::__construct(new CachingNoticeStream(new RawNetworkPublicNoticeStream(), parent::__construct(
'networkpublic'), new CachingNoticeStream(
$scoped); new RawNetworkPublicNoticeStream(),
'networkpublic'
),
$scoped
);
} }
} }
/** /**
* Raw public stream * Raw public stream
* *
* @category Stream
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class RawNetworkPublicNoticeStream extends FullNoticeStream class RawNetworkPublicNoticeStream extends FullNoticeStream
{ {
function getNoticeIds($offset, $limit, $since_id, $max_id) public function getNoticeIds($offset, $limit, $since_id, $max_id)
{ {
$notice = new Notice(); $notice = new Notice();
@ -38,11 +61,11 @@ class RawNetworkPublicNoticeStream extends FullNoticeStream
$notice->limit($offset, $limit); $notice->limit($offset, $limit);
} }
$notice->whereAdd('is_local ='. Notice::REMOTE); $notice->whereAdd('is_local = '. Notice::REMOTE);
// -1 == blacklisted, -2 == gateway (i.e. Twitter) // -1 == blacklisted, -2 == gateway (i.e. Twitter)
$notice->whereAdd('is_local !='. Notice::LOCAL_NONPUBLIC); $notice->whereAdd('is_local <> '. Notice::LOCAL_NONPUBLIC);
$notice->whereAdd('is_local !='. Notice::GATEWAY); $notice->whereAdd('is_local <> '. Notice::GATEWAY);
$notice->whereAdd('scope != ' . Notice::MESSAGE_SCOPE); $notice->whereAdd('scope <> ' . Notice::MESSAGE_SCOPE);
Notice::addWhereSinceId($notice, $since_id); Notice::addWhereSinceId($notice, $since_id);
Notice::addWhereMaxId($notice, $max_id); Notice::addWhereMaxId($notice, $max_id);
@ -58,7 +81,7 @@ class RawNetworkPublicNoticeStream extends FullNoticeStream
} }
$notice->free(); $notice->free();
$notice = NULL; $notice = null;
return $ids; return $ids;
} }

View File

@ -1,53 +1,52 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Public stream * Public stream
* *
* 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 * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Public stream * Public stream
* *
* @category Stream * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class PublicNoticeStream extends ModeratedNoticeStream class PublicNoticeStream extends ModeratedNoticeStream
{ {
function __construct(Profile $scoped=null) public function __construct(Profile $scoped = null)
{ {
parent::__construct(new CachingNoticeStream(new RawPublicNoticeStream(), parent::__construct(
'public'), new CachingNoticeStream(
$scoped); new RawPublicNoticeStream(),
'public'
),
$scoped
);
} }
} }
@ -55,16 +54,15 @@ class PublicNoticeStream extends ModeratedNoticeStream
* Raw public stream * Raw public stream
* *
* @category Stream * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class RawPublicNoticeStream extends FullNoticeStream class RawPublicNoticeStream extends FullNoticeStream
{ {
function getNoticeIds($offset, $limit, $since_id, $max_id) public function getNoticeIds($offset, $limit, $since_id, $max_id)
{ {
$notice = new Notice(); $notice = new Notice();
@ -79,7 +77,7 @@ class RawPublicNoticeStream extends FullNoticeStream
// This feed always gives only local activities. // This feed always gives only local activities.
$notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC); $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
$notice->whereAdd('scope != ' . Notice::MESSAGE_SCOPE); $notice->whereAdd('scope <> ' . Notice::MESSAGE_SCOPE);
Notice::addWhereSinceId($notice, $since_id); Notice::addWhereSinceId($notice, $since_id);
Notice::addWhereMaxId($notice, $max_id); Notice::addWhereMaxId($notice, $max_id);
@ -95,7 +93,7 @@ class RawPublicNoticeStream extends FullNoticeStream
} }
$notice->free(); $notice->free();
$notice = NULL; $notice = null;
return $ids; return $ids;
} }

View File

@ -1,53 +1,52 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Stream of mentions of me * Stream of mentions of me
* *
* 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 * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Stream of mentions of me * Stream of mentions of me
* *
* @category Stream * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class ReplyNoticeStream extends ScopingNoticeStream class ReplyNoticeStream extends ScopingNoticeStream
{ {
function __construct($userId, Profile $scoped=null) public function __construct($userId, Profile $scoped = null)
{ {
parent::__construct(new CachingNoticeStream(new RawReplyNoticeStream($userId), parent::__construct(
'reply:stream:' . $userId), new CachingNoticeStream(
$scoped); new RawReplyNoticeStream($userId),
'reply:stream:' . $userId
),
$scoped
);
} }
} }
@ -55,24 +54,23 @@ class ReplyNoticeStream extends ScopingNoticeStream
* Raw stream of mentions of me * Raw stream of mentions of me
* *
* @category Stream * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class RawReplyNoticeStream extends NoticeStream class RawReplyNoticeStream extends NoticeStream
{ {
protected $userId; protected $userId;
function __construct($userId) public function __construct($userId)
{ {
parent::__construct(); parent::__construct();
$this->userId = $userId; $this->userId = $userId;
} }
function getNoticeIds($offset, $limit, $since_id, $max_id) public function getNoticeIds($offset, $limit, $since_id, $max_id)
{ {
$reply = new Reply(); $reply = new Reply();
@ -94,14 +92,16 @@ class RawReplyNoticeStream extends NoticeStream
$reply->whereAddIn('notice.verb', $filter, 'string'); $reply->whereAddIn('notice.verb', $filter, 'string');
} }
$filter = array_keys(array_filter($this->selectVerbs, function ($v) { return !$v; })); $filter = array_keys(array_filter($this->selectVerbs, function ($v) {
return !$v;
}));
if (!empty($filter)) { if (!empty($filter)) {
// exclude verbs in selectVerbs with values that equate to false // exclude verbs in selectVerbs with values that equate to false
$reply->whereAddIn('!notice.verb', $filter, 'string'); $reply->whereAddIn('!notice.verb', $filter, 'string');
} }
} }
$reply->whereAdd('notice.scope != ' . NOTICE::MESSAGE_SCOPE); $reply->whereAdd('notice.scope <> ' . NOTICE::MESSAGE_SCOPE);
$reply->orderBy('reply.modified DESC, reply.notice_id DESC'); $reply->orderBy('reply.modified DESC, reply.notice_id DESC');

View File

@ -1,72 +1,63 @@
<?php <?php
/** // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2011, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* Stream of notices for a list // the Free Software Foundation, either version 3 of the License, or
* // (at your option) any later version.
* PHP version 5 //
* // GNU social is distributed in the hope that it will be useful,
* This program is free software: you can redistribute it and/or modify // but WITHOUT ANY WARRANTY; without even the implied warranty of
* it under the terms of the GNU Affero General Public License as published by // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* the Free Software Foundation, either version 3 of the License, or // GNU Affero General Public License for more details.
* (at your option) any later version. //
* // You should have received a copy of the GNU Affero General Public License
* This program is distributed in the hope that it will be useful, // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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('GNUSOCIAL')) { exit(1); }
/** /**
* Stream of notices for a list * Stream of notices for a list
* *
* @category Stream * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Shashi Gowda <connect2shashi@gmail.com> * @author Shashi Gowda <connect2shashi@gmail.com>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/ */
defined('GNUSOCIAL') || die();
/**
* Stream of notices for a list
*
* @copyright 2011 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
class PeopletagNoticeStream extends ScopingNoticeStream class PeopletagNoticeStream extends ScopingNoticeStream
{ {
function __construct($plist, Profile $scoped=null) public function __construct($plist, Profile $scoped = null)
{ {
parent::__construct(new CachingNoticeStream(new RawPeopletagNoticeStream($plist), parent::__construct(
'profile_list:notice_ids:' . $plist->id), new CachingNoticeStream(
$scoped); new RawPeopletagNoticeStream($plist),
'profile_list:notice_ids:' . $plist->id
),
$scoped
);
} }
} }
/** /**
* Stream of notices for a list * Stream of notices for a list
* *
* @category Stream
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Shashi Gowda <connect2shashi@gmail.com>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class RawPeopletagNoticeStream extends NoticeStream class RawPeopletagNoticeStream extends NoticeStream
{ {
protected $profile_list; protected $profile_list;
function __construct($profile_list) public function __construct($profile_list)
{ {
$this->profile_list = $profile_list; $this->profile_list = $profile_list;
} }
@ -82,7 +73,7 @@ class RawPeopletagNoticeStream extends NoticeStream
* @return array array of notice ids. * @return array array of notice ids.
*/ */
function getNoticeIds($offset, $limit, $since_id, $max_id) public function getNoticeIds($offset, $limit, $since_id, $max_id)
{ {
$notice = new Notice(); $notice = new Notice();
@ -94,7 +85,10 @@ class RawPeopletagNoticeStream extends NoticeStream
$ptag->tagger = $this->profile_list->tagger; $ptag->tagger = $this->profile_list->tagger;
$notice->joinAdd(array('profile_id', 'profile_tag:tagged')); $notice->joinAdd(array('profile_id', 'profile_tag:tagged'));
$notice->whereAdd('profile_tag.tagger = ' . $this->profile_list->tagger); $notice->whereAdd('profile_tag.tagger = ' . $this->profile_list->tagger);
$notice->whereAdd(sprintf('profile_tag.tag = "%s"', $this->profile_list->tag)); $notice->whereAdd(sprintf(
"profile_tag.tag = '%s'",
$notice->escape($this->profile_list->tag)
));
if ($since_id != 0) { if ($since_id != 0) {
$notice->whereAdd('notice.id > ' . $since_id); $notice->whereAdd('notice.id > ' . $since_id);

View File

@ -1,65 +1,49 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Peopletags with the most subscribers section * Peopletags with the most subscribers section
* *
* 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 Widget * @category Widget
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Peopletags with the most subscribers section * Peopletags with the most subscribers section
* *
* @category Widget * @copyright 2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @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 PeopletagsBySubsSection extends PeopletagSection class PeopletagsBySubsSection extends PeopletagSection
{ {
function getPeopletags() function getPeopletags()
{ {
$qry = 'SELECT profile_list.*, subscriber_count as value ' .
'FROM profile_list WHERE profile_list.private = false ' .
'ORDER BY value DESC ';
$limit = PEOPLETAGS_PER_SECTION; $limit = PEOPLETAGS_PER_SECTION;
$offset = 0;
if (common_config('db','type') == 'pgsql') { $qry = 'SELECT profile_list.*, subscriber_count AS value ' .
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; 'FROM profile_list WHERE profile_list.private = FALSE ' .
} else { 'ORDER BY value DESC ' .
$qry .= ' LIMIT ' . $offset . ', ' . $limit; 'LIMIT ' . $limit;
}
$peopletag = Memcached_DataObject::cachedQuery('Profile_list', $peopletag = Memcached_DataObject::cachedQuery('Profile_list', $qry, 3600);
$qry,
3600);
return $peopletag; return $peopletag;
} }

View File

@ -1,59 +1,58 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Stream of notices by a profile * Stream of notices by a profile
* *
* 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 * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Stream of notices by a profile * Stream of notices by a profile
* *
* @category General * @category General
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class ProfileNoticeStream extends ScopingNoticeStream class ProfileNoticeStream extends ScopingNoticeStream
{ {
protected $target; protected $target;
function __construct(Profile $target, Profile $scoped=null) public function __construct(Profile $target, Profile $scoped = null)
{ {
$this->target = $target; $this->target = $target;
parent::__construct(new CachingNoticeStream(new RawProfileNoticeStream($target), parent::__construct(
'profile:notice_ids:' . $target->getID()), new CachingNoticeStream(
$scoped); new RawProfileNoticeStream($target),
'profile:notice_ids:' . $target->getID()
),
$scoped
);
} }
function getNoticeIds($offset, $limit, $since_id=null, $max_id=null) public function getNoticeIds($offset, $limit, $since_id = null, $max_id = null)
{ {
if ($this->impossibleStream()) { if ($this->impossibleStream()) {
return array(); return array();
@ -62,7 +61,7 @@ class ProfileNoticeStream extends ScopingNoticeStream
} }
} }
function getNotices($offset, $limit, $since_id=null, $max_id=null) public function getNotices($offset, $limit, $since_id = null, $max_id = null)
{ {
if ($this->impossibleStream()) { if ($this->impossibleStream()) {
throw new PrivateStreamException($this->target, $this->scoped); throw new PrivateStreamException($this->target, $this->scoped);
@ -71,7 +70,7 @@ class ProfileNoticeStream extends ScopingNoticeStream
} }
} }
function impossibleStream() public function impossibleStream()
{ {
if (!$this->target->readableBy($this->scoped)) { if (!$this->target->readableBy($this->scoped)) {
// cannot read because it's a private stream and either noone's logged in or they are not subscribers // cannot read because it's a private stream and either noone's logged in or they are not subscribers
@ -82,12 +81,11 @@ class ProfileNoticeStream extends ScopingNoticeStream
if (common_config('notice', 'hidespam')) { if (common_config('notice', 'hidespam')) {
// if this is a silenced user // if this is a silenced user
if ($this->target->hasRole(Profile_role::SILENCED) if ($this->target->hasRole(Profile_role::SILENCED) &&
// and we are either not logged in // and we are either not logged in
&& (!$this->scoped instanceof Profile (!$this->scoped instanceof Profile ||
// or if we are, we are not logged in as the target, and we don't have right to review spam // or if we are, we are not logged in as the target, and we don't have right to review spam
|| (!$this->scoped->sameAs($this->target) && !$this->scoped->hasRight(Right::REVIEWSPAM)) (!$this->scoped->sameAs($this->target) && !$this->scoped->hasRight(Right::REVIEWSPAM)))) {
)) {
return true; return true;
} }
} }
@ -100,11 +98,10 @@ class ProfileNoticeStream extends ScopingNoticeStream
* Raw stream of notices by a profile * Raw stream of notices by a profile
* *
* @category General * @category General
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class RawProfileNoticeStream extends NoticeStream class RawProfileNoticeStream extends NoticeStream
@ -112,13 +109,13 @@ class RawProfileNoticeStream extends NoticeStream
protected $target; protected $target;
protected $selectVerbs = array(); // select all verbs protected $selectVerbs = array(); // select all verbs
function __construct(Profile $target) public function __construct(Profile $target)
{ {
parent::__construct(); parent::__construct();
$this->target = $target; $this->target = $target;
} }
function getNoticeIds($offset, $limit, $since_id, $max_id) public function getNoticeIds($offset, $limit, $since_id, $max_id)
{ {
$notice = new Notice(); $notice = new Notice();
@ -127,7 +124,7 @@ class RawProfileNoticeStream extends NoticeStream
$notice->selectAdd(); $notice->selectAdd();
$notice->selectAdd('id'); $notice->selectAdd('id');
$notice->whereAdd('scope != ' . Notice::MESSAGE_SCOPE); $notice->whereAdd('scope <> ' . Notice::MESSAGE_SCOPE);
Notice::addWhereSinceId($notice, $since_id); Notice::addWhereSinceId($notice, $since_id);
Notice::addWhereMaxId($notice, $max_id); Notice::addWhereMaxId($notice, $max_id);

View File

@ -1,47 +1,42 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
class SearchEngine class SearchEngine
{ {
protected $target; protected $target;
protected $table; protected $table;
function __construct($target, $table) public function __construct($target, $table)
{ {
$this->target = $target; $this->target = $target;
$this->table = $table; $this->table = $table;
} }
function query($q) public function query($q)
{ {
} }
function limit($offset, $count, $rss = false) public function limit($offset, $count, $rss = false)
{ {
return $this->target->limit($offset, $count); return $this->target->limit($offset, $count);
} }
function set_sort_mode($mode) public function set_sort_mode($mode)
{ {
switch ($mode) { switch ($mode) {
case 'chron': case 'chron':
@ -75,42 +70,82 @@ class SearchEngine
} }
} }
class PostgreSQLSearch extends SearchEngine
{
public function query($q)
{
if ($this->table === 'profile') {
$cols = implode(" || ' ' || ", array_map(
function ($col) {
return sprintf(
"COALESCE(%s.%s, '')",
common_database_tablename($this->table),
$col
);
},
['nickname', 'fullname', 'location', 'bio', 'homepage']
));
$this->target->whereAdd(sprintf(
'to_tsvector(\'english\', %2$s) @@ plainto_tsquery(\'%1$s\')',
$this->target->escape($q, true),
$cols
));
return true;
} elseif ($this->table === 'notice') {
// Don't show imported notices
$this->target->whereAdd('notice.is_local <> ' . Notice::GATEWAY);
$this->target->whereAdd(sprintf(
'to_tsvector(\'english\', content) @@ plainto_tsquery(\'%1$s\')',
$this->target->escape($q, true)
));
return true;
} else {
throw new ServerException('Unknown table: ' . $this->table);
}
}
}
class MySQLSearch extends SearchEngine class MySQLSearch extends SearchEngine
{ {
function query($q) public function query($q)
{ {
if ('profile' === $this->table) { if ($this->table === 'profile') {
$this->target->whereAdd( $this->target->whereAdd(sprintf(
sprintf('MATCH (%2$s.nickname, %2$s.fullname, %2$s.location, %2$s.bio, %2$s.homepage) ' . 'MATCH (%2$s.nickname, %2$s.fullname, %2$s.location, %2$s.bio, %2$s.homepage) ' .
'AGAINST ("%1$s" IN BOOLEAN MODE)', 'AGAINST (\'%1$s\' IN BOOLEAN MODE)',
$this->target->escape($q, true), $this->target->escape($q, true),
$this->table) $this->table
); ));
if (strtolower($q) != $q) { if (strtolower($q) != $q) {
$this->target->whereAdd( $this->target->whereAdd(
sprintf('MATCH (%2$s.nickname, %2$s.fullname, %2$s.location, %2$s.bio, %2$s.homepage) ' . sprintf(
'AGAINST ("%1$s" IN BOOLEAN MODE)', 'MATCH (%2$s.nickname, %2$s.fullname, %2$s.location, %2$s.bio, %2$s.homepage) ' .
'AGAINST (\'%1$s\' IN BOOLEAN MODE)',
$this->target->escape(strtolower($q), true), $this->target->escape(strtolower($q), true),
$this->table), $this->table
),
'OR' 'OR'
); );
} }
return true; return true;
} else if ('notice' === $this->table) { } elseif ($this->table === 'notice') {
// Don't show imported notices // Don't show imported notices
$this->target->whereAdd('notice.is_local != ' . Notice::GATEWAY); $this->target->whereAdd('notice.is_local <> ' . Notice::GATEWAY);
$this->target->whereAdd( $this->target->whereAdd(sprintf(
sprintf('MATCH (%2$s.content) AGAINST ("%1$s" IN BOOLEAN MODE)', 'MATCH (%2$s.content) AGAINST (\'%1$s\' IN BOOLEAN MODE)',
$this->target->escape($q, true), $this->target->escape($q, true),
$this->table) $this->table
); ));
if (strtolower($q) != $q) { if (strtolower($q) != $q) {
$this->target->whereAdd( $this->target->whereAdd(
sprintf('MATCH (%2$s.content) AGAINST ("%1$s" IN BOOLEAN MODE)', sprintf(
'MATCH (%2$s.content) AGAINST (\'%1$s\' IN BOOLEAN MODE)',
$this->target->escape(strtolower($q), true), $this->target->escape(strtolower($q), true),
$this->table), $this->table
),
'OR' 'OR'
); );
} }
@ -122,20 +157,22 @@ class MySQLSearch extends SearchEngine
} }
} }
class MySQLLikeSearch extends SearchEngine class SQLLikeSearch extends SearchEngine
{ {
function query($q) public function query($q)
{ {
if ('profile' === $this->table) { if ($this->table === 'profile') {
$qry = sprintf('(%2$s.nickname LIKE "%%%1$s%%" OR ' . $qry = sprintf(
' %2$s.fullname LIKE "%%%1$s%%" OR ' . '( %2$s.nickname LIKE \'%%%1$s%%\' ' .
' %2$s.location LIKE "%%%1$s%%" OR ' . ' OR %2$s.fullname LIKE \'%%%1$s%%\' ' .
' %2$s.bio LIKE "%%%1$s%%" OR ' . ' OR %2$s.location LIKE \'%%%1$s%%\' ' .
' %2$s.homepage LIKE "%%%1$s%%")', ' OR %2$s.bio LIKE \'%%%1$s%%\' ' .
' OR %2$s.homepage LIKE \'%%%1$s%%\')',
$this->target->escape($q, true), $this->target->escape($q, true),
$this->table); $this->table
} else if ('notice' === $this->table) { );
$qry = sprintf('content LIKE "%%%1$s%%"', $this->target->escape($q, true)); } elseif ($this->table === 'notice') {
$qry = sprintf('content LIKE \'%%%1$s%%\'', $this->target->escape($q, true));
} else { } else {
throw new ServerException('Unknown table: ' . $this->table); throw new ServerException('Unknown table: ' . $this->table);
} }
@ -145,21 +182,3 @@ class MySQLLikeSearch extends SearchEngine
return true; return true;
} }
} }
class PGSearch extends SearchEngine
{
function query($q)
{
if ('profile' === $this->table) {
return $this->target->whereAdd('textsearch @@ plainto_tsquery(\'' . $this->target->escape($q) . '\')');
} else if ('notice' === $this->table) {
// XXX: We need to filter out gateway notices (notice.is_local = -2) --Zach
return $this->target->whereAdd('to_tsvector(\'english\', content) @@ plainto_tsquery(\'' . $this->target->escape($q) . '\')');
} else {
throw new ServerException('Unknown table: ' . $this->table);
}
}
}

View File

@ -1,48 +1,40 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Section for featured users * Section for featured users
* *
* 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 Widget * @category Widget
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Section for featured users * Section for featured users
* *
* @category Widget * @copyright 2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @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 FeaturedUsersSection extends ProfileSection class FeaturedUsersSection extends ProfileSection
{ {
function show() public function show()
{ {
$featured_nicks = common_config('nickname', 'featured'); $featured_nicks = common_config('nickname', 'featured');
if (empty($featured_nicks)) { if (empty($featured_nicks)) {
@ -51,7 +43,7 @@ class FeaturedUsersSection extends ProfileSection
parent::show(); parent::show();
} }
function getProfiles() public function getProfiles()
{ {
$featured_nicks = common_config('nickname', 'featured'); $featured_nicks = common_config('nickname', 'featured');
@ -65,43 +57,30 @@ class FeaturedUsersSection extends ProfileSection
$quoted[] = "'$nick'"; $quoted[] = "'$nick'";
} }
$table = "user"; $table = common_database_tablename('user');
if(common_config('db','quote_identifiers')) { $limit = PROFILES_PER_SECTION + 1;
$table = '"' . $table . '"';
}
$qry = 'SELECT profile.* ' . $qry = 'SELECT profile.* ' .
'FROM profile JOIN '. $table .' on profile.id = '. $table .'.id ' . 'FROM profile INNER JOIN ' . $table . ' ON profile.id = ' . $table . '.id ' .
'WHERE '. $table .'.nickname in (' . implode(',', $quoted) . ') ' . 'WHERE ' . $table . '.nickname IN (' . implode(',', $quoted) . ') ' .
'ORDER BY profile.created DESC '; 'ORDER BY profile.created DESC LIMIT ' . $limit;
$limit = PROFILES_PER_SECTION + 1; $profile = Memcached_DataObject::cachedQuery('Profile', $qry, 6 * 3600);
$offset = 0;
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$profile = Memcached_DataObject::cachedQuery('Profile',
$qry,
6 * 3600);
return $profile; return $profile;
} }
function title() public function title()
{ {
// TRANS: Title for featured users section. // TRANS: Title for featured users section.
return _('Featured users'); return _('Featured users');
} }
function divId() public function divId()
{ {
return 'featured_users'; return 'featured_users';
} }
function moreUrl() public function moreUrl()
{ {
return common_local_url('featured'); return common_local_url('featured');
} }

View File

@ -1,23 +1,25 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool * @copyright 2008, 2009 StatusNet, Inc.
* Copyright (C) 2008, 2009, StatusNet, Inc. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
// 10x8 // 10x8
@ -36,12 +38,12 @@ class GalleryAction extends ProfileAction
parent::handle(); parent::handle();
} }
function showContent() public function showContent()
{ {
$this->showTagsDropdown(); $this->showTagsDropdown();
} }
function showTagsDropdown() public function showTagsDropdown()
{ {
$tag = $this->trimmed('tag'); $tag = $this->trimmed('tag');
@ -59,13 +61,17 @@ class GalleryAction extends ProfileAction
$this->elementStart('ul'); $this->elementStart('ul');
$this->elementStart('li', array('id' => 'filter_tags_all', $this->elementStart('li', array('id' => 'filter_tags_all',
'class' => 'child_1')); 'class' => 'child_1'));
$this->element('a', $this->element(
array('href' => 'a',
common_local_url($this->trimmed('action'), [
array('nickname' => 'href' => common_local_url(
$this->target->getNickname()))), $this->trimmed('action'),
['nickname' => $this->target->getNickname()]
),
],
// TRANS: List element on gallery action page to show all tags. // TRANS: List element on gallery action page to show all tags.
_m('TAGS','All')); _m('TAGS', 'All')
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li', array('id'=>'filter_tags_item')); $this->elementStart('li', array('id'=>'filter_tags_item'));
$this->elementStart('form', array('name' => 'bytag', $this->elementStart('form', array('name' => 'bytag',
@ -76,12 +82,18 @@ class GalleryAction extends ProfileAction
// TRANS: Fieldset legend on gallery action page. // TRANS: Fieldset legend on gallery action page.
$this->element('legend', null, _('Select tag to filter')); $this->element('legend', null, _('Select tag to filter'));
// TRANS: Dropdown field label on gallery action page for a list containing tags. // TRANS: Dropdown field label on gallery action page for a list containing tags.
$this->dropdown('tag', _('Tag'), $content, $this->dropdown(
'tag',
_('Tag'),
$content,
// TRANS: Dropdown field title on gallery action page for a list containing tags. // TRANS: Dropdown field title on gallery action page for a list containing tags.
_('Choose a tag to narrow list.'), false, $tag); _('Choose a tag to narrow list.'),
false,
$tag
);
$this->hidden('nickname', $this->target->getNickname()); $this->hidden('nickname', $this->target->getNickname());
// TRANS: Submit button text on gallery action page. // TRANS: Submit button text on gallery action page.
$this->submit('submit', _m('BUTTON','Go')); $this->submit('submit', _m('BUTTON', 'Go'));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
$this->elementEnd('li'); $this->elementEnd('li');
@ -92,7 +104,7 @@ class GalleryAction extends ProfileAction
} }
// Get list of tags we tagged other users with // Get list of tags we tagged other users with
function getTags($lst, $usr) public function getTags($lst, $usr)
{ {
$profile_tag = new Notice_tag(); $profile_tag = new Notice_tag();
$profile_tag->query('SELECT DISTINCT(tag) ' . $profile_tag->query('SELECT DISTINCT(tag) ' .
@ -100,7 +112,7 @@ class GalleryAction extends ProfileAction
'WHERE tagger = ' . $this->target->id . ' ' . 'WHERE tagger = ' . $this->target->id . ' ' .
'AND ' . $usr . ' = ' . $this->target->id . ' ' . 'AND ' . $usr . ' = ' . $this->target->id . ' ' .
'AND ' . $lst . ' = tagged ' . 'AND ' . $lst . ' = tagged ' .
'AND tagger != tagged'); 'AND tagger <> tagged');
$tags = array(); $tags = array();
while ($profile_tag->fetch()) { while ($profile_tag->fetch()) {
$tags[] = $profile_tag->tag; $tags[] = $profile_tag->tag;
@ -109,12 +121,12 @@ class GalleryAction extends ProfileAction
return $tags; return $tags;
} }
function getAllTags() public function getAllTags()
{ {
return array(); return array();
} }
function showProfileBlock() public function showProfileBlock()
{ {
$block = new AccountProfileBlock($this, $this->target); $block = new AccountProfileBlock($this, $this->target);
$block->show(); $block->show();

View File

@ -1,35 +1,30 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Base class for sections showing lists of people * Base class for sections showing lists of people
* *
* 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 Widget * @category Widget
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Base class for sections * Base class for sections
@ -37,44 +32,32 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* These are the widgets that show interesting data about a person * These are the widgets that show interesting data about a person
* group, or site. * group, or site.
* *
* @category Widget * @copyright 2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @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 TopPostersSection extends ProfileSection class TopPostersSection extends ProfileSection
{ {
function getProfiles() public function getProfiles()
{ {
$qry = 'SELECT profile.*, count(*) as value ' . $limit = PROFILES_PER_SECTION;
$qry = 'SELECT profile.*, COUNT(*) AS value ' .
'FROM profile JOIN notice ON profile.id = notice.profile_id ' . 'FROM profile JOIN notice ON profile.id = notice.profile_id ' .
(common_config('public', 'localonly') ? 'WHERE is_local = 1 ' : '') . (common_config('public', 'localonly') ? 'WHERE is_local = 1 ' : '') .
'GROUP BY profile.id,nickname,fullname,profileurl,homepage,bio,location,profile.created,profile.modified,textsearch ' . 'GROUP BY profile.id, nickname, fullname, profileurl, homepage, bio, location, profile.created, profile.modified ' .
'ORDER BY value DESC '; 'ORDER BY value DESC LIMIT ' . $limit;
$limit = PROFILES_PER_SECTION; $profile = Memcached_DataObject::cachedQuery('Profile', $qry, 6 * 3600);
$offset = 0;
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$profile = Memcached_DataObject::cachedQuery('Profile',
$qry,
6 * 3600);
return $profile; return $profile;
} }
function title() public function title()
{ {
// TRANS: Title for top posters section. // TRANS: Title for top posters section.
return _('Top posters'); return _('Top posters');
} }
function divId() public function divId()
{ {
return 'top_posters'; return 'top_posters';
} }

View File

@ -1,76 +1,74 @@
<?php <?php
/** // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('STATUSNET') && !defined('LACONICA')) { defined('GNUSOCIAL') || die();
exit(1);
}
class Daemon class Daemon
{ {
var $daemonize = true; public $daemonize = true;
var $_id = 'generic'; public $_id = 'generic';
function __construct($daemonize = true) public function __construct($daemonize = true)
{ {
$this->daemonize = $daemonize; $this->daemonize = $daemonize;
} }
function name() public function name()
{ {
return null; return null;
} }
function get_id() public function get_id()
{ {
return $this->_id; return $this->_id;
} }
function set_id($id) public function set_id($id)
{ {
$this->_id = $id; $this->_id = $id;
} }
function background() public function background()
{ {
/* // Database connection will likely get lost after forking
* This prefers to Starting PHP 5.4 (dotdeb), maybe earlier for some version/distrib $this->resetDb();
* seems MySQL connection using mysqli driver get lost when fork.
* Need to unset it so that child process recreate it.
*
* @todo FIXME cleaner way to do it ?
*/
global $_DB_DATAOBJECT;
unset($_DB_DATAOBJECT['CONNECTIONS']);
$pid = pcntl_fork(); // Double-forking.
if ($pid < 0) { // error foreach (['single', 'double'] as $v) {
common_log(LOG_ERR, "Could not fork."); switch ($pid = pcntl_fork()) {
case -1: // error
common_log(LOG_ERR, 'Could not fork.');
return false; return false;
} else if ($pid > 0) { // parent case 0: // child
common_log(LOG_INFO, "Successfully forked."); if ($v === 'single') {
exit(0); posix_setsid();
} else { // child }
break;
default: // parent
if ($v === 'double') {
common_log(LOG_INFO, 'Successfully forked.');
}
die();
}
}
return true; return true;
} }
}
function alreadyRunning() public function alreadyRunning()
{ {
$pidfilename = $this->pidFilename(); $pidfilename = $this->pidFilename();
@ -89,7 +87,7 @@ class Daemon
} }
} }
function writePidFile() public function writePidFile()
{ {
$pidfilename = $this->pidFilename(); $pidfilename = $this->pidFilename();
@ -100,7 +98,7 @@ class Daemon
return file_put_contents($pidfilename, posix_getpid() . "\n"); return file_put_contents($pidfilename, posix_getpid() . "\n");
} }
function clearPidFile() public function clearPidFile()
{ {
$pidfilename = $this->pidFilename(); $pidfilename = $this->pidFilename();
if (!$pidfilename) { if (!$pidfilename) {
@ -109,7 +107,7 @@ class Daemon
return unlink($pidfilename); return unlink($pidfilename);
} }
function pidFilename() public function pidFilename()
{ {
$piddir = common_config('daemon', 'piddir'); $piddir = common_config('daemon', 'piddir');
if (!$piddir) { if (!$piddir) {
@ -122,15 +120,17 @@ class Daemon
return $piddir . '/' . $name . '.pid'; return $piddir . '/' . $name . '.pid';
} }
function changeUser() public function changeUser()
{ {
$groupname = common_config('daemon', 'group'); $groupname = common_config('daemon', 'group');
if ($groupname) { if ($groupname) {
$group_info = posix_getgrnam($groupname); $group_info = posix_getgrnam($groupname);
if (!$group_info) { if (!$group_info) {
common_log(LOG_WARNING, common_log(
'Ignoring unknown group for daemon: ' . $groupname); LOG_WARNING,
'Ignoring unknown group for daemon: ' . $groupname
);
} else { } else {
common_log(LOG_INFO, "Setting group to " . $groupname); common_log(LOG_INFO, "Setting group to " . $groupname);
posix_setgid($group_info['gid']); posix_setgid($group_info['gid']);
@ -142,8 +142,10 @@ class Daemon
if ($username) { if ($username) {
$user_info = posix_getpwnam($username); $user_info = posix_getpwnam($username);
if (!$user_info) { if (!$user_info) {
common_log(LOG_WARNING, common_log(
'Ignoring unknown user for daemon: ' . $username); LOG_WARNING,
'Ignoring unknown user for daemon: ' . $username
);
} else { } else {
common_log(LOG_INFO, "Setting user to " . $username); common_log(LOG_INFO, "Setting user to " . $username);
posix_setuid($user_info['uid']); posix_setuid($user_info['uid']);
@ -151,7 +153,7 @@ class Daemon
} }
} }
function runOnce() public function runOnce()
{ {
if ($this->alreadyRunning()) { if ($this->alreadyRunning()) {
common_log(LOG_INFO, $this->name() . ' already running. Exiting.'); common_log(LOG_INFO, $this->name() . ' already running. Exiting.');
@ -169,7 +171,7 @@ class Daemon
$this->clearPidFile(); $this->clearPidFile();
} }
function run() public function run()
{ {
return true; return true;
} }

View File

@ -1,29 +1,29 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* GNU social - a federating social network
*
*
* 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 Config * @category Config
* @package GNUsocial * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org * @copyright 2008-2009, 2019 Free Software Foundation http://fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link https://www.gnu.org/software/social/
*/ */
defined('GNUSOCIAL') || die();
$default = $default =
array('site' => array('site' =>
array('name' => 'Just another GNU social node', array('name' => 'Just another GNU social node',
@ -74,7 +74,7 @@ $default =
'mirror' => null, 'mirror' => null,
'utf8' => true, 'utf8' => true,
'db_driver' => 'DB', # XXX: JanRain libs only work with DB 'db_driver' => 'DB', # XXX: JanRain libs only work with DB
'quote_identifiers' => false, 'quote_identifiers' => true,
'type' => 'mysql', 'type' => 'mysql',
'schemacheck' => 'runtime', // 'runtime' or 'script' 'schemacheck' => 'runtime', // 'runtime' or 'script'
'annotate_queries' => false, // true to add caller comments to queries, eg /* POST Notice::saveNew */ 'annotate_queries' => false, // true to add caller comments to queries, eg /* POST Notice::saveNew */

View File

@ -68,11 +68,11 @@ abstract class Installer
'check_module' => 'mysqli', 'check_module' => 'mysqli',
'scheme' => 'mysqli', // DSN prefix for PEAR::DB 'scheme' => 'mysqli', // DSN prefix for PEAR::DB
], ],
/*'pgsql' => [ 'pgsql' => [
'name' => 'PostgreSQL', 'name' => 'PostgreSQL 11+',
'check_module' => 'pgsql', 'check_module' => 'pgsql',
'scheme' => 'pgsql', // DSN prefix for PEAR::DB 'scheme' => 'pgsql', // DSN prefix for PEAR::DB
]*/ ]
]; ];
/** /**
@ -304,20 +304,34 @@ abstract class Installer
throw new Exception('Cannot connect to database: ' . $conn->getMessage()); throw new Exception('Cannot connect to database: ' . $conn->getMessage());
} }
// ensure database encoding is UTF8 switch ($this->dbtype) {
$conn->query('SET NAMES utf8mb4'); case 'pgsql':
if ($this->dbtype == 'mysql') { // ensure the database encoding is UTF8
$server_encoding = $conn->getRow("SHOW VARIABLES LIKE 'character_set_server'")[1]; $conn->query("SET NAMES 'UTF8'");
if ($server_encoding != 'utf8mb4') {
$this->updateStatus("GNU social requires UTF8 character encoding. Your database is " . htmlentities($server_encoding));
return false;
}
} elseif ($this->dbtype == 'pgsql') {
$server_encoding = $conn->getRow('SHOW server_encoding')[0]; $server_encoding = $conn->getRow('SHOW server_encoding')[0];
if ($server_encoding != 'UTF8') { if ($server_encoding !== 'UTF8') {
$this->updateStatus("GNU social requires UTF8 character encoding. Your database is " . htmlentities($server_encoding)); $this->updateStatus(
'GNU social requires the UTF8 character encoding. Yours is ' .
htmlentities($server_encoding)
);
return false; return false;
} }
break;
case 'mysql':
// ensure the database encoding is utf8mb4
$conn->query("SET NAMES 'utf8mb4'");
$server_encoding = $conn->getRow("SHOW VARIABLES LIKE 'character_set_server'")[1];
if ($server_encoding !== 'utf8mb4') {
$this->updateStatus(
'GNU social requires the utf8mb4 character encoding. Yours is ' .
htmlentities($server_encoding)
);
return false;
}
break;
default:
$this->updateStatus('Unknown DB type selected: ' . $this->dbtype);
return false;
} }
$res = $this->updateStatus("Creating database tables..."); $res = $this->updateStatus("Creating database tables...");
@ -362,7 +376,7 @@ abstract class Installer
*/ */
public function createCoreTables(DB_common $conn): bool public function createCoreTables(DB_common $conn): bool
{ {
$schema = Schema::get($conn); $schema = Schema::get($conn, $this->dbtype);
$tableDefs = $this->getCoreSchema(); $tableDefs = $this->getCoreSchema();
foreach ($tableDefs as $name => $def) { foreach ($tableDefs as $name => $def) {
if (defined('DEBUG_INSTALLER')) { if (defined('DEBUG_INSTALLER')) {
@ -446,7 +460,6 @@ abstract class Installer
// database // database
"\$config['db']['database'] = {$vals['db_database']};\n\n" . "\$config['db']['database'] = {$vals['db_database']};\n\n" .
($this->db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n" : '') .
"\$config['db']['type'] = {$vals['db_type']};\n\n" . "\$config['db']['type'] = {$vals['db_type']};\n\n" .
"// Uncomment below for better performance. Just remember you must run\n" . "// Uncomment below for better performance. Just remember you must run\n" .
@ -457,7 +470,7 @@ abstract class Installer
$cfg = str_replace("\n", PHP_EOL, $cfg); $cfg = str_replace("\n", PHP_EOL, $cfg);
// write configuration file out to install directory // write configuration file out to install directory
$res = file_put_contents(INSTALLDIR . '/config.php', $cfg); $res = file_put_contents(INSTALLDIR . DIRECTORY_SEPARATOR . 'config.php', $cfg);
return $res; return $res;
} }

View File

@ -167,7 +167,7 @@ class InternalSessionHandler implements SessionHandlerInterface
$ids = []; $ids = [];
$session = new Session(); $session = new Session();
$session->whereAdd('modified < "' . $epoch . '"'); $session->whereAdd("modified < TIMESTAMP '" . $epoch . "'");
$session->selectAdd(); $session->selectAdd();
$session->selectAdd('id'); $session->selectAdd('id');

View File

@ -1,36 +1,33 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool * Utilities for sending email
*
* utilities for sending email
*
* 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 Mail * @category Mail
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @author Robin Millette <millette@status.net> * @author Robin Millette <millette@status.net>
* @author Sarven Capadisli <csarven@status.net> * @author Sarven Capadisli <csarven@status.net>
* @copyright 2008 StatusNet, Inc. * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
require_once 'Mail.php'; require_once 'Mail.php';
@ -49,8 +46,10 @@ function mail_backend()
if (!$backend) { if (!$backend) {
$mail = new Mail(); $mail = new Mail();
$backend = $mail->factory(common_config('mail', 'backend'), $backend = $mail->factory(
common_config('mail', 'params') ?: array()); common_config('mail', 'backend'),
common_config('mail', 'params') ?: []
);
if ($_PEAR->isError($backend)) { if ($_PEAR->isError($backend)) {
throw new EmailException($backend->getMessage(), $backend->getCode()); throw new EmailException($backend->getMessage(), $backend->getCode());
} }
@ -124,7 +123,6 @@ function mail_notify_from()
$notifyfrom = common_config('mail', 'notifyfrom'); $notifyfrom = common_config('mail', 'notifyfrom');
if (!$notifyfrom) { if (!$notifyfrom) {
$domain = mail_domain(); $domain = mail_domain();
$notifyfrom = '"'. str_replace('"', '\\"', common_config('site', 'name')) .'" <noreply@'.$domain.'>'; $notifyfrom = '"'. str_replace('"', '\\"', common_config('site', 'name')) .'" <noreply@'.$domain.'>';
@ -194,7 +192,6 @@ function mail_subscribe_notify_profile($listenee, $other)
{ {
if ($other->hasRight(Right::EMAILONSUBSCRIBE) && if ($other->hasRight(Right::EMAILONSUBSCRIBE) &&
$listenee->email && $listenee->emailnotifysub) { $listenee->email && $listenee->emailnotifysub) {
$profile = $listenee->getProfile(); $profile = $listenee->getProfile();
$name = $profile->getBestName(); $name = $profile->getBestName();
@ -211,15 +208,19 @@ function mail_subscribe_notify_profile($listenee, $other)
$headers['To'] = $name . ' <' . $listenee->email . '>'; $headers['To'] = $name . ' <' . $listenee->email . '>';
// TRANS: Subject of new-subscriber notification e-mail. // TRANS: Subject of new-subscriber notification e-mail.
// TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename. // TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('%1$s is now following you on %2$s.'), $headers['Subject'] = sprintf(
_('%1$s is now following you on %2$s.'),
$other->getBestName(), $other->getBestName(),
common_config('site', 'name')); common_config('site', 'name')
);
// TRANS: Main body of new-subscriber notification e-mail. // 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: %1$s is the subscriber's long name, %2$s is the StatusNet sitename.
$body = sprintf(_('%1$s is now following you on %2$s.'), $body = sprintf(
_('%1$s is now following you on %2$s.'),
$long_name, $long_name,
common_config('site', 'name')) . common_config('site', 'name')
) .
mail_profile_block($other) . mail_profile_block($other) .
mail_footer_block(); mail_footer_block();
@ -233,7 +234,6 @@ function mail_subscribe_pending_notify_profile($listenee, $other)
{ {
if ($other->hasRight(Right::EMAILONSUBSCRIBE) && if ($other->hasRight(Right::EMAILONSUBSCRIBE) &&
$listenee->email && $listenee->emailnotifysub) { $listenee->email && $listenee->emailnotifysub) {
$profile = $listenee->getProfile(); $profile = $listenee->getProfile();
$name = $profile->getBestName(); $name = $profile->getBestName();
@ -251,18 +251,22 @@ function mail_subscribe_pending_notify_profile($listenee, $other)
$headers['To'] = $name . ' <' . $listenee->email . '>'; $headers['To'] = $name . ' <' . $listenee->email . '>';
// TRANS: Subject of pending new-subscriber notification e-mail. // TRANS: Subject of pending new-subscriber notification e-mail.
// TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename. // 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 '. $headers['Subject'] = sprintf(
_('%1$s would like to listen to '.
'your notices on %2$s.'), 'your notices on %2$s.'),
$other->getBestName(), $other->getBestName(),
common_config('site', 'name')); common_config('site', 'name')
);
// TRANS: Main body of pending new-subscriber notification e-mail. // 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. // 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. ' . $body = sprintf(
_('%1$s would like to listen to your notices on %2$s. ' .
'You may approve or reject their subscription at %3$s'), 'You may approve or reject their subscription at %3$s'),
$long_name, $long_name,
common_config('site', 'name'), common_config('site', 'name'),
common_local_url('subqueue', array('nickname' => $listenee->nickname))) . common_local_url('subqueue', ['nickname' => $listenee->nickname])
) .
mail_profile_block($other) . mail_profile_block($other) .
mail_footer_block(); mail_footer_block();
@ -277,13 +281,15 @@ function mail_footer_block()
// TRANS: Common footer block for StatusNet notification emails. // TRANS: Common footer block for StatusNet notification emails.
// TRANS: %1$s is the StatusNet sitename, // TRANS: %1$s is the StatusNet sitename,
// TRANS: %2$s is a link to the addressed user's e-mail settings. // TRANS: %2$s is a link to the addressed user's e-mail settings.
return "\n\n" . sprintf(_('Faithfully yours,'. return "\n\n" . sprintf(
_('Faithfully yours,'.
"\n".'%1$s.'."\n\n". "\n".'%1$s.'."\n\n".
"----\n". "----\n".
"Change your email address or ". "Change your email address or ".
"notification options at ".'%2$s'), "notification options at ".'%2$s'),
common_config('site', 'name'), common_config('site', 'name'),
common_local_url('emailsettings')) . "\n"; common_local_url('emailsettings')
) . "\n";
} }
/** /**
@ -326,10 +332,12 @@ function mail_profile_block($profile)
// TRANS: This is a paragraph in a new-subscriber e-mail. // TRANS: This is a paragraph in a new-subscriber e-mail.
// TRANS: %s is a URL where the subscriber can be reported as abusive. // TRANS: %s is a URL where the subscriber can be reported as abusive.
$out[] = sprintf(_('If you believe this account is being used abusively, ' . $out[] = sprintf(
_('If you believe this account is being used abusively, ' .
'you can block them from your subscribers list and ' . 'you can block them from your subscribers list and ' .
'report as spam to site administrators at %s.'), 'report as spam to site administrators at %s.'),
$blocklink); $blocklink
);
$out[] = ""; $out[] = "";
return implode("\n", $out); return implode("\n", $out);
@ -354,18 +362,22 @@ function mail_new_incoming_notify($user)
$headers['To'] = $name . ' <' . $user->email . '>'; $headers['To'] = $name . ' <' . $user->email . '>';
// TRANS: Subject of notification mail for new posting email address. // TRANS: Subject of notification mail for new posting email address.
// TRANS: %s is the StatusNet sitename. // TRANS: %s is the StatusNet sitename.
$headers['Subject'] = sprintf(_('New email address for posting to %s'), $headers['Subject'] = sprintf(
common_config('site', 'name')); _('New email address for posting to %s'),
common_config('site', 'name')
);
// TRANS: Body of notification mail for new posting email address. // TRANS: Body of notification mail for new posting email address.
// TRANS: %1$s is the StatusNet sitename, %2$s is the e-mail address to send // TRANS: %1$s is the StatusNet sitename, %2$s is the e-mail address to send
// TRANS: to to post by e-mail, %3$s is a URL to more instructions. // 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". $body = sprintf(
_("You have a new posting address on %1\$s.\n\n".
"Send email to %2\$s to post new messages.\n\n". "Send email to %2\$s to post new messages.\n\n".
"More email instructions at %3\$s."), "More email instructions at %3\$s."),
common_config('site', 'name'), common_config('site', 'name'),
$user->incomingemail, $user->incomingemail,
common_local_url('doc', array('title' => 'email'))) . common_local_url('doc', ['title' => 'email'])
) .
mail_footer_block(); mail_footer_block();
mail_send($user->email, $headers, $body); mail_send($user->email, $headers, $body);
@ -402,42 +414,58 @@ function mail_broadcast_notice_sms($notice)
$user = new User(); $user = new User();
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
$replies = $notice->getReplies(); $replies = $notice->getReplies();
$user->query('SELECT nickname, smsemail, incomingemail ' .
"FROM $UT LEFT OUTER JOIN subscription " . $repliesQry = '';
"ON $UT.id = subscription.subscriber " . if (!empty($replies)) {
'AND subscription.subscribed = ' . $notice->profile_id . ' ' . $repliesQry = sprintf(
'AND subscription.subscribed != subscription.subscriber ' . 'OR %s.id IN (%s)',
$user->escapedTableName(),
implode(',', $replies)
);
}
$user->query(sprintf(
'SELECT nickname, smsemail, incomingemail ' .
'FROM %1$s LEFT JOIN subscription ' .
'ON %1$s.id = subscription.subscriber ' .
'AND subscription.subscribed = %2$d ' .
'AND subscription.subscribed <> subscription.subscriber ' .
// Users (other than the sender) who `want SMS notices': // Users (other than the sender) who `want SMS notices':
"WHERE $UT.id != " . $notice->profile_id . ' ' . 'WHERE %1$s.id <> %2$d ' .
"AND $UT.smsemail IS NOT null " . 'AND %1$s.smsemail IS NOT NULL ' .
"AND $UT.smsnotify = 1 " . 'AND %1$s.smsnotify = TRUE ' .
// ... where either the user _is_ subscribed to the sender // ... where either the user _is_ subscribed to the sender
// (any of the "subscription" fields IS NOT null) // (any of the "subscription" fields IS NOT NULL)
// and wants to get SMS for all of this scribe's notices... // and wants to get SMS for all of this scribe's notices...
'AND (subscription.sms = 1 ' . 'AND (subscription.sms = TRUE ' .
// ... or where the user was mentioned in // ... or where the user was mentioned in
// or replied-to with the notice: // or replied-to with the notice:
($replies ? sprintf("OR $UT.id in (%s)", $repliesQry .
implode(',', $replies)) ')',
: '') . $user->escapedTableName(),
')'); $notice->profile_id
));
while ($user->fetch()) { while ($user->fetch()) {
common_log(LOG_INFO, common_log(
LOG_INFO,
'Sending notice ' . $notice->id . ' to ' . $user->smsemail, 'Sending notice ' . $notice->id . ' to ' . $user->smsemail,
__FILE__); __FILE__
$success = mail_send_sms_notice_address($notice, );
$success = mail_send_sms_notice_address(
$notice,
$user->smsemail, $user->smsemail,
$user->incomingemail, $user->incomingemail,
$user->nickname); $user->nickname
);
if (!$success) { if (!$success) {
// XXX: Not sure, but I think that's the right thing to do // XXX: Not sure, but I think that's the right thing to do
common_log(LOG_WARNING, common_log(
'Sending notice ' . $notice->id . ' to ' . LOG_WARNING,
$user->smsemail . ' FAILED, cancelling.', 'Sending notice ' . $notice->id . ' to ' . $user->smsemail . ' FAILED, canceling.',
__FILE__); __FILE__
);
return false; return false;
} }
} }
@ -462,10 +490,12 @@ function mail_broadcast_notice_sms($notice)
*/ */
function mail_send_sms_notice($notice, $user) function mail_send_sms_notice($notice, $user)
{ {
return mail_send_sms_notice_address($notice, return mail_send_sms_notice_address(
$notice,
$user->smsemail, $user->smsemail,
$user->incomingemail, $user->incomingemail,
$user->nickname); $user->nickname
);
} }
/** /**
@ -496,8 +526,7 @@ function mail_send_sms_notice_address($notice, $smsemail, $incomingemail, $nickn
$headers['To'] = $to; $headers['To'] = $to;
// TRANS: Subject line for SMS-by-email notification messages. // TRANS: Subject line for SMS-by-email notification messages.
// TRANS: %s is the posting user's nickname. // TRANS: %s is the posting user's nickname.
$headers['Subject'] = sprintf(_('%s status'), $headers['Subject'] = sprintf(_('%s status'), $other->getBestName());
$other->getBestName());
$body = $notice->content; $body = $notice->content;
@ -554,14 +583,16 @@ function mail_notify_nudge($from, $to)
// TRANS: Body for 'nudge' notification email. // 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: %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. // TRANS: %3$s is a URL to post notices at.
$body = sprintf(_("%1\$s (%2\$s) is wondering what you are up to ". $body = sprintf(
"these days and is inviting you to post some news.\n\n". _('%1$s (%2$s) is wondering what you are up to ' .
"So let's hear from you :)\n\n". "these days and is inviting you to post some news.\n\n" .
"%3\$s\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."), "Don't reply to this email; it won't get to them."),
$from_profile->getBestName(), $from_profile->getBestName(),
$from->nickname, $from->nickname,
common_local_url('all', array('nickname' => $to->nickname))) . common_local_url('all', ['nickname' => $to->nickname])
) .
mail_footer_block(); mail_footer_block();
common_switch_locale(); common_switch_locale();
@ -612,7 +643,8 @@ function mail_notify_message(Notice $message, Profile $from = null, ?array $to =
// TRANS: Body for direct-message notification email. // 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: %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: %3$s is the message content, %4$s a URL to the message,
$body = sprintf(_("%1\$s (%2\$s) sent you a private message:\n\n". $body = sprintf(
_("%1\$s (%2\$s) sent you a private message:\n\n".
"------------------------------------------------------\n". "------------------------------------------------------\n".
"%3\$s\n". "%3\$s\n".
"------------------------------------------------------\n\n". "------------------------------------------------------\n\n".
@ -622,7 +654,8 @@ function mail_notify_message(Notice $message, Profile $from = null, ?array $to =
$from->getBestName(), $from->getBestName(),
$from->getNickname(), $from->getNickname(),
$message->getContent(), $message->getContent(),
common_local_url('newmessage', ['to' => $from->getID()])) . common_local_url('newmessage', ['to' => $from->getID()])
) .
mail_footer_block(); mail_footer_block();
$headers = _mail_prepare_headers('message', $t->getNickname(), $from->getNickname()); $headers = _mail_prepare_headers('message', $t->getNickname(), $from->getNickname());
@ -675,8 +708,11 @@ function mail_notify_attn(Profile $rcpt, Notice $notice)
common_switch_locale($user->language); common_switch_locale($user->language);
if ($notice->hasConversation()) { if ($notice->hasConversation()) {
$conversationUrl = common_local_url('conversation', $conversationUrl = common_local_url(
array('id' => $notice->conversation)).'#notice-'.$notice->getID(); 'conversation',
['id' => $notice->conversation]
) . '#notice-'.$notice->getID();
// TRANS: Line in @-reply notification e-mail. %s is conversation URL. // TRANS: Line in @-reply notification e-mail. %s is conversation URL.
$conversationEmailText = sprintf(_("The full conversation can be read here:\n\n". $conversationEmailText = sprintf(_("The full conversation can be read here:\n\n".
"\t%s"), $conversationUrl) . "\n\n"; "\t%s"), $conversationUrl) . "\n\n";
@ -689,11 +725,12 @@ function mail_notify_attn(Profile $rcpt, Notice $notice)
$subject = sprintf(_('%1$s sent a notice to your attention'), $sender->getFancyName()); $subject = sprintf(_('%1$s sent a notice to your attention'), $sender->getFancyName());
// TRANS: Body of @-reply notification e-mail. // TRANS: Body of @-reply notification e-mail.
// TRANS: %1$s is the sending user's name, $2$s is the StatusNet sitename, // TRANS: %1$s is the sending user's name, $2$s is the GNU social sitename,
// TRANS: %3$s is a URL to the notice, %4$s is the notice text, // TRANS: %3$s is a URL to the notice, %4$s is the notice text,
// TRANS: %5$s is the text "The full conversation can be read here:" and a URL to the full conversion if it exists (otherwise empty), // TRANS: %5$s is the text "The full conversation can be read here:" and 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 @-replies for the addressed user, // 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". $body = sprintf(
_("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
"The notice is here:\n\n". "The notice is here:\n\n".
"\t%3\$s\n\n" . "\t%3\$s\n\n" .
"It reads:\n\n". "It reads:\n\n".
@ -703,16 +740,23 @@ function mail_notify_attn(Profile $rcpt, Notice $notice)
"\t%6\$s\n\n" . "\t%6\$s\n\n" .
"The list of all @-replies for you here:\n\n" . "The list of all @-replies for you here:\n\n" .
"%7\$s"), "%7\$s"),
$sender->getFancyName(),//%1 $sender->getFancyName(), //%1
common_config('site', 'name'),//%2 common_config('site', 'name'), //%2
common_local_url('shownotice', common_local_url(
array('notice' => $notice->getID())),//%3 'shownotice',
$notice->getContent(),//%4 ['notice' => $notice->getID()]
$conversationEmailText,//%5 ), //%3
common_local_url('newnotice', $notice->getContent(), //%4
array('replyto' => $sender->getNickname(), 'inreplyto' => $notice->getID())),//%6 $conversationEmailText, //%5
common_local_url('replies', common_local_url(
array('nickname' => $rcpt->getNickname()))) . //%7 'newnotice',
['replyto' => $sender->getNickname(), 'inreplyto' => $notice->getID()]
), //%6
common_local_url(
'replies',
['nickname' => $rcpt->getNickname()]
)
) . //%7
mail_footer_block(); mail_footer_block();
$headers = _mail_prepare_headers('mention', $rcpt->getNickname(), $sender->getNickname()); $headers = _mail_prepare_headers('mention', $rcpt->getNickname(), $sender->getNickname());
@ -764,20 +808,23 @@ function mail_notify_group_join($group, $joiner)
$headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>'; $headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>';
// TRANS: Subject of group join notification e-mail. // 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. // 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 '. $headers['Subject'] = sprintf(
'your group %2$s on %3$s'), _('%1$s has joined your group %2$s on %3$s'),
$joiner->getBestName(), $joiner->getBestName(),
$group->getBestName(), $group->getBestName(),
common_config('site', 'name')); common_config('site', 'name')
);
// TRANS: Main body of group join notification e-mail. // 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: %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: %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. // 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.'), $body = sprintf(
_('%1$s has joined your group %2$s on %3$s.'),
$joiner->getFancyName(), $joiner->getFancyName(),
$group->getFancyName(), $group->getFancyName(),
common_config('site', 'name')) . common_config('site', 'name')
) .
mail_profile_block($joiner) . mail_profile_block($joiner) .
mail_footer_block(); mail_footer_block();
@ -811,20 +858,24 @@ function mail_notify_group_join_pending($group, $joiner)
$headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>'; $headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>';
// TRANS: Subject of pending group join request notification e-mail. // 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. // 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.'), $headers['Subject'] = sprintf(
_('%1$s wants to join your group %2$s on %3$s.'),
$joiner->getBestName(), $joiner->getBestName(),
$group->getBestName(), $group->getBestName(),
common_config('site', 'name')); common_config('site', 'name')
);
// TRANS: Main body of pending group join request notification e-mail. // 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: %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. // 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. ' . $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'), 'You may approve or reject their group membership at %4$s'),
$joiner->getFancyName(), $joiner->getFancyName(),
$group->getFancyName(), $group->getFancyName(),
common_config('site', 'name'), common_config('site', 'name'),
common_local_url('groupqueue', array('nickname' => $group->nickname))) . common_local_url('groupqueue', ['nickname' => $group->nickname])
) .
mail_profile_block($joiner) . mail_profile_block($joiner) .
mail_footer_block(); mail_footer_block();

View File

@ -1,21 +1,20 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2010, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>. defined('GNUSOCIAL') || die();
*/
/** /**
* Base class for daemon that can launch one or more processing threads, * Base class for daemon that can launch one or more processing threads,
@ -34,14 +33,14 @@
*/ */
abstract class SpawningDaemon extends Daemon abstract class SpawningDaemon extends Daemon
{ {
protected $threads=1; protected $threads = 1;
const EXIT_OK = 0; const EXIT_OK = 0;
const EXIT_ERR = 1; const EXIT_ERR = 1;
const EXIT_SHUTDOWN = 100; const EXIT_SHUTDOWN = 100;
const EXIT_RESTART = 101; const EXIT_RESTART = 101;
function __construct($id=null, $daemonize=true, $threads=1) public function __construct($id = null, $daemonize = true, $threads = 1)
{ {
parent::__construct($daemonize); parent::__construct($daemonize);
@ -56,7 +55,7 @@ abstract class SpawningDaemon extends Daemon
* *
* @return int exit code; use self::EXIT_SHUTDOWN to request not to respawn. * @return int exit code; use self::EXIT_SHUTDOWN to request not to respawn.
*/ */
public abstract function runThread(); abstract public function runThread();
/** /**
* Spawn one or more background processes and let them start running. * Spawn one or more background processes and let them start running.
@ -69,17 +68,17 @@ abstract class SpawningDaemon extends Daemon
* though ParallelizingDaemon is probably better for workloads * though ParallelizingDaemon is probably better for workloads
* that have forseeable endpoints. * that have forseeable endpoints.
*/ */
function run() public function run()
{ {
$this->initPipes(); $this->initPipes();
$children = array(); $children = [];
for ($i = 1; $i <= $this->threads; $i++) { for ($i = 1; $i <= $this->threads; $i++) {
$pid = pcntl_fork(); $pid = pcntl_fork();
if ($pid < 0) { if ($pid < 0) {
$this->log(LOG_ERR, "Couldn't fork for thread $i; aborting\n"); $this->log(LOG_ERR, "Couldn't fork for thread $i; aborting\n");
exit(1); exit(1);
} else if ($pid == 0) { } elseif ($pid === 0) {
$this->initAndRunChild($i); $this->initAndRunChild($i);
} else { } else {
$this->log(LOG_INFO, "Spawned thread $i as pid $pid"); $this->log(LOG_INFO, "Spawned thread $i as pid $pid");
@ -101,7 +100,7 @@ abstract class SpawningDaemon extends Daemon
if (pcntl_wifexited($status)) { if (pcntl_wifexited($status)) {
$exitCode = pcntl_wexitstatus($status); $exitCode = pcntl_wexitstatus($status);
$info = "status $exitCode"; $info = "status $exitCode";
} else if (pcntl_wifsignaled($status)) { } elseif (pcntl_wifsignaled($status)) {
$exitCode = self::EXIT_ERR; $exitCode = self::EXIT_ERR;
$signal = pcntl_wtermsig($status); $signal = pcntl_wtermsig($status);
$info = "signal $signal"; $info = "signal $signal";
@ -114,7 +113,7 @@ abstract class SpawningDaemon extends Daemon
$pid = pcntl_fork(); $pid = pcntl_fork();
if ($pid < 0) { if ($pid < 0) {
$this->log(LOG_ERR, "Couldn't fork to respawn thread $i; aborting thread.\n"); $this->log(LOG_ERR, "Couldn't fork to respawn thread $i; aborting thread.\n");
} else if ($pid == 0) { } elseif ($pid === 0) {
$this->initAndRunChild($i); $this->initAndRunChild($i);
} else { } else {
$this->log(LOG_INFO, "Respawned thread $i as pid $pid"); $this->log(LOG_INFO, "Respawned thread $i as pid $pid");
@ -134,7 +133,7 @@ abstract class SpawningDaemon extends Daemon
* Create an IPC socket pair which child processes can use to detect * Create an IPC socket pair which child processes can use to detect
* if the parent process has been killed. * if the parent process has been killed.
*/ */
function initPipes() public function initPipes()
{ {
$sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0); $sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
if ($sockets) { if ($sockets) {
@ -197,10 +196,19 @@ abstract class SpawningDaemon extends Daemon
*/ */
protected function resetDb() protected function resetDb()
{ {
// @fixme do we need to explicitly open the db too
// or is this implied?
global $_DB_DATAOBJECT; global $_DB_DATAOBJECT;
unset($_DB_DATAOBJECT['CONNECTIONS']);
// Can't be called statically
$user = new User();
$conn = $user->getDatabaseConnection();
$conn->disconnect();
// Remove the disconnected connection from the list
foreach ($_DB_DATAOBJECT['CONNECTIONS'] as $k => $v) {
if ($v === $conn) {
unset($_DB_DATAOBJECT['CONNECTIONS'][$k]);
}
}
// Reconnect main memcached, or threads will stomp on // Reconnect main memcached, or threads will stomp on
// each other and corrupt their requests. // each other and corrupt their requests.
@ -216,14 +224,13 @@ abstract class SpawningDaemon extends Daemon
} }
} }
function log($level, $msg) public function log($level, $msg)
{ {
common_log($level, get_class($this) . ' ('. $this->get_id() .'): '.$msg); common_log($level, get_class($this) . ' ('. $this->get_id() .'): '.$msg);
} }
function name() public function name()
{ {
return strtolower(get_class($this).'.'.$this->get_id()); return strtolower(get_class($this).'.'.$this->get_id());
} }
} }

View File

@ -1,24 +1,23 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008-2011, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>.
*/
/* XXX: break up into separate modules (HTTP, user, files) */ /* XXX: break up into separate modules (HTTP, user, files) */
defined('GNUSOCIAL') || die();
/** /**
* Show a server error. * Show a server error.
*/ */
@ -52,12 +51,14 @@ function common_init_locale($language=null)
} }
putenv('LANGUAGE='.$language); putenv('LANGUAGE='.$language);
putenv('LANG='.$language); putenv('LANG='.$language);
$ok = setlocale(LC_ALL, $ok = setlocale(
$language . ".utf8", LC_ALL,
$language . ".UTF8", $language . '.utf8',
$language . ".utf-8", $language . '.UTF8',
$language . ".UTF-8", $language . '.utf-8',
$language); $language . '.UTF-8',
$language
);
return $ok; return $ok;
} }
@ -356,12 +357,14 @@ function common_set_cookie($key, $value, $expiration=0)
} else { } else {
$cookiepath = '/'; $cookiepath = '/';
} }
return setcookie($key, return setcookie(
$key,
$value, $value,
$expiration, $expiration,
$cookiepath, $cookiepath,
$server, $server,
GNUsocial::useHTTPS()); GNUsocial::useHTTPS()
);
} }
define('REMEMBERME', 'rememberme'); define('REMEMBERME', 'rememberme');
@ -592,7 +595,6 @@ function common_to_alphanumeric($str)
function common_purify($html, array $args=[]) function common_purify($html, array $args=[])
{ {
$cfg = \HTMLPurifier_Config::createDefault(); $cfg = \HTMLPurifier_Config::createDefault();
/** /**
* rel values that should be avoided since they can be used to infer * rel values that should be avoided since they can be used to infer
@ -839,9 +841,10 @@ function common_find_mentions($text, Profile $sender, Notice $parent=null)
} }
$tagged = $sender->getTaggedSubscribers($tag); $tagged = $sender->getTaggedSubscribers($tag);
$url = common_local_url('showprofiletag', $url = common_local_url(
['nickname' => $sender->getNickname(), 'showprofiletag',
'tag' => $tag]); ['nickname' => $sender->getNickname(), 'tag' => $tag]
);
$mentions[] = ['mentioned' => $tagged, $mentions[] = ['mentioned' => $tagged,
'type' => 'list', 'type' => 'list',
@ -888,17 +891,21 @@ function common_find_mentions($text, Profile $sender, Notice $parent=null)
function common_find_mentions_raw($text, $preMention='@') function common_find_mentions_raw($text, $preMention='@')
{ {
$tmatches = []; $tmatches = [];
preg_match_all('/^T (' . Nickname::DISPLAY_FMT . ') /', preg_match_all(
'/^T (' . Nickname::DISPLAY_FMT . ') /',
$text, $text,
$tmatches, $tmatches,
PREG_OFFSET_CAPTURE); PREG_OFFSET_CAPTURE
);
$atmatches = []; $atmatches = [];
// the regexp's "(?!\@)" makes sure it doesn't matches the single "@remote" in "@remote@server.com" // the regexp's "(?!\@)" makes sure it doesn't matches the single "@remote" in "@remote@server.com"
preg_match_all('/'.Nickname::BEFORE_MENTIONS.preg_quote($preMention, '/').'(' . Nickname::DISPLAY_FMT . ')\b(?!\@)/', preg_match_all(
'/' . Nickname::BEFORE_MENTIONS . preg_quote($preMention, '/') . '(' . Nickname::DISPLAY_FMT . ')\b(?!\@)/',
$text, $text,
$atmatches, $atmatches,
PREG_OFFSET_CAPTURE); PREG_OFFSET_CAPTURE
);
$matches = array_merge($tmatches[1], $atmatches[1]); $matches = array_merge($tmatches[1], $atmatches[1]);
return $matches; return $matches;
@ -961,7 +968,8 @@ function common_url_schemes($filter = null)
$schemes, $schemes,
function ($scheme) use ($filter) { function ($scheme) use ($filter) {
return is_null($filter) || ($scheme & $filter); return is_null($filter) || ($scheme & $filter);
}) }
)
); );
} }
@ -1339,8 +1347,10 @@ function common_relative_profile($sender, $nickname, $dt=null)
// Try to find profiles this profile is subscribed to that have this nickname // Try to find profiles this profile is subscribed to that have this nickname
$recipient = new Profile(); $recipient = new Profile();
// XXX: use a join instead of a subquery $recipient->whereAdd(
$recipient->whereAdd('EXISTS (SELECT subscribed from subscription where subscriber = '.intval($sender->id).' and subscribed = id)', 'AND'); sprintf('id IN (SELECT subscribed FROM subscription WHERE subscriber = %d)', $sender->id),
'AND'
);
$recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND'); $recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND');
if ($recipient->find(true)) { if ($recipient->find(true)) {
// XXX: should probably differentiate between profiles with // XXX: should probably differentiate between profiles with
@ -1349,8 +1359,10 @@ function common_relative_profile($sender, $nickname, $dt=null)
} }
// Try to find profiles that listen to this profile and that have this nickname // Try to find profiles that listen to this profile and that have this nickname
$recipient = new Profile(); $recipient = new Profile();
// XXX: use a join instead of a subquery $recipient->whereAdd(
$recipient->whereAdd('EXISTS (SELECT subscriber from subscription where subscribed = '.intval($sender->id).' and subscriber = id)', 'AND'); sprintf('id IN (SELECT subscriber FROM subscription WHERE subscribed = %d)', $sender->id),
'AND'
);
$recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND'); $recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND');
if ($recipient->find(true)) { if ($recipient->find(true)) {
// XXX: should probably differentiate between profiles with // XXX: should probably differentiate between profiles with
@ -1701,11 +1713,13 @@ function common_enqueue_notice($notice)
function common_profile_url($nickname) function common_profile_url($nickname)
{ {
return common_local_url('showstream', return common_local_url(
'showstream',
['nickname' => $nickname], ['nickname' => $nickname],
null, null,
null, null,
false); false
);
} }
/** /**
@ -2210,11 +2224,13 @@ function common_remove_magic_from_request()
function common_user_uri(&$user) function common_user_uri(&$user)
{ {
return common_local_url('userbyid', return common_local_url(
'userbyid',
['id' => $user->id], ['id' => $user->id],
null, null,
null, null,
false); false
);
} }
/** /**
@ -2225,11 +2241,12 @@ function common_user_uri(&$user)
* alphanums and remove lookalikes (0, O, 1, I) = 32 chars = 5 bits to make it easy for the user to type in * alphanums and remove lookalikes (0, O, 1, I) = 32 chars = 5 bits to make it easy for the user to type in
* @return string confirmation_code of length $bits/5 * @return string confirmation_code of length $bits/5
*/ */
function common_confirmation_code($bits, $codechars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ') { function common_confirmation_code($bits, $codechars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ')
{
$chars = ceil($bits/5); $chars = ceil($bits/5);
$codechars_length = strlen($codechars)-1; $codechars_length = strlen($codechars)-1;
$code = ''; $code = '';
for($i = 0; $i < $chars; ++$i) { for ($i = 0; $i < $chars; ++$i) {
$random_char = $codechars[random_int(0, $codechars_length)]; $random_char = $codechars[random_int(0, $codechars_length)];
$code .= $random_char; $code .= $random_char;
} }
@ -2403,15 +2420,13 @@ function common_compatible_license($from, $to)
} }
/** /**
* returns a quoted table name, if required according to config * returns a quoted table name
*/ */
function common_database_tablename($tablename) function common_database_tablename($tablename)
{ {
if (common_config('db', 'quote_identifiers')) { $schema = Schema::get();
$tablename = '"'. $tablename .'"'; // table prefixes could be added here later
} return $schema->quoteIdentifier($tablename);
//table prefixes could be added here later
return $tablename;
} }
/** /**
@ -2692,10 +2707,13 @@ function _common_size_str_to_int($size): int
* *
* @return int * @return int
*/ */
function common_get_preferred_php_upload_limit(): int { function common_get_preferred_php_upload_limit(): int
return min(_common_size_str_to_int(ini_get('post_max_size')), {
return min(
_common_size_str_to_int(ini_get('post_max_size')),
_common_size_str_to_int(ini_get('upload_max_filesize')), _common_size_str_to_int(ini_get('upload_max_filesize')),
_common_size_str_to_int(ini_get('memory_limit'))); _common_size_str_to_int(ini_get('memory_limit'))
);
} }
function html_sprintf() function html_sprintf()

View File

@ -1,28 +1,28 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* GNU Social - a federating social network //
* Copyright (C) 2014, Free Software Foundation, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/** /**
* @package Activity * @package Favorite
* @maintainer Mikael Nordfeldth <mmn@hethane.se> * @author Mikael Nordfeldth <mmn@hethane.se>
* @copyright 2014 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
defined('GNUSOCIAL') || die();
class FavoriteModule extends ActivityVerbHandlerModule class FavoriteModule extends ActivityVerbHandlerModule
{ {
const PLUGIN_VERSION = '2.0.0'; const PLUGIN_VERSION = '2.0.0';
@ -93,15 +93,14 @@ class FavoriteModule extends ActivityVerbHandlerModule
while ($fave->fetch()) { while ($fave->fetch()) {
try { try {
$fave->decache(); $fave->decache();
$fave->query(sprintf('UPDATE fave '. $fave->query(sprintf(
'SET uri = "%s", '. "UPDATE fave SET uri = '%s', modified = TIMESTAMP '%s' " .
' modified = "%s" '. 'WHERE user_id = %d AND notice_id = %d',
'WHERE user_id = %d '.
'AND notice_id = %d',
Fave::newUri($fave->getActor(), $fave->getTarget(), $fave->modified), Fave::newUri($fave->getActor(), $fave->getTarget(), $fave->modified),
common_sql_date(strtotime($fave->modified)), common_sql_date(strtotime($fave->modified)),
$fave->user_id, $fave->user_id,
$fave->notice_id)); $fave->notice_id
));
} catch (Exception $e) { } catch (Exception $e) {
common_log(LOG_ERR, "Error updating fave URI: " . $e->getMessage()); common_log(LOG_ERR, "Error updating fave URI: " . $e->getMessage());
} }
@ -114,77 +113,129 @@ class FavoriteModule extends ActivityVerbHandlerModule
public function onRouterInitialized(URLMapper $m) public function onRouterInitialized(URLMapper $m)
{ {
// Web UI actions // Web UI actions
$m->connect('main/favor', $m->connect(
['action' => 'favor']); 'main/favor',
$m->connect('main/disfavor', ['action' => 'favor']
['action' => 'disfavor']); );
$m->connect(
'main/disfavor',
['action' => 'disfavor']
);
if (common_config('singleuser', 'enabled')) { if (common_config('singleuser', 'enabled')) {
$nickname = User::singleUserNickname(); $nickname = User::singleUserNickname();
$m->connect('favorites', $m->connect(
['action' => 'showfavorites', 'favorites',
'nickname' => $nickname]); [
$m->connect('favoritesrss', 'action' => 'showfavorites',
['action' => 'favoritesrss', 'nickname' => $nickname,
'nickname' => $nickname]); ]
);
$m->connect(
'favoritesrss',
[
'action' => 'favoritesrss',
'nickname' => $nickname,
]
);
} else { } else {
$m->connect('favoritedrss', $m->connect(
['action' => 'favoritedrss']); 'favoritedrss',
$m->connect('favorited/', ['action' => 'favoritedrss']
['action' => 'favorited']); );
$m->connect('favorited', $m->connect(
['action' => 'favorited']); 'favorited/',
['action' => 'favorited']
);
$m->connect(
'favorited',
['action' => 'favorited']
);
$m->connect(':nickname/favorites', $m->connect(
':nickname/favorites',
['action' => 'showfavorites'], ['action' => 'showfavorites'],
['nickname' => Nickname::DISPLAY_FMT]); ['nickname' => Nickname::DISPLAY_FMT]
$m->connect(':nickname/favorites/rss', );
$m->connect(
':nickname/favorites/rss',
['action' => 'favoritesrss'], ['action' => 'favoritesrss'],
['nickname' => Nickname::DISPLAY_FMT]); ['nickname' => Nickname::DISPLAY_FMT]
);
} }
// Favorites for API // Favorites for API
$m->connect('api/favorites/create.:format', $m->connect(
'api/favorites/create.:format',
['action' => 'ApiFavoriteCreate'], ['action' => 'ApiFavoriteCreate'],
['format' => '(xml|json)']); ['format' => '(xml|json)']
$m->connect('api/favorites/destroy.:format', );
$m->connect(
'api/favorites/destroy.:format',
['action' => 'ApiFavoriteDestroy'], ['action' => 'ApiFavoriteDestroy'],
['format' => '(xml|json)']); ['format' => '(xml|json)']
$m->connect('api/favorites/list.:format', );
$m->connect(
'api/favorites/list.:format',
['action' => 'ApiTimelineFavorites'], ['action' => 'ApiTimelineFavorites'],
['format' => '(xml|json|rss|atom|as)']); ['format' => '(xml|json|rss|atom|as)']
$m->connect('api/favorites/:id.:format', );
$m->connect(
'api/favorites/:id.:format',
['action' => 'ApiTimelineFavorites'], ['action' => 'ApiTimelineFavorites'],
['id' => Nickname::INPUT_FMT, [
'format' => '(xml|json|rss|atom|as)']); 'id' => Nickname::INPUT_FMT,
$m->connect('api/favorites.:format', 'format' => '(xml|json|rss|atom|as)',
]
);
$m->connect(
'api/favorites.:format',
['action' => 'ApiTimelineFavorites'], ['action' => 'ApiTimelineFavorites'],
['format' => '(xml|json|rss|atom|as)']); ['format' => '(xml|json|rss|atom|as)']
$m->connect('api/favorites/create/:id.:format', );
$m->connect(
'api/favorites/create/:id.:format',
['action' => 'ApiFavoriteCreate'], ['action' => 'ApiFavoriteCreate'],
['id' => '[0-9]+', [
'format' => '(xml|json)']); 'id' => '[0-9]+',
$m->connect('api/favorites/destroy/:id.:format', 'format' => '(xml|json)',
]
);
$m->connect(
'api/favorites/destroy/:id.:format',
['action' => 'ApiFavoriteDestroy'], ['action' => 'ApiFavoriteDestroy'],
['id' => '[0-9]+', [
'format' => '(xml|json)']); 'id' => '[0-9]+',
'format' => '(xml|json)',
]
);
// AtomPub API // AtomPub API
$m->connect('api/statusnet/app/favorites/:profile/:notice.atom', $m->connect(
'api/statusnet/app/favorites/:profile/:notice.atom',
['action' => 'AtomPubShowFavorite'], ['action' => 'AtomPubShowFavorite'],
['profile' => '[0-9]+', [
'notice' => '[0-9]+']); 'profile' => '[0-9]+',
'notice' => '[0-9]+',
]
);
$m->connect('api/statusnet/app/favorites/:profile.atom', $m->connect(
'api/statusnet/app/favorites/:profile.atom',
['action' => 'AtomPubFavoriteFeed'], ['action' => 'AtomPubFavoriteFeed'],
['profile' => '[0-9]+']); ['profile' => '[0-9]+']
);
// Required for qvitter API // Required for qvitter API
$m->connect('api/statuses/favs/:id.:format', $m->connect(
'api/statuses/favs/:id.:format',
['action' => 'ApiStatusesFavs'], ['action' => 'ApiStatusesFavs'],
['id' => '[0-9]+', [
'format' => '(xml|json)']); 'id' => '[0-9]+',
'format' => '(xml|json)',
]
);
} }
// FIXME: Set this to abstract public in lib/modules/ActivityHandlerPlugin.php when all plugins have migrated! // FIXME: Set this to abstract public in lib/modules/ActivityHandlerPlugin.php when all plugins have migrated!
@ -443,10 +494,12 @@ class FavoriteModule extends ActivityVerbHandlerModule
$emailfave = $scoped->getConfigPref('email', 'notify_fave') ? 1 : 0; $emailfave = $scoped->getConfigPref('email', 'notify_fave') ? 1 : 0;
$action->elementStart('li'); $action->elementStart('li');
$action->checkbox('email-notify_fave', $action->checkbox(
'email-notify_fave',
// TRANS: Checkbox label in e-mail preferences form. // TRANS: Checkbox label in e-mail preferences form.
_('Send me email when someone adds my notice as a favorite.'), _('Send me email when someone adds my notice as a favorite.'),
$emailfave); $emailfave
);
$action->elementEnd('li'); $action->elementEnd('li');
return true; return true;
@ -454,9 +507,9 @@ class FavoriteModule extends ActivityVerbHandlerModule
public function onStartEmailSaveForm(Action $action, Profile $scoped) public function onStartEmailSaveForm(Action $action, Profile $scoped)
{ {
$emailfave = $action->booleanintstring('email-notify_fave'); $emailfave = $action->boolean('email-notify_fave');
try { try {
if ($emailfave == $scoped->getPref('email', 'notify_fave')) { if ($emailfave == (bool) $scoped->getPref('email', 'notify_fave')) {
// No need to update setting // No need to update setting
return true; return true;
} }
@ -473,24 +526,31 @@ class FavoriteModule extends ActivityVerbHandlerModule
public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped=null) public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped=null)
{ {
$menu->out->menuItem(common_local_url('showfavorites', array('nickname' => $target->getNickname())), $menu->out->menuItem(
common_local_url('showfavorites', ['nickname' => $target->getNickname()]),
// TRANS: Menu item in personal group navigation menu. // TRANS: Menu item in personal group navigation menu.
_m('MENU','Favorites'), _m('MENU', 'Favorites'),
// @todo i18n FIXME: Need to make this two messages. // @todo i18n FIXME: Need to make this two messages.
// TRANS: Menu item title in personal group navigation menu. // TRANS: Menu item title in personal group navigation menu.
// TRANS: %s is a username. // TRANS: %s is a username.
sprintf(_('%s\'s favorite notices'), $target->getBestName()), sprintf(_('%s\'s favorite notices'), $target->getBestName()),
$scoped instanceof Profile && $target->id === $scoped->id && $menu->actionName =='showfavorites', ($scoped instanceof Profile && $target->id === $scoped->id && $menu->actionName === 'showfavorites'),
'nav_timeline_favorites'); 'nav_timeline_favorites'
);
} }
public function onEndPublicGroupNav(Menu $menu) public function onEndPublicGroupNav(Menu $menu)
{ {
if (!common_config('singleuser', 'enabled')) { if (!common_config('singleuser', 'enabled')) {
// TRANS: Menu item in search group navigation panel. // TRANS: Menu item in search group navigation panel.
$menu->out->menuItem(common_local_url('favorited'), _m('MENU','Popular'), $menu->out->menuItem(
common_local_url('favorited'),
_m('MENU', 'Popular'),
// TRANS: Menu item title in search group navigation panel. // TRANS: Menu item title in search group navigation panel.
_('Popular notices'), $menu->actionName == 'favorited', 'nav_timeline_favorited'); _('Popular notices'),
($menu->actionName === 'favorited'),
'nav_timeline_favorited'
);
} }
} }
@ -529,9 +589,13 @@ class FavoriteModule extends ActivityVerbHandlerModule
switch (true) { switch (true) {
case $exists && ActivityUtils::compareVerbs($verb, array(ActivityVerb::FAVORITE, ActivityVerb::LIKE)): case $exists && ActivityUtils::compareVerbs($verb, array(ActivityVerb::FAVORITE, ActivityVerb::LIKE)):
case !$exists && ActivityUtils::compareVerbs($verb, array(ActivityVerb::UNFAVORITE, ActivityVerb::UNLIKE)): case !$exists && ActivityUtils::compareVerbs($verb, array(ActivityVerb::UNFAVORITE, ActivityVerb::UNLIKE)):
common_redirect(common_local_url('activityverb', common_redirect(common_local_url(
array('id' => $target->getID(), 'activityverb',
'verb' => ActivityUtils::resolveUri($expected_verb, true)))); [
'id' => $target->getID(),
'verb' => ActivityUtils::resolveUri($expected_verb, true),
]
));
break; break;
default: default:
// No need to redirect as we are on the correct action already. // No need to redirect as we are on the correct action already.
@ -617,7 +681,8 @@ function mail_notify_fave(User $rcpt, Profile $sender, Notice $notice)
// TRANS: %3$s is a URL to the faved notice, %4$s is the faved notice text, // TRANS: %3$s is a URL to the faved notice, %4$s is the faved notice text,
// TRANS: %5$s is a URL to all faves of the adding user, %6$s is the StatusNet sitename, // TRANS: %5$s is a URL to all faves of the adding user, %6$s is the StatusNet sitename,
// TRANS: %7$s is the adding user's nickname. // TRANS: %7$s is the adding user's nickname.
$body = sprintf(_("%1\$s (@%7\$s) just added your notice from %2\$s". $body = sprintf(
_("%1\$s (@%7\$s) just added your notice from %2\$s".
" as one of their favorites.\n\n" . " as one of their favorites.\n\n" .
"The URL of your notice is:\n\n" . "The URL of your notice is:\n\n" .
"%3\$s\n\n" . "%3\$s\n\n" .
@ -627,13 +692,12 @@ function mail_notify_fave(User $rcpt, Profile $sender, Notice $notice)
"%5\$s"), "%5\$s"),
$bestname, $bestname,
common_exact_date($notice->created), common_exact_date($notice->created),
common_local_url('shownotice', common_local_url('shownotice', ['notice' => $notice->id]),
array('notice' => $notice->id)),
$notice->content, $notice->content,
common_local_url('showfavorites', common_local_url('showfavorites', ['nickname' => $sender->getNickname()]),
array('nickname' => $sender->getNickname())),
common_config('site', 'name'), common_config('site', 'name'),
$sender->getNickname()) . $sender->getNickname()
) .
mail_footer_block(); mail_footer_block();
$headers = _mail_prepare_headers('fave', $rcpt->getNickname(), $sender->getNickname()); $headers = _mail_prepare_headers('fave', $rcpt->getNickname(), $sender->getNickname());

View File

@ -1,48 +1,43 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Notice stream for favorites * 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 * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { exit(1); } defined('GNUSOCIAL') || die();
/** /**
* Notice stream for favorites * Notice stream for favorites
* *
* @category Stream * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class FaveNoticeStream extends ScopingNoticeStream class FaveNoticeStream extends ScopingNoticeStream
{ {
function __construct(Profile $target, Profile $scoped=null) public function __construct(Profile $target, Profile $scoped = null)
{ {
$stream = new RawFaveNoticeStream($target, $scoped); $stream = new RawFaveNoticeStream($target, $scoped);
if ($target->sameAs($scoped)) { if ($target->sameAs($scoped)) {
@ -58,11 +53,10 @@ class FaveNoticeStream extends ScopingNoticeStream
* Raw notice stream for favorites * Raw notice stream for favorites
* *
* @category Stream * @category Stream
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class RawFaveNoticeStream extends NoticeStream class RawFaveNoticeStream extends NoticeStream
{ {
@ -71,7 +65,7 @@ class RawFaveNoticeStream extends NoticeStream
protected $selectVerbs = array(); protected $selectVerbs = array();
function __construct(Profile $target, Profile $scoped=null) public function __construct(Profile $target, Profile $scoped = null)
{ {
parent::__construct(); parent::__construct();
@ -92,7 +86,7 @@ class RawFaveNoticeStream extends NoticeStream
* @param <type> $max_id * @param <type> $max_id
* @return <type> * @return <type>
*/ */
function getNoticeIds($offset, $limit, $since_id, $max_id) public function getNoticeIds($offset, $limit, $since_id, $max_id)
{ {
$fav = new Fave(); $fav = new Fave();
$qry = null; $qry = null;
@ -104,7 +98,7 @@ class RawFaveNoticeStream extends NoticeStream
$qry = 'SELECT fave.* FROM fave '; $qry = 'SELECT fave.* FROM fave ';
$qry .= 'INNER JOIN notice ON fave.notice_id = notice.id '; $qry .= 'INNER JOIN notice ON fave.notice_id = notice.id ';
$qry .= 'WHERE fave.user_id = ' . $this->user_id . ' '; $qry .= 'WHERE fave.user_id = ' . $this->user_id . ' ';
$qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' '; $qry .= 'AND notice.is_local <> ' . Notice::GATEWAY . ' ';
} }
if ($since_id != 0) { if ($since_id != 0) {
@ -137,4 +131,3 @@ class RawFaveNoticeStream extends NoticeStream
return $ids; return $ids;
} }
} }

View File

@ -51,8 +51,8 @@ class Activitypub_pending_follow_requests extends Managed_DataObject
{ {
return [ return [
'fields' => [ 'fields' => [
'local_profile_id' => ['type' => 'integer', 'not null' => true], 'local_profile_id' => ['type' => 'int', 'not null' => true],
'remote_profile_id' => ['type' => 'integer', 'not null' => true], 'remote_profile_id' => ['type' => 'int', 'not null' => true],
'relation_id' => ['type' => 'serial', 'not null' => true], 'relation_id' => ['type' => 'serial', 'not null' => true],
], ],
'primary key' => ['relation_id'], 'primary key' => ['relation_id'],

View File

@ -61,7 +61,7 @@ class Activitypub_profile extends Managed_DataObject
return [ return [
'fields' => [ 'fields' => [
'uri' => ['type' => 'text', 'not null' => true], 'uri' => ['type' => 'text', 'not null' => true],
'profile_id' => ['type' => 'integer'], 'profile_id' => ['type' => 'int', 'not null' => true],
'inboxuri' => ['type' => 'text', 'not null' => true], 'inboxuri' => ['type' => 'text', 'not null' => true],
'sharedInboxuri' => ['type' => 'text'], 'sharedInboxuri' => ['type' => 'text'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],

View File

@ -53,7 +53,7 @@ class Activitypub_rsa extends Managed_DataObject
{ {
return [ return [
'fields' => [ 'fields' => [
'profile_id' => ['type' => 'integer'], 'profile_id' => ['type' => 'int', 'not null' => true],
'private_key' => ['type' => 'text'], 'private_key' => ['type' => 'text'],
'public_key' => ['type' => 'text', 'not null' => true], 'public_key' => ['type' => 'text', 'not null' => true],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],

View File

@ -1,45 +1,36 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Score of a notice by activity spam service * Score of a notice by activity spam service
* *
* 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 Spam * @category Spam
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Score of a notice per the activity spam service * Score of a notice per the activity spam service
* *
* @category Spam * @copyright 2011 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -54,7 +45,6 @@ class Spam_score extends Managed_DataObject
public static function save($notice, $result) public static function save($notice, $result)
{ {
$orig = null; $orig = null;
$score = Spam_score::getKV('notice_id', $notice->id); $score = Spam_score::getKV('notice_id', $notice->id);
@ -93,12 +83,13 @@ class Spam_score extends Managed_DataObject
'notice_id' => array('type' => 'int', 'notice_id' => array('type' => 'int',
'not null' => true, 'not null' => true,
'description' => 'notice getting scored'), 'description' => 'notice getting scored'),
'score' => array('type' => 'double', 'score' => array('type' => 'float',
'size' => 'big',
'not null' => true, 'not null' => true,
'description' => 'score for the notice (0.0, 1.0)'), 'description' => 'score for the notice (0.0, 1.0)'),
'scaled' => array('type' => 'int', 'scaled' => array('type' => 'int',
'description' => 'scaled score for the notice (0, 10000)'), 'description' => 'scaled score for the notice (0, 10000)'),
'is_spam' => array('type' => 'tinyint', 'is_spam' => array('type' => 'bool',
'description' => 'flag for spamosity'), 'description' => 'flag for spamosity'),
'created' => array('type' => 'datetime', 'created' => array('type' => 'datetime',
'not null' => true, 'not null' => true,
@ -146,7 +137,7 @@ class Spam_score extends Managed_DataObject
if ($score->find()) { if ($score->find()) {
while ($score->fetch()) { while ($score->fetch()) {
$orig = clone($score); $orig = clone($score);
$score->is_spam = ($score->score >= 0.90) ? 1 : 0; $score->is_spam = ($score->score >= 0.90) ? true : false;
$score->update($orig); $score->update($orig);
} }
} }
@ -169,9 +160,8 @@ class Spam_score extends Managed_DataObject
} }
} }
function saveNew($notice, $result) public function saveNew($notice, $result)
{ {
$score = new Spam_score(); $score = new Spam_score();
$score->notice_id = $notice->id; $score->notice_id = $notice->id;

View File

@ -1,52 +1,45 @@
<?php <?php
/** // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2012, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* Spam notice stream // the Free Software Foundation, either version 3 of the License, or
* // (at your option) any later version.
* PHP version 5 //
* // GNU social is distributed in the hope that it will be useful,
* This program is free software: you can redistribute it and/or modify // but WITHOUT ANY WARRANTY; without even the implied warranty of
* it under the terms of the GNU Affero General Public License as published by // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* the Free Software Foundation, either version 3 of the License, or // GNU Affero General Public License for more details.
* (at your option) any later version. //
* // You should have received a copy of the GNU Affero General Public License
* This program is distributed in the hope that it will be useful, // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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 Spam
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2012 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/** /**
* Spam notice stream * Spam notice stream
* *
* @category Spam * @category Spam
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2012 StatusNet, Inc. * @copyright 2012 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
defined('GNUSOCIAL') || die();
/**
* Spam notice stream
*
* @copyright 2012 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
*/
class SpamNoticeStream extends ScopingNoticeStream class SpamNoticeStream extends ScopingNoticeStream
{ {
function __construct(Profile $scoped=null) public function __construct(Profile $scoped = null)
{ {
parent::__construct(new CachingNoticeStream(new RawSpamNoticeStream(), 'spam_score:notice_ids'), parent::__construct(
$scoped); new CachingNoticeStream(new RawSpamNoticeStream(), 'spam_score:notice_ids'),
$scoped
);
} }
} }
@ -54,20 +47,16 @@ class SpamNoticeStream extends ScopingNoticeStream
* Raw stream of spammy notices * Raw stream of spammy notices
* *
* @category Stream * @category Stream
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/ */
class RawSpamNoticeStream extends NoticeStream class RawSpamNoticeStream extends NoticeStream
{ {
function getNoticeIds($offset, $limit, $since_id, $max_id) public function getNoticeIds($offset, $limit, $since_id, $max_id)
{ {
$ss = new Spam_score(); $ss = new Spam_score();
$ss->is_spam = 1; $ss->is_spam = true;
$ss->selectAdd(); $ss->selectAdd();
$ss->selectAdd('notice_id'); $ss->selectAdd('notice_id');

View File

@ -1,20 +1,22 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2013 StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>. /**
* @copyright 2013 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..')); define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
@ -33,13 +35,13 @@ END_OF_SILENCESPAMMER_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc'; require_once INSTALLDIR.'/scripts/commandline.inc';
function testAllUsers($filter, $minimum, $percent) { function testAllUsers($filter, $minimum, $percent)
{
$found = false; $found = false;
$offset = 0; $offset = 0;
$limit = 1000; $limit = 1000;
do { do {
$user = new User(); $user = new User();
$user->orderBy('created'); $user->orderBy('created');
$user->limit($offset, $limit); $user->limit($offset, $limit);
@ -56,12 +58,11 @@ function testAllUsers($filter, $minimum, $percent) {
} }
$offset += $found; $offset += $found;
} }
} while ($found > 0); } while ($found > 0);
} }
function silencespammer($filter, $user, $minimum, $percent) { function silencespammer($filter, $user, $minimum, $percent)
{
printfnq("Testing user %s\n", $user->nickname); printfnq("Testing user %s\n", $user->nickname);
$profile = Profile::getKV('id', $user->id); $profile = Profile::getKV('id', $user->id);
@ -82,7 +83,7 @@ function silencespammer($filter, $user, $minimum, $percent) {
$ss->query(sprintf("SELECT count(*) as spam_count ". $ss->query(sprintf("SELECT count(*) as spam_count ".
"FROM notice join spam_score on notice.id = spam_score.notice_id ". "FROM notice join spam_score on notice.id = spam_score.notice_id ".
"WHERE notice.profile_id = %d AND spam_score.is_spam = 1", $profile->id)); 'WHERE notice.profile_id = %d AND spam_score.is_spam = TRUE', $profile->id));
while ($ss->fetch()) { while ($ss->fetch()) {
$spam_count = $ss->spam_count; $spam_count = $ss->spam_count;
@ -94,7 +95,7 @@ function silencespammer($filter, $user, $minimum, $percent) {
printfnq("Silencing user %s (%d/%d = %0.2f%% spam)\n", $user->nickname, $spam_count, $cnt, $spam_percent); printfnq("Silencing user %s (%d/%d = %0.2f%% spam)\n", $user->nickname, $spam_count, $cnt, $spam_percent);
try { try {
$profile->silence(); $profile->silence();
} catch(Exception $e) { } catch (Exception $e) {
printfnq("Error: %s", $e->getMessage()); printfnq("Error: %s", $e->getMessage());
} }
} }

View File

@ -1,33 +1,32 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Simple-minded queue manager for storing items in the database * Simple-minded queue manager for storing items in the database
* *
* 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 QueueManager * @category QueueManager
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @author Brion Vibber <brion@status.net> * @author Brion Vibber <brion@status.net>
* @copyright 2009-2010 StatusNet, Inc. * @copyright 2009-2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
defined('GNUSOCIAL') || die();
class DBQueueManager extends QueueManager class DBQueueManager extends QueueManager
{ {
/** /**
@ -39,7 +38,7 @@ class DBQueueManager extends QueueManager
{ {
$qi = new Queue_item(); $qi = new Queue_item();
$qi->frame = $this->encode($object); $qi->frame = DB_DataObject_Cast::blob($this->encode($object));
$qi->transport = $queue; $qi->transport = $queue;
$qi->created = common_sql_now(); $qi->created = common_sql_now();
$result = $qi->insert(); $result = $qi->insert();
@ -121,7 +120,8 @@ class DBQueueManager extends QueueManager
// What to do if no handler was found. For example, the OpportunisticQM // What to do if no handler was found. For example, the OpportunisticQM
// should avoid deleting items just because it can't reach XMPP queues etc. // should avoid deleting items just because it can't reach XMPP queues etc.
protected function noHandlerFound(Queue_item $qi, $rep=null) { protected function noHandlerFound(Queue_item $qi, $rep = null)
{
$this->_log(LOG_INFO, "[{$qi->transport}:{$rep}] No handler for queue {$qi->transport}; discarding."); $this->_log(LOG_INFO, "[{$qi->transport}:{$rep}] No handler for queue {$qi->transport}; discarding.");
$this->_done($qi); $this->_done($qi);
} }

View File

@ -1,31 +1,31 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Data class for email reminders * Data class for email reminders
* *
* 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 Data * @category Data
* @package EmailReminder * @package EmailReminder
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
defined('GNUSOCIAL') || die();
class Email_reminder extends Managed_DataObject class Email_reminder extends Managed_DataObject
{ {
public $__table = 'email_reminder'; public $__table = 'email_reminder';
@ -46,8 +46,8 @@ class Email_reminder extends Managed_DataObject
* @param int $days Number of days after the code was created * @param int $days Number of days after the code was created
* @return boolean true if any Email_reminder records were found * @return boolean true if any Email_reminder records were found
*/ */
static function needsReminder($type, $object, $days = null) { public static function needsReminder($type, $object, $days = null)
{
$reminder = new Email_reminder(); $reminder = new Email_reminder();
$reminder->type = $type; $reminder->type = $type;
$reminder->code = $object->code; $reminder->code = $object->code;
@ -72,8 +72,8 @@ class Email_reminder extends Managed_DataObject
* @param int $days Number of days after the code was created * @param int $days Number of days after the code was created
* @return int $result row ID of the new reminder record * @return int $result row ID of the new reminder record
*/ */
static function recordReminder($type, $object, $days) { public static function recordReminder($type, $object, $days)
{
$reminder = new Email_reminder(); $reminder = new Email_reminder();
$reminder->type = $type; $reminder->type = $type;
$reminder->code = $object->code; $reminder->code = $object->code;
@ -108,13 +108,13 @@ class Email_reminder extends Managed_DataObject
), ),
'code' => array( 'code' => array(
'type' => 'varchar', 'type' => 'varchar',
'not null' => 'true', 'not null' => true,
'length' => 191, 'length' => 191,
'description' => 'confirmation code' 'description' => 'confirmation code'
), ),
'days' => array( 'days' => array(
'type' => 'int', 'type' => 'int',
'not null' => 'true', 'not null' => true,
'description' => 'number of days since code creation' 'description' => 'number of days since code creation'
), ),
'sent' => array( 'sent' => array(

View File

@ -1,45 +1,38 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/* /*
* StatusNet - the distributed open-source microblogging tool
*
* Handler for reminder queue items which send reminder emails to all users * Handler for reminder queue items which send reminder emails to all users
* we would like to complete a given process (e.g.: registration). * we would like to complete a given process (e.g.: registration).
* *
* 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 Email * @category Email
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Handler for reminder queue items which send reminder emails to all users * Handler for reminder queue items which send reminder emails to all users
* we would like to complete a given process (e.g.: registration) * we would like to complete a given process (e.g.: registration)
* *
* @category Email
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class SiteConfirmReminderHandler extends QueueHandler class SiteConfirmReminderHandler extends QueueHandler
{ {
@ -52,7 +45,7 @@ class SiteConfirmReminderHandler extends QueueHandler
* *
* @return string * @return string
*/ */
function transport() public function transport()
{ {
return 'siterem'; return 'siterem';
} }
@ -63,14 +56,14 @@ class SiteConfirmReminderHandler extends QueueHandler
* @param array $remitem type of reminder to send and any special options * @param array $remitem type of reminder to send and any special options
* @return boolean true on success, false on failure * @return boolean true on success, false on failure
*/ */
function handle($remitem) : bool public function handle($remitem): bool
{ {
list($type, $opts) = $remitem; list($type, $opts) = $remitem;
$qm = QueueManager::get(); $qm = QueueManager::get();
try { try {
switch($type) { switch ($type) {
case UserConfirmRegReminderHandler::REGISTER_REMINDER: case UserConfirmRegReminderHandler::REGISTER_REMINDER:
$confirm = new Confirm_address(); $confirm = new Confirm_address();
$confirm->address_type = $type; $confirm->address_type = $type;
@ -87,7 +80,11 @@ class SiteConfirmReminderHandler extends QueueHandler
case UserInviteReminderHandler::INVITE_REMINDER: case UserInviteReminderHandler::INVITE_REMINDER:
$invitation = new Invitation(); $invitation = new Invitation();
// Only send one reminder (the latest one), regardless of how many invitations a user has // Only send one reminder (the latest one), regardless of how many invitations a user has
$sql = 'SELECT * FROM (SELECT * FROM invitation WHERE registered_user_id IS NULL ORDER BY created DESC) invitees GROUP BY invitees.address'; $sql = 'SELECT * FROM invitation ' .
'WHERE (address, created) IN ' .
'(SELECT address, MAX(created) FROM invitation GROUP BY address) AND ' .
'registered_user_id IS NULL ' .
'ORDER BY created DESC';
$invitation->query($sql); $invitation->query($sql);
while ($invitation->fetch()) { while ($invitation->fetch()) {
try { try {

View File

@ -1,35 +1,30 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* Data class for email summary status * Data class for email summary status
* *
* PHP version 5
*
* @category Data * @category Data
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2010, StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
@ -39,10 +34,8 @@ require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
* Email summary information for users * Email summary information for users
* *
* @category Action * @category Action
* @package StatusNet * @copyright 2010, StatusNet, Inc.
* @author Evan Prodromou <evan@status.net> * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -50,7 +43,7 @@ class Email_summary_status extends Managed_DataObject
{ {
public $__table = 'email_summary_status'; // table name public $__table = 'email_summary_status'; // table name
public $user_id; // int(4) primary_key not_null public $user_id; // int(4) primary_key not_null
public $send_summary; // tinyint not_null public $send_summary; // bool not_null default_true
public $last_summary_id; // int(4) null public $last_summary_id; // int(4) null
public $created; // datetime not_null public $created; // datetime not_null
public $modified; // datetime not_null public $modified; // datetime not_null
@ -60,7 +53,7 @@ class Email_summary_status extends Managed_DataObject
return array( return array(
'fields' => array( 'fields' => array(
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'), 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
'send_summary' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'not null' => true, 'description' => 'whether to send a summary or not'), 'send_summary' => array('type' => 'bool', 'default' => true, 'not null' => true, 'description' => 'whether to send a summary or not'),
'last_summary_id' => array('type' => 'int', 'description' => 'last summary id'), 'last_summary_id' => array('type' => 'int', 'description' => 'last summary id'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
@ -79,7 +72,7 @@ class Email_summary_status extends Managed_DataObject
* *
* @return int flag for whether to send this user a summary email * @return int flag for whether to send this user a summary email
*/ */
static function getSendSummary($user_id) public static function getSendSummary($user_id)
{ {
$ess = Email_summary_status::getKV('user_id', $user_id); $ess = Email_summary_status::getKV('user_id', $user_id);
@ -97,7 +90,7 @@ class Email_summary_status extends Managed_DataObject
* *
* @return Email_summary_status instance for this user, with count already incremented. * @return Email_summary_status instance for this user, with count already incremented.
*/ */
static function getLastSummaryID($user_id) public static function getLastSummaryID($user_id)
{ {
$ess = Email_summary_status::getKV('user_id', $user_id); $ess = Email_summary_status::getKV('user_id', $user_id);

View File

@ -94,8 +94,10 @@ class Happening extends Managed_DataObject
'unique keys' => array( 'unique keys' => array(
'happening_uri_key' => array('uri'), 'happening_uri_key' => array('uri'),
), ),
'foreign keys' => array('happening_profile_id__key' => array('profile', array('profile_id' => 'id')), 'foreign keys' => array(
'happening_uri__key' => array('notice', array('uri' => 'uri'))), 'happening_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
'happening_uri_fkey' => array('notice', array('uri' => 'uri'))
),
'indexes' => array('happening_created_idx' => array('created'), 'indexes' => array('happening_created_idx' => array('created'),
'happening_start_end_idx' => array('start_time', 'end_time')), 'happening_start_end_idx' => array('start_time', 'end_time')),
); );

View File

@ -85,8 +85,10 @@ class RSVP extends Managed_DataObject
'rsvp_uri_key' => array('uri'), 'rsvp_uri_key' => array('uri'),
'rsvp_profile_event_key' => array('profile_id', 'event_uri'), 'rsvp_profile_event_key' => array('profile_id', 'event_uri'),
), ),
'foreign keys' => array('rsvp_event_uri_key' => array('happening', array('event_uri' => 'uri')), 'foreign keys' => array(
'rsvp_profile_id__key' => array('profile', array('profile_id' => 'id'))), 'rsvp_event_uri_fkey' => array('happening', array('event_uri' => 'uri')),
'rsvp_profile_id_fkey' => array('profile', array('profile_id' => 'id'))
),
'indexes' => array('rsvp_created_idx' => array('created')), 'indexes' => array('rsvp_created_idx' => array('created')),
); );
} }

View File

@ -1,36 +1,30 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Action for showing Twitter-like JSON search results * Action for showing Twitter-like JSON search results
* *
* 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 Search * @category Search
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
class UserautocompleteAction extends Action class UserautocompleteAction extends Action
{ {
@ -44,7 +38,7 @@ class UserautocompleteAction extends Action
* @return boolean true if nothing goes wrong * @return boolean true if nothing goes wrong
* @throws ClientException * @throws ClientException
*/ */
public function prepare(array $args = array()) public function prepare(array $args = [])
{ {
parent::prepare($args); parent::prepare($args);
$this->query = $this->trimmed('term'); $this->query = $this->trimmed('term');
@ -87,7 +81,7 @@ class UserautocompleteAction extends Action
. ' AND LEFT(LOWER(profile.nickname), ' . ' AND LEFT(LOWER(profile.nickname), '
. strlen($this->query) . strlen($this->query)
. ') = \'%s\' ' . ') = \'%s\' '
. ' LIMIT 0, 10'; . ' LIMIT 10';
$profile->query(sprintf($sql, $this->query)); $profile->query(sprintf($sql, $this->query));
} }

View File

@ -1,35 +1,30 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* Data class for counting greetings * Data class for counting greetings
* *
* PHP version 5
*
* @category Data * @category Data
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2009, StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
@ -45,10 +40,8 @@ require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
* and other bits of good functionality to StatusNet-specific data classes. * and other bits of good functionality to StatusNet-specific data classes.
* *
* @category Action * @category Action
* @package StatusNet * @copyright 2009, StatusNet, Inc.
* @author Evan Prodromou <evan@status.net> * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -56,7 +49,7 @@ class User_followeveryone_prefs extends Managed_DataObject
{ {
public $__table = 'user_followeveryone_prefs'; // table name public $__table = 'user_followeveryone_prefs'; // table name
public $user_id; // int(4) primary_key not_null public $user_id; // int(4) primary_key not_null
public $followeveryone; // tinyint(1) public $followeveryone; // bool default_true
public $created; // datetime() not_null public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
@ -65,7 +58,7 @@ class User_followeveryone_prefs extends Managed_DataObject
return array( return array(
'fields' => array( 'fields' => array(
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'), 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
'followeveryone' => array('type' => 'int', 'default' => 1, 'size' => 'tiny', 'description' => 'whether to follow everyone'), 'followeveryone' => array('type' => 'bool', 'default' => true, 'description' => 'whether to follow everyone'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
), ),
@ -76,7 +69,7 @@ class User_followeveryone_prefs extends Managed_DataObject
); );
} }
static function followEveryone($user_id) public static function followEveryone($user_id)
{ {
$ufep = self::getKV('user_id', $user_id); $ufep = self::getKV('user_id', $user_id);
@ -87,7 +80,7 @@ class User_followeveryone_prefs extends Managed_DataObject
} }
} }
static function savePref($user_id, $followEveryone) public static function savePref($user_id, $followEveryone)
{ {
$ufep = self::getKV('user_id', $user_id); $ufep = self::getKV('user_id', $user_id);

View File

@ -62,33 +62,22 @@ class GroupFavoritedAction extends ShowgroupAction
$groupId = (int)$this->group->id; $groupId = (int)$this->group->id;
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff')); $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
$cutoff = sprintf( $cutoff = sprintf(
"fave.modified > '%s'", "fave.modified > TIMESTAMP '%s'",
common_sql_date(time() - common_config('popular', 'cutoff')) common_sql_date(time() - common_config('popular', 'cutoff'))
); );
$qry = 'SELECT notice.*, ' .
$weightexpr . ' as weight ' .
'FROM notice ' .
"JOIN group_inbox ON notice.id = group_inbox.notice_id " .
'JOIN fave ON notice.id = fave.notice_id ' .
"WHERE $cutoff AND group_id = $groupId " .
'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
'ORDER BY weight DESC';
$offset = ($this->page - 1) * NOTICES_PER_PAGE; $offset = ($this->page - 1) * NOTICES_PER_PAGE;
$limit = NOTICES_PER_PAGE + 1; $limit = NOTICES_PER_PAGE + 1;
if (common_config('db', 'type') == 'pgsql') { $qry = 'SELECT notice.*, ' . $weightexpr . ' AS weight ' .
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; 'FROM notice ' .
} else { 'INNER JOIN group_inbox ON notice.id = group_inbox.notice_id ' .
$qry .= ' LIMIT ' . $offset . ', ' . $limit; 'INNER JOIN fave ON notice.id = fave.notice_id ' .
} 'WHERE ' . $cutoff . ' AND group_id = ' . $groupId . ' ' .
'GROUP BY id, profile_id, uri, content, rendered, url, created, notice.modified, reply_to, is_local, source, notice.conversation ' .
'ORDER BY weight DESC LIMIT ' . $limit . ' OFFSET ' . $offset;
$notice = Memcached_DataObject::cachedQuery( $notice = Memcached_DataObject::cachedQuery('Notice', $qry, 600);
'Notice',
$qry,
600
);
$nl = new NoticeList($notice, $this); $nl = new NoticeList($notice, $this);

View File

@ -1,52 +1,37 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2012, StatusNet, Inc.
*
* ModLogPlugin.php
*
* 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 Moderation * @category Moderation
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2012 StatusNet, Inc. * @copyright 2012 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
// This check helps protect against security problems;
// your code file can't be executed directly from the web.
exit(1);
}
/** /**
* Moderation logging * Moderation logging
* *
* Shows a history of moderation for this user in the sidebar * Shows a history of moderation for this user in the sidebar
* *
* @category Moderation
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2012 StatusNet, Inc. * @copyright 2012 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class ModLogPlugin extends Plugin class ModLogPlugin extends Plugin
{ {
const PLUGIN_VERSION = '2.0.0'; const PLUGIN_VERSION = '2.0.0';
@ -63,7 +48,7 @@ class ModLogPlugin extends Plugin
* @return boolean hook value; true means continue processing, false means stop. * @return boolean hook value; true means continue processing, false means stop.
*/ */
function onCheckSchema() public function onCheckSchema()
{ {
$schema = Schema::get(); $schema = Schema::get();
@ -72,7 +57,7 @@ class ModLogPlugin extends Plugin
return true; return true;
} }
function onEndGrantRole($profile, $role) public function onEndGrantRole($profile, $role)
{ {
$modlog = new ModLog(); $modlog = new ModLog();
@ -86,7 +71,7 @@ class ModLogPlugin extends Plugin
} }
$modlog->role = $role; $modlog->role = $role;
$modlog->is_grant = 1; $modlog->is_grant = true;
$modlog->created = common_sql_now(); $modlog->created = common_sql_now();
$modlog->insert(); $modlog->insert();
@ -94,7 +79,7 @@ class ModLogPlugin extends Plugin
return true; return true;
} }
function onEndRevokeRole($profile, $role) public function onEndRevokeRole($profile, $role)
{ {
$modlog = new ModLog(); $modlog = new ModLog();
@ -109,7 +94,7 @@ class ModLogPlugin extends Plugin
} }
$modlog->role = $role; $modlog->role = $role;
$modlog->is_grant = 0; $modlog->is_grant = false;
$modlog->created = common_sql_now(); $modlog->created = common_sql_now();
$modlog->insert(); $modlog->insert();
@ -117,7 +102,7 @@ class ModLogPlugin extends Plugin
return true; return true;
} }
function onEndShowSections(Action $action) public function onEndShowSections(Action $action)
{ {
if (!$action instanceof ShowstreamAction) { if (!$action instanceof ShowstreamAction) {
// early return for actions we're not interested in // early return for actions we're not interested in
@ -140,7 +125,6 @@ class ModLogPlugin extends Plugin
$cnt = $ml->find(); $cnt = $ml->find();
if ($cnt > 0) { if ($cnt > 0) {
$action->elementStart('div', array('id' => 'entity_mod_log', $action->elementStart('div', array('id' => 'entity_mod_log',
'class' => 'section')); 'class' => 'section'));
@ -158,9 +142,14 @@ class ModLogPlugin extends Plugin
if (empty($mod)) { if (empty($mod)) {
$action->text(_('[unknown]')); $action->text(_('[unknown]'));
} else { } else {
$action->element('a', array('href' => $mod->getUrl(), $action->element(
'title' => $mod->getFullname()), 'a',
$mod->getNickname()); [
'href' => $mod->getUrl(),
'title' => $mod->getFullname(),
],
$mod->getNickname()
);
} }
} else { } else {
$action->text(_('[unknown]')); $action->text(_('[unknown]'));
@ -175,7 +164,8 @@ class ModLogPlugin extends Plugin
} }
} }
function onUserRightsCheck($profile, $right, &$result) { public function onUserRightsCheck($profile, $right, &$result)
{
switch ($right) { switch ($right) {
case self::VIEWMODLOG: case self::VIEWMODLOG:
$result = ($profile->hasRole(Profile_role::MODERATOR) || $profile->hasRole('modhelper')); $result = ($profile->hasRole(Profile_role::MODERATOR) || $profile->hasRole('modhelper'));

View File

@ -1,49 +1,37 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool * Data object to store moderation logs
* Copyright (C) 2012, StatusNet, Inc.
*
* ModLog.php -- data object to store moderation logs
*
* 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 Moderation * @category Moderation
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2012 StatusNet, Inc. * @copyright 2012 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* Class comment here * @copyright 2012 StatusNet, Inc.
* * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @category Category here
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
class ModLog extends Managed_DataObject class ModLog extends Managed_DataObject
{ {
public $__table = 'mod_log'; // table name public $__table = 'mod_log'; // table name
@ -52,7 +40,7 @@ class ModLog extends Managed_DataObject
public $profile_id; // profile id public $profile_id; // profile id
public $moderator_id; // profile id public $moderator_id; // profile id
public $role; // the role public $role; // the role
public $grant; // 1 = grant, 0 = revoke public $is_grant; // true = grant, false = revoke
public $created; // datetime public $created; // datetime
/** /**
@ -75,9 +63,8 @@ class ModLog extends Managed_DataObject
'length' => 32, 'length' => 32,
'not null' => true, 'not null' => true,
'description' => 'role granted or revoked'), 'description' => 'role granted or revoked'),
'is_grant' => array('type' => 'int', 'is_grant' => array('type' => 'bool',
'size' => 'tiny', 'default' => true,
'default' => 1,
'description' => 'Was this a grant or revocation of a role'), 'description' => 'Was this a grant or revocation of a role'),
'created' => array('type' => 'datetime', 'created' => array('type' => 'datetime',
'not null' => true, 'not null' => true,
@ -86,7 +73,7 @@ class ModLog extends Managed_DataObject
'primary key' => array('id'), 'primary key' => array('id'),
'foreign keys' => array( 'foreign keys' => array(
'mod_log_profile_id_fkey' => array('profile', array('profile_id' => 'id')), 'mod_log_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
'mod_log_moderator_id_fkey' => array('user', array('user_id' => 'id')) 'mod_log_moderator_id_fkey' => array('user', array('moderator_id' => 'id'))
), ),
'indexes' => array( 'indexes' => array(
'mod_log_profile_id_created_idx' => array('profile_id', 'created'), 'mod_log_profile_id_created_idx' => array('profile_id', 'created'),

View File

@ -326,15 +326,18 @@ class Nodeinfo_2_0Action extends Action
*/ */
public function getActiveUsers(int $days): int public function getActiveUsers(int $days): int
{ {
$userTable = common_database_tablename('user');
$query = " $query = "
SELECT COUNT(DISTINCT profile_id) as active_users_count SELECT COUNT(DISTINCT profile_id) AS active_users_count
FROM ( FROM (
SELECT profile_id FROM notice WHERE notice.created >= NOW() - INTERVAL {$days} DAY AND notice.is_local = 1 SELECT profile_id FROM notice
WHERE notice.created >= (CURRENT_TIMESTAMP - INTERVAL '{$days}' DAY) AND notice.is_local = 1
UNION ALL UNION ALL
SELECT user_id FROM fave INNER JOIN user ON fave.user_id = user.id WHERE fave.created >= NOW() - INTERVAL {$days} DAY SELECT user_id FROM fave INNER JOIN {$userTable} ON fave.user_id = {$userTable}.id
WHERE fave.created >= (CURRENT_TIMESTAMP - INTERVAL '{$days}' DAY)
UNION ALL UNION ALL
SELECT id FROM user WHERE user.created >= NOW() - INTERVAL {$days} DAY SELECT id FROM {$userTable} WHERE {$userTable}.created >= (CURRENT_TIMESTAMP - INTERVAL '{$days}' DAY)
) as source"; ) AS source";
$activeUsersCount = new DB_DataObject(); $activeUsersCount = new DB_DataObject();
$activeUsersCount->query($query); $activeUsersCount->query($query);

View File

@ -1,32 +1,31 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2009-2010, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>.
*/
/** /**
* OStatusPlugin implementation for GNU Social * OStatusPlugin implementation for GNU Social
*
* Depends on: WebFinger plugin * Depends on: WebFinger plugin
* *
* @package OStatusPlugin * @package OStatusPlugin
* @maintainer Brion Vibber <brion@status.net> * @author Brion Vibber <brion@status.net>
* @copyright 2009-2010 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
if (!defined('GNUSOCIAL')) { exit(1); }
defined('GNUSOCIAL') || die();
require_once __DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'util.php'; require_once __DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'util.php';
@ -43,44 +42,68 @@ class OStatusPlugin extends Plugin
public function onRouterInitialized(URLMapper $m) public function onRouterInitialized(URLMapper $m)
{ {
// Discovery actions // Discovery actions
$m->connect('main/ostatustag', $m->connect(
['action' => 'ostatustag']); 'main/ostatustag',
$m->connect('main/ostatustag?nickname=:nickname', ['action' => 'ostatustag']
);
$m->connect(
'main/ostatustag?nickname=:nickname',
['action' => 'ostatustag'], ['action' => 'ostatustag'],
['nickname' => '[A-Za-z0-9_-]+']); ['nickname' => '[A-Za-z0-9_-]+']
$m->connect('main/ostatus/group/:group', );
$m->connect(
'main/ostatus/group/:group',
['action' => 'ostatusinit'], ['action' => 'ostatusinit'],
['group' => '[A-Za-z0-9_-]+']); ['group' => '[A-Za-z0-9_-]+']
$m->connect('main/ostatus/peopletag/:peopletag/tagger/:tagger', );
$m->connect(
'main/ostatus/peopletag/:peopletag/tagger/:tagger',
['action' => 'ostatusinit'], ['action' => 'ostatusinit'],
['tagger' => '[A-Za-z0-9_-]+', [
'peopletag' => '[A-Za-z0-9_-]+']); 'tagger' => '[A-Za-z0-9_-]+',
$m->connect('main/ostatus', 'peopletag' => '[A-Za-z0-9_-]+',
['action' => 'ostatusinit']); ]
);
$m->connect(
'main/ostatus',
['action' => 'ostatusinit']
);
// Remote subscription actions // Remote subscription actions
$m->connect('main/ostatusgroup', $m->connect(
['action' => 'ostatusgroup']); 'main/ostatusgroup',
$m->connect('main/ostatuspeopletag', ['action' => 'ostatusgroup']
['action' => 'ostatuspeopletag']); );
$m->connect(
'main/ostatuspeopletag',
['action' => 'ostatuspeopletag']
);
// WebSub actions // WebSub actions
$m->connect('main/push/hub', ['action' => 'pushhub']); $m->connect('main/push/hub', ['action' => 'pushhub']);
$m->connect('main/push/callback/:feed', $m->connect(
'main/push/callback/:feed',
['action' => 'pushcallback'], ['action' => 'pushcallback'],
['feed' => '[0-9]+']); ['feed' => '[0-9]+']
);
// Salmon endpoint // Salmon endpoint
$m->connect('main/salmon/user/:id', $m->connect(
'main/salmon/user/:id',
['action' => 'usersalmon'], ['action' => 'usersalmon'],
['id' => '[0-9]+']); ['id' => '[0-9]+']
$m->connect('main/salmon/group/:id', );
$m->connect(
'main/salmon/group/:id',
['action' => 'groupsalmon'], ['action' => 'groupsalmon'],
['id' => '[0-9]+']); ['id' => '[0-9]+']
$m->connect('main/salmon/peopletag/:id', );
$m->connect(
'main/salmon/peopletag/:id',
['action' => 'peopletagsalmon'], ['action' => 'peopletagsalmon'],
['id' => '[0-9]+']); ['id' => '[0-9]+']
);
return true; return true;
} }
@ -89,7 +112,7 @@ class OStatusPlugin extends Plugin
* @param QueueManager $qm * @param QueueManager $qm
* @return boolean hook return * @return boolean hook return
*/ */
function onEndInitializeQueueManager(QueueManager $qm) public function onEndInitializeQueueManager(QueueManager $qm)
{ {
// Prepare outgoing distributions after notice save. // Prepare outgoing distributions after notice save.
$qm->connect('ostatus', 'OStatusQueueHandler'); $qm->connect('ostatus', 'OStatusQueueHandler');
@ -114,7 +137,7 @@ class OStatusPlugin extends Plugin
/** /**
* Put saved notices into the queue for pubsub distribution. * Put saved notices into the queue for pubsub distribution.
*/ */
function onStartEnqueueNotice($notice, &$transports) public function onStartEnqueueNotice($notice, &$transports)
{ {
if ($notice->inScope(null) && $notice->getProfile()->hasRight(Right::PUBLICNOTICE)) { if ($notice->inScope(null) && $notice->getProfile()->hasRight(Right::PUBLICNOTICE)) {
$transports[] = 'ostatus'; $transports[] = 'ostatus';
@ -131,7 +154,7 @@ class OStatusPlugin extends Plugin
* Set up a WebSub hub link to our internal link for canonical timeline * Set up a WebSub hub link to our internal link for canonical timeline
* Atom feeds for users and groups. * Atom feeds for users and groups.
*/ */
function onStartApiAtom($feed) public function onStartApiAtom($feed)
{ {
$id = null; $id = null;
@ -140,11 +163,11 @@ class OStatusPlugin extends Plugin
$user = $feed->getUser(); $user = $feed->getUser();
$id = $user->id; $id = $user->id;
$profile = $user->getProfile(); $profile = $user->getProfile();
} else if ($feed instanceof AtomGroupNoticeFeed) { } elseif ($feed instanceof AtomGroupNoticeFeed) {
$salmonAction = 'groupsalmon'; $salmonAction = 'groupsalmon';
$group = $feed->getGroup(); $group = $feed->getGroup();
$id = $group->id; $id = $group->id;
} else if ($feed instanceof AtomListNoticeFeed) { } elseif ($feed instanceof AtomListNoticeFeed) {
$salmonAction = 'peopletagsalmon'; $salmonAction = 'peopletagsalmon';
$peopletag = $feed->getList(); $peopletag = $feed->getList();
$id = $peopletag->id; $id = $peopletag->id;
@ -179,25 +202,32 @@ class OStatusPlugin extends Plugin
* @param Profile $profile * @param Profile $profile
* @return bool hook return value * @return bool hook return value
*/ */
function onStartProfileRemoteSubscribe(HTMLOutputter $output, Profile $profile): bool public function onStartProfileRemoteSubscribe(HTMLOutputter $output, Profile $profile): bool
{ {
$this->onStartProfileListItemActionElements($output); $this->onStartProfileListItemActionElements($output);
return true; return true;
} }
function onStartGroupSubscribe($widget, $group) public function onStartGroupSubscribe($widget, $group)
{ {
$cur = common_current_user(); $cur = common_current_user();
if (empty($cur)) { if (empty($cur)) {
$widget->out->elementStart('li', 'entity_subscribe'); $widget->out->elementStart('li', 'entity_subscribe');
$url = common_local_url('ostatusinit', $url = common_local_url(
array('group' => $group->nickname)); 'ostatusinit',
$widget->out->element('a', array('href' => $url, ['group' => $group->nickname]
'class' => 'entity_remote_subscribe'), );
$widget->out->element(
'a',
[
'href' => $url,
'class' => 'entity_remote_subscribe',
],
// TRANS: Link to subscribe to a remote entity. // TRANS: Link to subscribe to a remote entity.
_m('Subscribe')); _m('Subscribe')
);
$widget->out->elementEnd('li'); $widget->out->elementEnd('li');
return false; return false;
@ -206,19 +236,26 @@ class OStatusPlugin extends Plugin
return true; return true;
} }
function onStartSubscribePeopletagForm($output, $peopletag) public function onStartSubscribePeopletagForm($output, $peopletag)
{ {
$cur = common_current_user(); $cur = common_current_user();
if (empty($cur)) { if (empty($cur)) {
$output->elementStart('li', 'entity_subscribe'); $output->elementStart('li', 'entity_subscribe');
$profile = $peopletag->getTagger(); $profile = $peopletag->getTagger();
$url = common_local_url('ostatusinit', $url = common_local_url(
array('tagger' => $profile->nickname, 'peopletag' => $peopletag->tag)); 'ostatusinit',
$output->element('a', array('href' => $url, ['tagger' => $profile->nickname, 'peopletag' => $peopletag->tag]
'class' => 'entity_remote_subscribe'), );
$output->element(
'a',
[
'href' => $url,
'class' => 'entity_remote_subscribe',
],
// TRANS: Link to subscribe to a remote entity. // TRANS: Link to subscribe to a remote entity.
_m('Subscribe')); _m('Subscribe')
);
$output->elementEnd('li'); $output->elementEnd('li');
return false; return false;
@ -230,10 +267,11 @@ class OStatusPlugin extends Plugin
/* /*
* If the field being looked for is URI look for the profile * If the field being looked for is URI look for the profile
*/ */
function onStartProfileCompletionSearch($action, $profile, $search_engine) { public function onStartProfileCompletionSearch($action, $profile, $search_engine)
{
if ($action->field == 'uri') { if ($action->field == 'uri') {
$profile->joinAdd(array('id', 'user:id')); $profile->joinAdd(['id', 'user:id']);
$profile->whereAdd('uri LIKE "%' . $profile->escape($q) . '%"'); $profile->whereAdd("uri LIKE '%" . $profile->escape($q) . "%'");
$profile->query(); $profile->query();
$validate = new Validate(); $validate = new Validate();
@ -242,14 +280,13 @@ class OStatusPlugin extends Plugin
try { try {
if ($validate->email($q)) { if ($validate->email($q)) {
$oprofile = Ostatus_profile::ensureWebfinger($q); $oprofile = Ostatus_profile::ensureWebfinger($q);
} else if ($validate->uri($q)) { } elseif ($validate->uri($q)) {
$oprofile = Ostatus_profile::ensureProfileURL($q); $oprofile = Ostatus_profile::ensureProfileURL($q);
} else { } else {
// TRANS: Exception in OStatus when invalid URI was entered. // TRANS: Exception in OStatus when invalid URI was entered.
throw new Exception(_m('Invalid URI.')); throw new Exception(_m('Invalid URI.'));
} }
return $this->filter(array($oprofile->localProfile())); return $this->filter(array($oprofile->localProfile()));
} catch (Exception $e) { } catch (Exception $e) {
// TRANS: Error message in OStatus plugin. Do not translate the domain names example.com // TRANS: Error message in OStatus plugin. Do not translate the domain names example.com
// TRANS: and example.net, as these are official standard domain names for use in examples. // TRANS: and example.net, as these are official standard domain names for use in examples.
@ -269,13 +306,15 @@ class OStatusPlugin extends Plugin
* *
* @return array The matching IDs (without $preMention) and each respective position in the given string. * @return array The matching IDs (without $preMention) and each respective position in the given string.
*/ */
static function extractWebfingerIds($text, $preMention='@') public static function extractWebfingerIds($text, $preMention = '@')
{ {
$wmatches = array(); $wmatches = array();
$result = preg_match_all('/(?<!\S)'.preg_quote($preMention, '/').'('.Nickname::WEBFINGER_FMT.')/', $result = preg_match_all(
'/(?<!\S)' . preg_quote($preMention, '/') . '(' . Nickname::WEBFINGER_FMT . ')/',
$text, $text,
$wmatches, $wmatches,
PREG_OFFSET_CAPTURE); PREG_OFFSET_CAPTURE
);
if ($result === false) { if ($result === false) {
common_log(LOG_ERR, __METHOD__ . ': Error parsing webfinger IDs from text (preg_last_error=='.preg_last_error().').'); common_log(LOG_ERR, __METHOD__ . ': Error parsing webfinger IDs from text (preg_last_error=='.preg_last_error().').');
return []; return [];
@ -292,15 +331,17 @@ class OStatusPlugin extends Plugin
* *
* @return array The matching URLs (without @ or acct:) and each respective position in the given string. * @return array The matching URLs (without @ or acct:) and each respective position in the given string.
*/ */
static function extractUrlMentions($text, $preMention='@') public static function extractUrlMentions($text, $preMention = '@')
{ {
$wmatches = array(); $wmatches = array();
// In the regexp below we need to match / _before_ URL_REGEX_VALID_PATH_CHARS because it otherwise gets merged // In the regexp below we need to match / _before_ URL_REGEX_VALID_PATH_CHARS because it otherwise gets merged
// with the TLD before (but / is in URL_REGEX_VALID_PATH_CHARS anyway, it's just its positioning that is important) // with the TLD before (but / is in URL_REGEX_VALID_PATH_CHARS anyway, it's just its positioning that is important)
$result = preg_match_all('/(?:^|\s+)'.preg_quote($preMention, '/').'('.URL_REGEX_DOMAIN_NAME.'(?:\/['.URL_REGEX_VALID_PATH_CHARS.']*)*)/', $result = preg_match_all(
'/(?:^|\s+)' . preg_quote($preMention, '/') . '(' . URL_REGEX_DOMAIN_NAME . '(?:\/[' . URL_REGEX_VALID_PATH_CHARS . ']*)*)/',
$text, $text,
$wmatches, $wmatches,
PREG_OFFSET_CAPTURE); PREG_OFFSET_CAPTURE
);
if ($result === false) { if ($result === false) {
common_log(LOG_ERR, __METHOD__ . ': Error parsing profile URL mentions from text (preg_last_error=='.preg_last_error().').'); common_log(LOG_ERR, __METHOD__ . ': Error parsing profile URL mentions from text (preg_last_error=='.preg_last_error().').');
return []; return [];
@ -319,7 +360,7 @@ class OStatusPlugin extends Plugin
* @param array &$mention in/out param: set of found mentions * @param array &$mention in/out param: set of found mentions
* @return boolean hook return value * @return boolean hook return value
*/ */
function onEndFindMentions(Profile $sender, $text, &$mentions) public function onEndFindMentions(Profile $sender, $text, &$mentions)
{ {
$matches = array(); $matches = array();
@ -472,7 +513,7 @@ class OStatusPlugin extends Plugin
* @param Profile &$profile * @param Profile &$profile
* @return hook return code * @return hook return code
*/ */
function onStartCommandGetProfile($command, $arg, &$profile) public function onStartCommandGetProfile($command, $arg, &$profile)
{ {
$oprofile = $this->pullRemoteProfile($arg); $oprofile = $this->pullRemoteProfile($arg);
if ($oprofile instanceof Ostatus_profile && !$oprofile->isGroup()) { if ($oprofile instanceof Ostatus_profile && !$oprofile->isGroup()) {
@ -499,7 +540,7 @@ class OStatusPlugin extends Plugin
* @param User_group &$group * @param User_group &$group
* @return hook return code * @return hook return code
*/ */
function onStartCommandGetGroup($command, $arg, &$group) public function onStartCommandGetGroup($command, $arg, &$group)
{ {
$oprofile = $this->pullRemoteProfile($arg); $oprofile = $this->pullRemoteProfile($arg);
if ($oprofile instanceof Ostatus_profile && $oprofile->isGroup()) { if ($oprofile instanceof Ostatus_profile && $oprofile->isGroup()) {
@ -546,21 +587,24 @@ class OStatusPlugin extends Plugin
return null; return null;
} }
function onEndProfileSettingsActions($out) { public function onEndProfileSettingsActions($out) {
$siteName = common_config('site', 'name'); $siteName = common_config('site', 'name');
$js = 'navigator.registerContentHandler("application/vnd.mozilla.maybe.feed", "'.addslashes(common_local_url('RemoteFollowSub', null, array('profile' => '%s'))).'", "'.addslashes($siteName).'")'; $js = 'navigator.registerContentHandler("application/vnd.mozilla.maybe.feed", "'.addslashes(common_local_url('RemoteFollowSub', null, array('profile' => '%s'))).'", "'.addslashes($siteName).'")';
$out->elementStart('li'); $out->elementStart('li');
$out->element('a', $out->element(
array('href' => 'javascript:'.$js), 'a',
['href' => 'javascript:' . $js],
// TRANS: Option in profile settings to add this instance to Firefox as a feedreader // TRANS: Option in profile settings to add this instance to Firefox as a feedreader
_('Add to Firefox as feedreader')); _('Add to Firefox as feedreader')
);
$out->elementEnd('li'); $out->elementEnd('li');
} }
/** /**
* Make sure necessary tables are filled out. * Make sure necessary tables are filled out.
*/ */
function onCheckSchema() { public function onCheckSchema()
{
$schema = Schema::get(); $schema = Schema::get();
$schema->ensureTable('ostatus_profile', Ostatus_profile::schemaDef()); $schema->ensureTable('ostatus_profile', Ostatus_profile::schemaDef());
$schema->ensureTable('feedsub', FeedSub::schemaDef()); $schema->ensureTable('feedsub', FeedSub::schemaDef());
@ -569,12 +613,14 @@ class OStatusPlugin extends Plugin
return true; return true;
} }
public function onEndShowStylesheets(Action $action) { public function onEndShowStylesheets(Action $action)
{
$action->cssLink($this->path('theme/base/css/ostatus.css')); $action->cssLink($this->path('theme/base/css/ostatus.css'));
return true; return true;
} }
function onEndShowStatusNetScripts($action) { public function onEndShowStatusNetScripts($action)
{
$action->script($this->path('js/ostatus.js')); $action->script($this->path('js/ostatus.js'));
return true; return true;
} }
@ -589,7 +635,7 @@ class OStatusPlugin extends Plugin
* @param string out &$title * @param string out &$title
* @return mixed hook return code * @return mixed hook return code
*/ */
function onStartNoticeSourceLink($notice, &$name, &$url, &$title) public function onStartNoticeSourceLink($notice, &$name, &$url, &$title)
{ {
// If we don't handle this, keep the event handler going // If we don't handle this, keep the event handler going
if (!in_array($notice->source, array('ostatus', 'share'))) { if (!in_array($notice->source, array('ostatus', 'share'))) {
@ -626,7 +672,7 @@ class OStatusPlugin extends Plugin
* @param DOMDocument $feed * @param DOMDocument $feed
* @return mixed hook return code * @return mixed hook return code
*/ */
function onStartFeedSubReceive($feedsub, $feed) public function onStartFeedSubReceive($feedsub, $feed)
{ {
$oprofile = Ostatus_profile::getKV('feeduri', $feedsub->uri); $oprofile = Ostatus_profile::getKV('feeduri', $feedsub->uri);
if ($oprofile instanceof Ostatus_profile) { if ($oprofile instanceof Ostatus_profile) {
@ -645,7 +691,7 @@ class OStatusPlugin extends Plugin
* @param integer $count in/out * @param integer $count in/out
* @return mixed hook return code * @return mixed hook return code
*/ */
function onFeedSubSubscriberCount($feedsub, &$count) public function onFeedSubSubscriberCount($feedsub, &$count)
{ {
$oprofile = Ostatus_profile::getKV('feeduri', $feedsub->uri); $oprofile = Ostatus_profile::getKV('feeduri', $feedsub->uri);
if ($oprofile instanceof Ostatus_profile) { if ($oprofile instanceof Ostatus_profile) {
@ -668,7 +714,7 @@ class OStatusPlugin extends Plugin
* *
* @throws Exception * @throws Exception
*/ */
function onStartSubscribe(Profile $profile, Profile $other) public function onStartSubscribe(Profile $profile, Profile $other)
{ {
if (!$profile->isLocal()) { if (!$profile->isLocal()) {
return true; return true;
@ -693,7 +739,7 @@ class OStatusPlugin extends Plugin
* *
* @throws Exception * @throws Exception
*/ */
function onEndSubscribe(Profile $profile, Profile $other) public function onEndSubscribe(Profile $profile, Profile $other)
{ {
if (!$profile->isLocal()) { if (!$profile->isLocal()) {
return true; return true;
@ -722,7 +768,7 @@ class OStatusPlugin extends Plugin
* @param Profile $other * @param Profile $other
* @return hook return value * @return hook return value
*/ */
function onEndUnsubscribe(Profile $profile, Profile $other) public function onEndUnsubscribe(Profile $profile, Profile $other)
{ {
if (!$profile->isLocal()) { if (!$profile->isLocal()) {
return true; return true;
@ -740,19 +786,23 @@ class OStatusPlugin extends Plugin
$act->verb = ActivityVerb::UNFOLLOW; $act->verb = ActivityVerb::UNFOLLOW;
$act->id = TagURI::mint('unfollow:%d:%d:%s', $act->id = TagURI::mint(
'unfollow:%d:%d:%s',
$profile->id, $profile->id,
$other->id, $other->id,
common_date_iso8601(time())); common_date_iso8601(time())
);
$act->time = time(); $act->time = time();
// TRANS: Title for unfollowing a remote profile. // TRANS: Title for unfollowing a remote profile.
$act->title = _m('TITLE','Unfollow'); $act->title = _m('TITLE', 'Unfollow');
// TRANS: Success message for unsubscribe from user attempt through OStatus. // TRANS: Success message for unsubscribe from user attempt through OStatus.
// TRANS: %1$s is the unsubscriber's name, %2$s is the unsubscribed user's name. // TRANS: %1$s is the unsubscriber's name, %2$s is the unsubscribed user's name.
$act->content = sprintf(_m('%1$s stopped following %2$s.'), $act->content = sprintf(
_m('%1$s stopped following %2$s.'),
$profile->getBestName(), $profile->getBestName(),
$other->getBestName()); $other->getBestName()
);
$act->actor = $profile->asActivityObject(); $act->actor = $profile->asActivityObject();
$act->objects[] = $other->asActivityObject(); $act->objects[] = $other->asActivityObject();
@ -773,7 +823,7 @@ class OStatusPlugin extends Plugin
* @return mixed hook return value * @return mixed hook return value
* @throws Exception of various kinds, some from $oprofile->subscribe(); * @throws Exception of various kinds, some from $oprofile->subscribe();
*/ */
function onStartJoinGroup($group, $profile) public function onStartJoinGroup($group, $profile)
{ {
$oprofile = Ostatus_profile::getKV('group_id', $group->id); $oprofile = Ostatus_profile::getKV('group_id', $group->id);
if (!$oprofile instanceof Ostatus_profile) { if (!$oprofile instanceof Ostatus_profile) {
@ -786,10 +836,12 @@ class OStatusPlugin extends Plugin
// has not yet been created. // has not yet been created.
$act = new Activity(); $act = new Activity();
$act->id = TagURI::mint('join:%d:%d:%s', $act->id = TagURI::mint(
'join:%d:%d:%s',
$profile->id, $profile->id,
$group->id, $group->id,
common_date_iso8601(time())); common_date_iso8601(time())
);
$act->actor = $profile->asActivityObject(); $act->actor = $profile->asActivityObject();
$act->verb = ActivityVerb::JOIN; $act->verb = ActivityVerb::JOIN;
@ -797,12 +849,14 @@ class OStatusPlugin extends Plugin
$act->time = time(); $act->time = time();
// TRANS: Title for joining a remote groep. // TRANS: Title for joining a remote groep.
$act->title = _m('TITLE','Join'); $act->title = _m('TITLE', 'Join');
// TRANS: Success message for subscribe to group attempt through OStatus. // TRANS: Success message for subscribe to group attempt through OStatus.
// TRANS: %1$s is the member name, %2$s is the subscribed group's name. // TRANS: %1$s is the member name, %2$s is the subscribed group's name.
$act->content = sprintf(_m('%1$s has joined group %2$s.'), $act->content = sprintf(
_m('%1$s has joined group %2$s.'),
$profile->getBestName(), $profile->getBestName(),
$oprofile->getBestName()); $oprofile->getBestName()
);
if ($oprofile->notifyActivity($act, $profile)) { if ($oprofile->notifyActivity($act, $profile)) {
return true; return true;
@ -827,7 +881,7 @@ class OStatusPlugin extends Plugin
* *
* @return mixed hook return value * @return mixed hook return value
*/ */
function onEndLeaveGroup($group, $profile) public function onEndLeaveGroup($group, $profile)
{ {
$oprofile = Ostatus_profile::getKV('group_id', $group->id); $oprofile = Ostatus_profile::getKV('group_id', $group->id);
if (!$oprofile instanceof Ostatus_profile) { if (!$oprofile instanceof Ostatus_profile) {
@ -840,10 +894,12 @@ class OStatusPlugin extends Plugin
$member = $profile; $member = $profile;
$act = new Activity(); $act = new Activity();
$act->id = TagURI::mint('leave:%d:%d:%s', $act->id = TagURI::mint(
'leave:%d:%d:%s',
$member->id, $member->id,
$group->id, $group->id,
common_date_iso8601(time())); common_date_iso8601(time())
);
$act->actor = $member->asActivityObject(); $act->actor = $member->asActivityObject();
$act->verb = ActivityVerb::LEAVE; $act->verb = ActivityVerb::LEAVE;
@ -851,12 +907,14 @@ class OStatusPlugin extends Plugin
$act->time = time(); $act->time = time();
// TRANS: Title for leaving a remote group. // TRANS: Title for leaving a remote group.
$act->title = _m('TITLE','Leave'); $act->title = _m('TITLE', 'Leave');
// TRANS: Success message for unsubscribe from group attempt through OStatus. // TRANS: Success message for unsubscribe from group attempt through OStatus.
// TRANS: %1$s is the member name, %2$s is the unsubscribed group's name. // TRANS: %1$s is the member name, %2$s is the unsubscribed group's name.
$act->content = sprintf(_m('%1$s has left group %2$s.'), $act->content = sprintf(
_m('%1$s has left group %2$s.'),
$member->getBestName(), $member->getBestName(),
$oprofile->getBestName()); $oprofile->getBestName()
);
$oprofile->notifyActivity($act, $member); $oprofile->notifyActivity($act, $member);
} }
@ -873,7 +931,7 @@ class OStatusPlugin extends Plugin
* @throws Exception of various kinds, some from $oprofile->subscribe(); * @throws Exception of various kinds, some from $oprofile->subscribe();
*/ */
function onStartSubscribePeopletag($peopletag, $user) public function onStartSubscribePeopletag($peopletag, $user)
{ {
$oprofile = Ostatus_profile::getKV('peopletag_id', $peopletag->id); $oprofile = Ostatus_profile::getKV('peopletag_id', $peopletag->id);
if (!$oprofile instanceof Ostatus_profile) { if (!$oprofile instanceof Ostatus_profile) {
@ -886,10 +944,12 @@ class OStatusPlugin extends Plugin
$tagger = Profile::getKV($peopletag->tagger); $tagger = Profile::getKV($peopletag->tagger);
$act = new Activity(); $act = new Activity();
$act->id = TagURI::mint('subscribe_peopletag:%d:%d:%s', $act->id = TagURI::mint(
'subscribe_peopletag:%d:%d:%s',
$sub->id, $sub->id,
$peopletag->id, $peopletag->id,
common_date_iso8601(time())); common_date_iso8601(time())
);
$act->actor = $sub->asActivityObject(); $act->actor = $sub->asActivityObject();
$act->verb = ActivityVerb::FOLLOW; $act->verb = ActivityVerb::FOLLOW;
@ -897,13 +957,15 @@ class OStatusPlugin extends Plugin
$act->time = time(); $act->time = time();
// TRANS: Title for following a remote list. // TRANS: Title for following a remote list.
$act->title = _m('TITLE','Follow list'); $act->title = _m('TITLE', 'Follow list');
// TRANS: Success message for remote list follow through OStatus. // TRANS: Success message for remote list follow through OStatus.
// TRANS: %1$s is the subscriber name, %2$s is the list, %3$s is the lister's name. // TRANS: %1$s is the subscriber name, %2$s is the list, %3$s is the lister's name.
$act->content = sprintf(_m('%1$s is now following people listed in %2$s by %3$s.'), $act->content = sprintf(
_m('%1$s is now following people listed in %2$s by %3$s.'),
$sub->getBestName(), $sub->getBestName(),
$oprofile->getBestName(), $oprofile->getBestName(),
$tagger->getBestName()); $tagger->getBestName()
);
if ($oprofile->notifyActivity($act, $sub)) { if ($oprofile->notifyActivity($act, $sub)) {
return true; return true;
@ -924,7 +986,7 @@ class OStatusPlugin extends Plugin
* @return mixed hook return value * @return mixed hook return value
*/ */
function onEndUnsubscribePeopletag($peopletag, $user) public function onEndUnsubscribePeopletag($peopletag, $user)
{ {
$oprofile = Ostatus_profile::getKV('peopletag_id', $peopletag->id); $oprofile = Ostatus_profile::getKV('peopletag_id', $peopletag->id);
if (!$oprofile instanceof Ostatus_profile) { if (!$oprofile instanceof Ostatus_profile) {
@ -938,10 +1000,12 @@ class OStatusPlugin extends Plugin
$tagger = Profile::getKV($peopletag->tagger); $tagger = Profile::getKV($peopletag->tagger);
$act = new Activity(); $act = new Activity();
$act->id = TagURI::mint('unsubscribe_peopletag:%d:%d:%s', $act->id = TagURI::mint(
'unsubscribe_peopletag:%d:%d:%s',
$sub->id, $sub->id,
$peopletag->id, $peopletag->id,
common_date_iso8601(time())); common_date_iso8601(time())
);
$act->actor = $member->asActivityObject(); $act->actor = $member->asActivityObject();
$act->verb = ActivityVerb::UNFOLLOW; $act->verb = ActivityVerb::UNFOLLOW;
@ -952,10 +1016,12 @@ class OStatusPlugin extends Plugin
$act->title = _m('Unfollow list'); $act->title = _m('Unfollow list');
// TRANS: Success message for remote list unfollow through OStatus. // TRANS: Success message for remote list unfollow through OStatus.
// TRANS: %1$s is the subscriber name, %2$s is the list, %3$s is the lister's name. // TRANS: %1$s is the subscriber name, %2$s is the list, %3$s is the lister's name.
$act->content = sprintf(_m('%1$s stopped following the list %2$s by %3$s.'), $act->content = sprintf(
_m('%1$s stopped following the list %2$s by %3$s.'),
$sub->getBestName(), $sub->getBestName(),
$oprofile->getBestName(), $oprofile->getBestName(),
$tagger->getBestName()); $tagger->getBestName()
);
$oprofile->notifyActivity($act, $user); $oprofile->notifyActivity($act, $user);
} }
@ -967,7 +1033,7 @@ class OStatusPlugin extends Plugin
* @param Notice $notice being favored * @param Notice $notice being favored
* @return hook return value * @return hook return value
*/ */
function onEndFavorNotice(Profile $profile, Notice $notice) public function onEndFavorNotice(Profile $profile, Notice $notice)
{ {
// Only distribute local users' favor actions, remote users // Only distribute local users' favor actions, remote users
// will have already distributed theirs. // will have already distributed theirs.
@ -1005,7 +1071,7 @@ class OStatusPlugin extends Plugin
* @return hook return value * @return hook return value
* @throws Exception of various kinds, some from $oprofile->subscribe(); * @throws Exception of various kinds, some from $oprofile->subscribe();
*/ */
function onEndTagProfile($ptag) public function onEndTagProfile($ptag)
{ {
$oprofile = Ostatus_profile::getKV('profile_id', $ptag->tagged); $oprofile = Ostatus_profile::getKV('profile_id', $ptag->tagged);
if (!$oprofile instanceof Ostatus_profile) { if (!$oprofile instanceof Ostatus_profile) {
@ -1023,18 +1089,23 @@ class OStatusPlugin extends Plugin
$tagged = Profile::getKV('id', $ptag->tagged); $tagged = Profile::getKV('id', $ptag->tagged);
$act->verb = ActivityVerb::TAG; $act->verb = ActivityVerb::TAG;
$act->id = TagURI::mint('tag_profile:%d:%d:%s', $act->id = TagURI::mint(
$plist->tagger, $plist->id, 'tag_profile:%d:%d:%s',
common_date_iso8601(time())); $plist->tagger,
$plist->id,
common_date_iso8601(time())
);
$act->time = time(); $act->time = time();
// TRANS: Title for listing a remote profile. // TRANS: Title for listing a remote profile.
$act->title = _m('TITLE','List'); $act->title = _m('TITLE', 'List');
// TRANS: Success message for remote list addition through OStatus. // TRANS: Success message for remote list addition through OStatus.
// TRANS: %1$s is the list creator's name, %2$s is the added list member, %3$s is the list name. // TRANS: %1$s is the list creator's name, %2$s is the added list member, %3$s is the list name.
$act->content = sprintf(_m('%1$s listed %2$s in the list %3$s.'), $act->content = sprintf(
_m('%1$s listed %2$s in the list %3$s.'),
$tagger->getBestName(), $tagger->getBestName(),
$tagged->getBestName(), $tagged->getBestName(),
$plist->getBestName()); $plist->getBestName()
);
$act->actor = $tagger->asActivityObject(); $act->actor = $tagger->asActivityObject();
$act->objects = array($tagged->asActivityObject()); $act->objects = array($tagged->asActivityObject());
@ -1056,7 +1127,7 @@ class OStatusPlugin extends Plugin
* @param Profile_tag $ptag the people tag that was deleted * @param Profile_tag $ptag the people tag that was deleted
* @return hook return value * @return hook return value
*/ */
function onEndUntagProfile($ptag) public function onEndUntagProfile($ptag)
{ {
$oprofile = Ostatus_profile::getKV('profile_id', $ptag->tagged); $oprofile = Ostatus_profile::getKV('profile_id', $ptag->tagged);
if (!$oprofile instanceof Ostatus_profile) { if (!$oprofile instanceof Ostatus_profile) {
@ -1074,18 +1145,23 @@ class OStatusPlugin extends Plugin
$tagged = Profile::getKV('id', $ptag->tagged); $tagged = Profile::getKV('id', $ptag->tagged);
$act->verb = ActivityVerb::UNTAG; $act->verb = ActivityVerb::UNTAG;
$act->id = TagURI::mint('untag_profile:%d:%d:%s', $act->id = TagURI::mint(
$plist->tagger, $plist->id, 'untag_profile:%d:%d:%s',
common_date_iso8601(time())); $plist->tagger,
$plist->id,
common_date_iso8601(time())
);
$act->time = time(); $act->time = time();
// TRANS: Title for unlisting a remote profile. // TRANS: Title for unlisting a remote profile.
$act->title = _m('TITLE','Unlist'); $act->title = _m('TITLE', 'Unlist');
// TRANS: Success message for remote list removal through OStatus. // TRANS: Success message for remote list removal through OStatus.
// TRANS: %1$s is the list creator's name, %2$s is the removed list member, %3$s is the list name. // TRANS: %1$s is the list creator's name, %2$s is the removed list member, %3$s is the list name.
$act->content = sprintf(_m('%1$s removed %2$s from the list %3$s.'), $act->content = sprintf(
_m('%1$s removed %2$s from the list %3$s.'),
$tagger->getBestName(), $tagger->getBestName(),
$tagged->getBestName(), $tagged->getBestName(),
$plist->getBestName()); $plist->getBestName()
);
$act->actor = $tagger->asActivityObject(); $act->actor = $tagger->asActivityObject();
$act->objects = array($tagged->asActivityObject()); $act->objects = array($tagged->asActivityObject());
@ -1107,7 +1183,7 @@ class OStatusPlugin extends Plugin
* *
* @return hook return value * @return hook return value
*/ */
function onEndDisfavorNotice(Profile $profile, Notice $notice) public function onEndDisfavorNotice(Profile $profile, Notice $notice)
{ {
// Only distribute local users' disfavor actions, remote users // Only distribute local users' disfavor actions, remote users
// will have already distributed theirs. // will have already distributed theirs.
@ -1123,18 +1199,22 @@ class OStatusPlugin extends Plugin
$act = new Activity(); $act = new Activity();
$act->verb = ActivityVerb::UNFAVORITE; $act->verb = ActivityVerb::UNFAVORITE;
$act->id = TagURI::mint('disfavor:%d:%d:%s', $act->id = TagURI::mint(
'disfavor:%d:%d:%s',
$profile->id, $profile->id,
$notice->id, $notice->id,
common_date_iso8601(time())); common_date_iso8601(time())
);
$act->time = time(); $act->time = time();
// TRANS: Title for unliking a remote notice. // TRANS: Title for unliking a remote notice.
$act->title = _m('Unlike'); $act->title = _m('Unlike');
// TRANS: Success message for remove a favorite notice through OStatus. // TRANS: Success message for remove a favorite notice through OStatus.
// TRANS: %1$s is the unfavoring user's name, %2$s is URI to the no longer favored notice. // TRANS: %1$s is the unfavoring user's name, %2$s is URI to the no longer favored notice.
$act->content = sprintf(_m('%1$s no longer likes %2$s.'), $act->content = sprintf(
_m('%1$s no longer likes %2$s.'),
$profile->getBestName(), $profile->getBestName(),
$notice->getUrl()); $notice->getUrl()
);
$act->actor = $profile->asActivityObject(); $act->actor = $profile->asActivityObject();
$act->objects[] = $notice->asActivityObject(); $act->objects[] = $notice->asActivityObject();
@ -1144,7 +1224,7 @@ class OStatusPlugin extends Plugin
return true; return true;
} }
function onStartGetProfileUri($profile, &$uri) public function onStartGetProfileUri($profile, &$uri)
{ {
$oprofile = Ostatus_profile::getKV('profile_id', $profile->id); $oprofile = Ostatus_profile::getKV('profile_id', $profile->id);
if ($oprofile instanceof Ostatus_profile) { if ($oprofile instanceof Ostatus_profile) {
@ -1154,12 +1234,12 @@ class OStatusPlugin extends Plugin
return true; return true;
} }
function onStartUserGroupHomeUrl($group, &$url) public function onStartUserGroupHomeUrl($group, &$url)
{ {
return $this->onStartUserGroupPermalink($group, $url); return $this->onStartUserGroupPermalink($group, $url);
} }
function onStartUserGroupPermalink($group, &$url) public function onStartUserGroupPermalink($group, &$url)
{ {
$oprofile = Ostatus_profile::getKV('group_id', $group->id); $oprofile = Ostatus_profile::getKV('group_id', $group->id);
if ($oprofile instanceof Ostatus_profile) { if ($oprofile instanceof Ostatus_profile) {
@ -1170,21 +1250,21 @@ class OStatusPlugin extends Plugin
} }
} }
function onStartShowUserGroupsContent($action) public function onStartShowUserGroupsContent($action)
{ {
$this->showEntityRemoteSubscribe($action); $this->showEntityRemoteSubscribe($action);
return true; return true;
} }
function onEndShowGroupsMiniList($action) public function onEndShowGroupsMiniList($action)
{ {
$this->showEntityRemoteSubscribe($action); $this->showEntityRemoteSubscribe($action);
return true; return true;
} }
function showEntityRemoteSubscribe($action) public function showEntityRemoteSubscribe($action)
{ {
if (!$action->getScoped() instanceof Profile) { if (!$action->getScoped() instanceof Profile) {
// early return if we're not logged in // early return if we're not logged in
@ -1195,10 +1275,15 @@ class OStatusPlugin extends Plugin
$action->elementStart('div', 'entity_actions'); $action->elementStart('div', 'entity_actions');
$action->elementStart('p', array('id' => 'entity_remote_subscribe', $action->elementStart('p', array('id' => 'entity_remote_subscribe',
'class' => 'entity_subscribe')); 'class' => 'entity_subscribe'));
$action->element('a', array('href' => common_local_url('ostatusgroup'), $action->element(
'class' => 'entity_remote_subscribe'), 'a',
[
'href' => common_local_url('ostatusgroup'),
'class' => 'entity_remote_subscribe',
],
// TRANS: Link text for link to remote subscribe. // TRANS: Link text for link to remote subscribe.
_m('Remote')); _m('Remote')
);
$action->elementEnd('p'); $action->elementEnd('p');
$action->elementEnd('div'); $action->elementEnd('div');
} }
@ -1208,7 +1293,7 @@ class OStatusPlugin extends Plugin
* Ping remote profiles with updates to this profile. * Ping remote profiles with updates to this profile.
* Salmon pings are queued for background processing. * Salmon pings are queued for background processing.
*/ */
function onEndBroadcastProfile(Profile $profile) public function onEndBroadcastProfile(Profile $profile)
{ {
$user = User::getKV('id', $profile->id); $user = User::getKV('id', $profile->id);
@ -1233,16 +1318,20 @@ class OStatusPlugin extends Plugin
$act = new Activity(); $act = new Activity();
$act->verb = ActivityVerb::UPDATE_PROFILE; $act->verb = ActivityVerb::UPDATE_PROFILE;
$act->id = TagURI::mint('update-profile:%d:%s', $act->id = TagURI::mint(
'update-profile:%d:%s',
$profile->id, $profile->id,
common_date_iso8601(time())); common_date_iso8601(time())
);
$act->time = time(); $act->time = time();
// TRANS: Title for activity. // TRANS: Title for activity.
$act->title = _m('Profile update'); $act->title = _m('Profile update');
// TRANS: Ping text for remote profile update through OStatus. // TRANS: Ping text for remote profile update through OStatus.
// TRANS: %s is user that updated their profile. // TRANS: %s is user that updated their profile.
$act->content = sprintf(_m('%s has updated their profile page.'), $act->content = sprintf(
$profile->getBestName()); _m('%s has updated their profile page.'),
$profile->getBestName()
);
$act->actor = $profile->asActivityObject(); $act->actor = $profile->asActivityObject();
$act->objects[] = $act->actor; $act->objects[] = $act->actor;
@ -1254,7 +1343,7 @@ class OStatusPlugin extends Plugin
return true; return true;
} }
function onEndShowAccountProfileBlock(HTMLOutputter $out, Profile $profile) public function onEndShowAccountProfileBlock(HTMLOutputter $out, Profile $profile)
{ {
if ($profile->isLocal()) { if ($profile->isLocal()) {
return true; return true;
@ -1288,7 +1377,7 @@ class OStatusPlugin extends Plugin
} }
// FIXME: This one can accept both an Action and a Widget. Confusing! Refactor to (HTMLOutputter $out, Profile $target)! // FIXME: This one can accept both an Action and a Widget. Confusing! Refactor to (HTMLOutputter $out, Profile $target)!
function onStartProfileListItemActionElements($item) public function onStartProfileListItemActionElements($item)
{ {
if (common_logged_in()) { if (common_logged_in()) {
// only non-logged in users get to see the "remote subscribe" form // only non-logged in users get to see the "remote subscribe" form
@ -1314,8 +1403,10 @@ class OStatusPlugin extends Plugin
$output->elementStart('li', 'entity_tag'); $output->elementStart('li', 'entity_tag');
$url = common_local_url('ostatustag', ['nickname' => $target->getNickname()]); $url = common_local_url('ostatustag', ['nickname' => $target->getNickname()]);
$output->element('a', $output->element('a',
['href' => $url, [
'class' => 'entity_remote_tag'], 'href' => $url,
'class' => 'entity_remote_tag',
],
// TRANS: Link text for a user to list an OStatus user. // TRANS: Link text for a user to list an OStatus user.
_m('List')); _m('List'));
$output->elementEnd('li'); $output->elementEnd('li');
@ -1388,7 +1479,7 @@ class OStatusPlugin extends Plugin
return false; return false;
} }
function onStartGetProfileFromURI($uri, &$profile) public function onStartGetProfileFromURI($uri, &$profile)
{ {
// Don't want to do Web-based discovery on our own server, // Don't want to do Web-based discovery on our own server,
// so we check locally first. This duplicates the functionality // so we check locally first. This duplicates the functionality
@ -1417,7 +1508,7 @@ class OStatusPlugin extends Plugin
} }
} }
function onEndWebFingerNoticeLinks(XML_XRD $xrd, Notice $target) public function onEndWebFingerNoticeLinks(XML_XRD $xrd, Notice $target)
{ {
$salmon_url = null; $salmon_url = null;
$actor = $target->getProfile(); $actor = $target->getProfile();
@ -1439,16 +1530,19 @@ class OStatusPlugin extends Plugin
return true; return true;
} }
function onEndWebFingerProfileLinks(XML_XRD $xrd, Profile $target) public function onEndWebFingerProfileLinks(XML_XRD $xrd, Profile $target)
{ {
if ($target->getObjectType() === ActivityObject::PERSON) { if ($target->getObjectType() === ActivityObject::PERSON) {
$this->addWebFingerPersonLinks($xrd, $target); $this->addWebFingerPersonLinks($xrd, $target);
} elseif ($target->getObjectType() === ActivityObject::GROUP) { } elseif ($target->getObjectType() === ActivityObject::GROUP) {
$xrd->links[] = new XML_XRD_Element_Link(Discovery::UPDATESFROM, $xrd->links[] = new XML_XRD_Element_Link(
common_local_url('ApiTimelineGroup', Discovery::UPDATESFROM,
array('id' => $target->getGroup()->getID(), 'format' => 'atom')), common_local_url(
'application/atom+xml'); 'ApiTimelineGroup',
['id' => $target->getGroup()->getID(), 'format' => 'atom']
),
'application/atom+xml'
);
} }
// Salmon // Salmon
@ -1479,10 +1573,14 @@ class OStatusPlugin extends Plugin
protected function addWebFingerPersonLinks(XML_XRD $xrd, Profile $target) protected function addWebFingerPersonLinks(XML_XRD $xrd, Profile $target)
{ {
$xrd->links[] = new XML_XRD_Element_Link(Discovery::UPDATESFROM, $xrd->links[] = new XML_XRD_Element_Link(
common_local_url('ApiTimelineUser', Discovery::UPDATESFROM,
array('id' => $target->id, 'format' => 'atom')), common_local_url(
'application/atom+xml'); 'ApiTimelineUser',
['id' => $target->id, 'format' => 'atom']
),
'application/atom+xml'
);
// Get this profile's keypair // Get this profile's keypair
$magicsig = Magicsig::getKV('user_id', $target->id); $magicsig = Magicsig::getKV('user_id', $target->id);
@ -1494,8 +1592,10 @@ class OStatusPlugin extends Plugin
return false; // value doesn't mean anything, just figured I'd indicate this function didn't do anything return false; // value doesn't mean anything, just figured I'd indicate this function didn't do anything
} }
if (Event::handle('StartAttachPubkeyToUserXRD', array($magicsig, $xrd, $target))) { if (Event::handle('StartAttachPubkeyToUserXRD', array($magicsig, $xrd, $target))) {
$xrd->links[] = new XML_XRD_Element_Link(Magicsig::PUBLICKEYREL, $xrd->links[] = new XML_XRD_Element_Link(
'data:application/magic-public-key,'. $magicsig->toString()); Magicsig::PUBLICKEYREL,
'data:application/magic-public-key,' . $magicsig->toString()
);
// The following event handles plugins like Diaspora which add their own version of the Magicsig pubkey // The following event handles plugins like Diaspora which add their own version of the Magicsig pubkey
Event::handle('EndAttachPubkeyToUserXRD', array($magicsig, $xrd, $target)); Event::handle('EndAttachPubkeyToUserXRD', array($magicsig, $xrd, $target));
} }
@ -1507,7 +1607,7 @@ class OStatusPlugin extends Plugin
} }
// FIXME: Maybe this shouldn't be so authoritative that it breaks other remote profile lookups? // FIXME: Maybe this shouldn't be so authoritative that it breaks other remote profile lookups?
static public function onCheckActivityAuthorship(Activity $activity, Profile &$profile) public static function onCheckActivityAuthorship(Activity $activity, Profile &$profile)
{ {
try { try {
$oprofile = Ostatus_profile::ensureProfileURL($profile->getUrl()); $oprofile = Ostatus_profile::ensureProfileURL($profile->getUrl());
@ -1562,8 +1662,13 @@ class OStatusPlugin extends Plugin
// 201 Created is what Mastodon returns when it's ok // 201 Created is what Mastodon returns when it's ok
// 202 Accepted is what we get from Diaspora, also good // 202 Accepted is what we get from Diaspora, also good
if (!in_array($response->getStatus(), array(200, 201, 202))) { if (!in_array($response->getStatus(), array(200, 201, 202))) {
common_log(LOG_ERR, sprintf('Salmon (from profile %d) endpoint %s returned status %s: %s', common_log(LOG_ERR, sprintf(
$magic_env->getActor()->getID(), $endpoint_uri, $response->getStatus(), $response->getBody())); 'Salmon (from profile %d) endpoint %s returned status %s: %s',
$magic_env->getActor()->getID(),
$endpoint_uri,
$response->getStatus(),
$response->getBody()
));
return true; return true;
} }

View File

@ -1,29 +1,32 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2009-2010, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/** /**
* FeedSub handles low-level WebSub (PubSubHubbub/PuSH) subscriptions.
* Higher-level behavior building OStatus stuff on top is handled
* under Ostatus_profile.
*
* @package OStatusPlugin * @package OStatusPlugin
* @maintainer Brion Vibber <brion@status.net> * @author Brion Vibber <brion@status.net>
* @copyright 2009-2010 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
defined('GNUSOCIAL') || die();
/* /*
WebSub (previously PubSubHubbub/PuSH) subscription flow: WebSub (previously PubSubHubbub/PuSH) subscription flow:
@ -37,14 +40,8 @@ WebSub (previously PubSubHubbub/PuSH) subscription flow:
main/push/callback main/push/callback
hub sends us updates via POST hub sends us updates via POST
*/ */
/**
* FeedSub handles low-level WebSub (PubSubHubbub/PuSH) subscriptions.
* Higher-level behavior building OStatus stuff on top is handled
* under Ostatus_profile.
*/
class FeedSub extends Managed_DataObject class FeedSub extends Managed_DataObject
{ {
public $__table = 'feedsub'; public $__table = 'feedsub';
@ -71,7 +68,7 @@ class FeedSub extends Managed_DataObject
'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'FeedSub uri'), 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'FeedSub uri'),
'huburi' => array('type' => 'text', 'description' => 'FeedSub hub-uri'), 'huburi' => array('type' => 'text', 'description' => 'FeedSub hub-uri'),
'secret' => array('type' => 'text', 'description' => 'FeedSub stored secret'), 'secret' => array('type' => 'text', 'description' => 'FeedSub stored secret'),
'sub_state' => array('type' => 'enum("subscribe","active","unsubscribe","inactive","nohub")', 'not null' => true, 'description' => 'subscription state'), 'sub_state' => array('type' => 'enum', 'enum' => array('subscribe', 'active', 'unsubscribe', 'inactive', 'nohub'), 'not null' => true, 'description' => 'subscription state'),
'sub_start' => array('type' => 'datetime', 'description' => 'subscription start'), 'sub_start' => array('type' => 'datetime', 'description' => 'subscription start'),
'sub_end' => array('type' => 'datetime', 'description' => 'subscription end'), 'sub_end' => array('type' => 'datetime', 'description' => 'subscription end'),
'last_update' => array('type' => 'datetime', 'description' => 'when this record was last updated'), 'last_update' => array('type' => 'datetime', 'description' => 'when this record was last updated'),
@ -96,7 +93,7 @@ class FeedSub extends Managed_DataObject
return $this->uri; return $this->uri;
} }
function getLeaseRemaining() public function getLeaseRemaining()
{ {
if (empty($this->sub_end)) { if (empty($this->sub_end)) {
return null; return null;
@ -180,7 +177,6 @@ class FeedSub extends Managed_DataObject
try { try {
// discover the hub uri // discover the hub uri
$feedsub->ensureHub(); $feedsub->ensureHub();
} catch (FeedSubNoHubException $e) { } catch (FeedSubNoHubException $e) {
// Only throw this exception if we can't handle huburi-less feeds // Only throw this exception if we can't handle huburi-less feeds
// (i.e. we have a fallback hub or we can do feed polling (nohub) // (i.e. we have a fallback hub or we can do feed polling (nohub)
@ -263,7 +259,7 @@ class FeedSub extends Managed_DataObject
*/ */
public function subscribe($rediscovered=false) public function subscribe($rediscovered=false)
{ {
if ($this->sub_state && $this->sub_state != 'inactive') { if ($this->sub_state !== 'inactive') {
common_log(LOG_WARNING, sprintf('Attempting to (re)start WebSub subscription to %s in unexpected state %s', $this->getUri(), $this->sub_state)); common_log(LOG_WARNING, sprintf('Attempting to (re)start WebSub subscription to %s in unexpected state %s', $this->getUri(), $this->sub_state));
} }
@ -276,7 +272,7 @@ class FeedSub extends Managed_DataObject
if (common_config('feedsub', 'fallback_hub')) { if (common_config('feedsub', 'fallback_hub')) {
// No native hub on this feed? // No native hub on this feed?
// Use our fallback hub, which handles polling on our behalf. // Use our fallback hub, which handles polling on our behalf.
} else if (common_config('feedsub', 'nohub')) { } elseif (common_config('feedsub', 'nohub')) {
// For this to actually work, we'll need some polling mechanism. // For this to actually work, we'll need some polling mechanism.
// The FeedPoller plugin should take care of it. // The FeedPoller plugin should take care of it.
return; return;
@ -298,7 +294,8 @@ class FeedSub extends Managed_DataObject
* *
* @throws ServerException if feed state is not valid * @throws ServerException if feed state is not valid
*/ */
public function unsubscribe() { public function unsubscribe()
{
if ($this->sub_state != 'active') { if ($this->sub_state != 'active') {
common_log(LOG_WARNING, sprintf('Attempting to (re)end WebSub subscription to %s in unexpected state %s', $this->getUri(), $this->sub_state)); common_log(LOG_WARNING, sprintf('Attempting to (re)end WebSub subscription to %s in unexpected state %s', $this->getUri(), $this->sub_state));
} }
@ -344,7 +341,7 @@ class FeedSub extends Managed_DataObject
*/ */
public function garbageCollect() public function garbageCollect()
{ {
if ($this->sub_state == '' || $this->sub_state == 'inactive') { if ($this->sub_state === 'inactive') {
// No active WebSub subscription, we can just leave it be. // No active WebSub subscription, we can just leave it be.
return true; return true;
} }
@ -366,12 +363,12 @@ class FeedSub extends Managed_DataObject
return true; return true;
} }
static public function renewalCheck() public static function renewalCheck()
{ {
$fs = new FeedSub(); $fs = new FeedSub();
// the "" empty string check is because we historically haven't saved unsubscribed feeds as NULL $fs->whereAdd("sub_end IS NOT NULL AND sub_end < (CURRENT_TIMESTAMP + INTERVAL '1' DAY)");
$fs->whereAdd('sub_end IS NOT NULL AND sub_end!="" AND sub_end < NOW() + INTERVAL 1 day'); // find can be both false and 0, depending on why nothing was found
if (!$fs->find()) { // find can be both false and 0, depending on why nothing was found if (!$fs->find()) {
throw new NoResultException($fs); throw new NoResultException($fs);
} }
return $fs; return $fs;
@ -437,10 +434,10 @@ class FeedSub extends Managed_DataObject
if ($status == 202 || $status == 204) { if ($status == 202 || $status == 204) {
common_log(LOG_INFO, __METHOD__ . ': sub req ok, awaiting verification callback'); common_log(LOG_INFO, __METHOD__ . ': sub req ok, awaiting verification callback');
return; return;
} else if ($status >= 200 && $status < 300) { } elseif ($status >= 200 && $status < 300) {
common_log(LOG_ERR, __METHOD__ . ": sub req returned unexpected HTTP $status: " . $response->getBody()); common_log(LOG_ERR, __METHOD__ . ": sub req returned unexpected HTTP $status: " . $response->getBody());
$msg = sprintf(_m("Unexpected HTTP status: %d"), $status); $msg = sprintf(_m("Unexpected HTTP status: %d"), $status);
} else if ($status == 422 && !$rediscovered) { } elseif ($status == 422 && !$rediscovered) {
// Error code regarding something wrong in the data (it seems // Error code regarding something wrong in the data (it seems
// that we're talking to a WebSub hub at least, so let's check // that we're talking to a WebSub hub at least, so let's check
// our own data to be sure we're not mistaken somehow, which // our own data to be sure we're not mistaken somehow, which
@ -482,7 +479,8 @@ class FeedSub extends Managed_DataObject
if ($lease_seconds > 0) { if ($lease_seconds > 0) {
$this->sub_end = common_sql_date(time() + $lease_seconds); $this->sub_end = common_sql_date(time() + $lease_seconds);
} else { } else {
$this->sub_end = null; // Backwards compatibility to StatusNet (PuSH <0.4 supported permanent subs) // Backwards compatibility to StatusNet (PuSH <0.4 supported permanent subs)
$this->sub_end = DB_DataObject_Cast::sql('NULL');
} }
$this->modified = common_sql_now(); $this->modified = common_sql_now();
@ -498,11 +496,10 @@ class FeedSub extends Managed_DataObject
{ {
$original = clone($this); $original = clone($this);
// @fixme these should all be null, but DB_DataObject doesn't save null values...????? $this->secret = DB_DataObject_Cast::sql('NULL');
$this->secret = ''; $this->sub_state = 'inactive';
$this->sub_state = ''; $this->sub_start = DB_DataObject_Cast::sql('NULL');
$this->sub_start = ''; $this->sub_end = DB_DataObject_Cast::sql('NULL');
$this->sub_end = '';
$this->modified = common_sql_now(); $this->modified = common_sql_now();
return $this->update($original); return $this->update($original);
@ -544,7 +541,6 @@ class FeedSub extends Managed_DataObject
} }
$this->receiveFeed($post); $this->receiveFeed($post);
} catch (FeedSubBadPushSignatureException $e) { } catch (FeedSubBadPushSignatureException $e) {
// We got a signature, so something could be wrong. Let's check to see if // We got a signature, so something could be wrong. Let's check to see if
// maybe upstream has switched to another hub. Let's fetch feed and then // maybe upstream has switched to another hub. Let's fetch feed and then
@ -628,7 +624,6 @@ class FeedSub extends Managed_DataObject
throw new FeedSubBadPushSignatureException('Incoming WebSub push signature did not match expected HMAC hash.'); throw new FeedSubBadPushSignatureException('Incoming WebSub push signature did not match expected HMAC hash.');
} }
return true; return true;
} else { } else {
common_log(LOG_ERR, sprintf(__METHOD__.': ignoring WebSub push with bogus HMAC==', _ve($hmac))); common_log(LOG_ERR, sprintf(__METHOD__.': ignoring WebSub push with bogus HMAC==', _ve($hmac)));
} }

View File

@ -57,7 +57,7 @@ class HubSub extends Managed_DataObject
'secret' => array('type' => 'text', 'description' => 'HubSub stored secret'), 'secret' => array('type' => 'text', 'description' => 'HubSub stored secret'),
'sub_start' => array('type' => 'datetime', 'description' => 'subscription start'), 'sub_start' => array('type' => 'datetime', 'description' => 'subscription start'),
'sub_end' => array('type' => 'datetime', 'description' => 'subscription end'), 'sub_end' => array('type' => 'datetime', 'description' => 'subscription end'),
'errors' => array('type' => 'integer', 'not null' => true, 'default' => 0, 'description' => 'Queue handling error count, is reset on success.'), 'errors' => array('type' => 'int', 'not null' => true, 'default' => 0, 'description' => 'Queue handling error count, is reset on success.'),
'error_start' => array('type' => 'datetime', 'default' => null, 'description' => 'time of first error since latest success, should be null if no errors have been counted'), 'error_start' => array('type' => 'datetime', 'default' => null, 'description' => 'time of first error since latest success, should be null if no errors have been counted'),
'last_error' => array('type' => 'datetime', 'default' => null, 'description' => 'time of last failure, if ever'), 'last_error' => array('type' => 'datetime', 'default' => null, 'description' => 'time of last failure, if ever'),
'last_error_msg' => array('type' => 'text', 'default' => null, 'description' => 'Last error _message_'), 'last_error_msg' => array('type' => 'text', 'default' => null, 'description' => 'Last error _message_'),

View File

@ -51,9 +51,9 @@ class Ostatus_profile extends Managed_DataObject
return array( return array(
'fields' => array( 'fields' => array(
'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true), 'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
'profile_id' => array('type' => 'integer'), 'profile_id' => array('type' => 'int'),
'group_id' => array('type' => 'integer'), 'group_id' => array('type' => 'int'),
'peopletag_id' => array('type' => 'integer'), 'peopletag_id' => array('type' => 'int'),
'feeduri' => array('type' => 'varchar', 'length' => 191), 'feeduri' => array('type' => 'varchar', 'length' => 191),
'salmonuri' => array('type' => 'varchar', 'length' => 191), 'salmonuri' => array('type' => 'varchar', 'length' => 191),
'avatar' => array('type' => 'text'), 'avatar' => array('type' => 'text'),

View File

@ -1,21 +1,23 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - a distributed open-source microblogging tool //
* Copyright (C) 2010 StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>. /**
* @copyright 2010 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
/* /*
@ -53,7 +55,7 @@ echo "Looking for feed subscriptions with dirty no good huburis...\n";
$feedsub = new FeedSub(); $feedsub = new FeedSub();
$feedsub->sub_state = 'subscribe'; $feedsub->sub_state = 'subscribe';
$feedsub->whereAdd('created < DATE_SUB(NOW(), INTERVAL 1 HOUR)'); $feedsub->whereAdd("created < (CURRENT_TIMESTAMP - INTERVAL '1' HOUR)");
$feedsub->find(); $feedsub->find();
$cnt = 0; $cnt = 0;

View File

@ -1,21 +1,23 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - a distributed open-source microblogging tool //
* Copyright (C) 2010, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>. /**
* @copyright 2010 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..')); define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
@ -39,7 +41,8 @@ END_OF_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc'; require_once INSTALLDIR.'/scripts/commandline.inc';
function showProfileInfo(Ostatus_profile $oprofile) { function showProfileInfo(Ostatus_profile $oprofile)
{
if ($oprofile->isGroup()) { if ($oprofile->isGroup()) {
echo "group\n"; echo "group\n";
} else { } else {
@ -51,7 +54,8 @@ function showProfileInfo(Ostatus_profile $oprofile) {
echo "\n"; echo "\n";
} }
function fixProfile(Ostatus_profile $oprofile) { function fixProfile(Ostatus_profile $oprofile)
{
echo "Before:\n"; echo "Before:\n";
showProfileInfo($oprofile); showProfileInfo($oprofile);
@ -102,10 +106,10 @@ if (have_option('all')) {
echo "Failed on URI=="._ve($oprofile->uri).": {$e->getMessage()}\n"; echo "Failed on URI=="._ve($oprofile->uri).": {$e->getMessage()}\n";
} }
} }
} else if (have_option('suspicious')) { } elseif (have_option('suspicious')) {
$oprofile = new Ostatus_profile(); $oprofile = new Ostatus_profile();
$oprofile->joinAdd(array('profile_id', 'profile:id')); $oprofile->joinAdd(['profile_id', 'profile:id']);
$oprofile->whereAdd("nickname rlike '^[0-9]$'"); $oprofile->whereAdd("CHAR_LENGTH(nickname) = 1 AND nickname BETWEEN '0' AND '9'");
$oprofile->find(); $oprofile->find();
echo "Found $oprofile->N matching profiles:\n\n"; echo "Found $oprofile->N matching profiles:\n\n";
while ($oprofile->fetch()) { while ($oprofile->fetch()) {
@ -116,7 +120,7 @@ if (have_option('all')) {
echo "Failed on URI=="._ve($oprofile->uri).": {$e->getMessage()}\n"; echo "Failed on URI=="._ve($oprofile->uri).": {$e->getMessage()}\n";
} }
} }
} else if (!empty($args[0]) && $validate->uri($args[0])) { } elseif (!empty($args[0]) && $validate->uri($args[0])) {
$uri = $args[0]; $uri = $args[0];
$oprofile = Ostatus_profile::getKV('uri', $uri); $oprofile = Ostatus_profile::getKV('uri', $uri);

View File

@ -1,35 +1,30 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Settings for OpenID * Settings for OpenID
* *
* 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 Settings * @category Settings
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @copyright 2008-2009 StatusNet, Inc. * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('GNUSOCIAL')) { defined('GNUSOCIAL') || die();
exit(1);
}
require_once INSTALLDIR.'/plugins/OpenID/openid.php'; require_once INSTALLDIR.'/plugins/OpenID/openid.php';
@ -38,11 +33,8 @@ require_once INSTALLDIR.'/plugins/OpenID/openid.php';
* *
* Lets users add, edit and delete OpenIDs from their account * Lets users add, edit and delete OpenIDs from their account
* *
* @category Settings * @copyright 2008-2009 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @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 OpenidsettingsAction extends SettingsAction class OpenidsettingsAction extends SettingsAction
{ {
@ -100,17 +92,26 @@ class OpenidsettingsAction extends SettingsAction
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label. // TRANS: Field label.
$this->input('openid_url', _m('OpenID URL'), null, $this->input(
'openid_url',
_m('OpenID URL'),
null,
// TRANS: Form guide. // TRANS: Form guide.
_m('An OpenID URL which identifies you.'), _m('An OpenID URL which identifies you.'),
null, true, null,
['placeholder'=>'https://example.com/you']); true,
['placeholder' => 'https://example.com/you']
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label. // TRANS: Field label.
$this->checkbox('openid-synch', _m('Synchronize Account'), false, $this->checkbox(
'openid-synch',
_m('Synchronize Account'),
false,
// TRANS: Form guide. // TRANS: Form guide.
_m('Synchronize GNU social profile with this OpenID identity.')); _m('Synchronize GNU social profile with this OpenID identity.')
);
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Button text for adding an OpenID URL. // TRANS: Button text for adding an OpenID URL.
@ -129,13 +130,16 @@ class OpenidsettingsAction extends SettingsAction
$this->element('h2', null, _m('HEADER', 'OpenID Actions')); $this->element('h2', null, _m('HEADER', 'OpenID Actions'));
if ($cnt == 1 && !$this->scoped->hasPassword()) { if ($cnt == 1 && !$this->scoped->hasPassword()) {
$this->element('p', 'form_guide', $this->element(
'p',
'form_guide',
// TRANS: Form guide. // TRANS: Form guide.
_m('You can\'t remove your main OpenID account ' . _m('You can\'t remove your main OpenID account ' .
'without either adding a password to your ' . 'without either adding a password to your ' .
'GNU social account or another OpenID account. ' . 'GNU social account or another OpenID account. ' .
'You can synchronize your profile with your ' . 'You can synchronize your profile with your ' .
'OpenID by clicking the button labeled "Synchronize".')); 'OpenID by clicking the button labeled "Synchronize".')
);
if ($oid->fetch()) { if ($oid->fetch()) {
$this->elementStart('form', ['method' => 'POST', $this->elementStart('form', ['method' => 'POST',
@ -152,12 +156,15 @@ class OpenidsettingsAction extends SettingsAction
$this->elementEnd('form'); $this->elementEnd('form');
} }
} else { } else {
$this->element('p', 'form_guide', $this->element(
'p',
'form_guide',
// TRANS: Form guide. // TRANS: Form guide.
_m('You can remove an OpenID from your account ' . _m('You can remove an OpenID from your account ' .
'by clicking the button labeled "Remove". ' . 'by clicking the button labeled "Remove". ' .
'You can synchronize your profile with an OpenID ' . 'You can synchronize your profile with an OpenID ' .
'by clicking the button labeled "Synchronize".')); 'by clicking the button labeled "Synchronize".')
);
$idx = 0; $idx = 0;
while ($oid->fetch()) { while ($oid->fetch()) {
@ -191,26 +198,38 @@ class OpenidsettingsAction extends SettingsAction
// TRANS: Fieldset legend. // TRANS: Fieldset legend.
$this->element('legend', null, _m('OpenID Trusted Sites')); $this->element('legend', null, _m('OpenID Trusted Sites'));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->element('p', 'form_guide', $this->element(
'p',
'form_guide',
// TRANS: Form guide. // TRANS: Form guide.
_m('The following sites are allowed to access your ' . _m('The following sites are allowed to access your ' .
'identity and log you in. You can remove a site from ' . 'identity and log you in. You can remove a site from ' .
'this list to deny it access to your OpenID.')); 'this list to deny it access to your OpenID.')
);
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$user_openid_trustroot = new User_openid_trustroot(); $user_openid_trustroot = new User_openid_trustroot();
$user_openid_trustroot->user_id = $this->scoped->getID(); $user_openid_trustroot->user_id = $this->scoped->getID();
if ($user_openid_trustroot->find()) { if ($user_openid_trustroot->find()) {
while ($user_openid_trustroot->fetch()) { while ($user_openid_trustroot->fetch()) {
$this->elementStart('li'); $this->elementStart('li');
$this->element('input', ['name' => 'openid_trustroot[]', $this->element(
'input',
[
'name' => 'openid_trustroot[]',
'type' => 'checkbox', 'type' => 'checkbox',
'class' => 'checkbox', 'class' => 'checkbox',
'value' => $user_openid_trustroot->trustroot, 'value' => $user_openid_trustroot->trustroot,
'id' => 'openid_trustroot_' . crc32($user_openid_trustroot->trustroot)]); 'id' => 'openid_trustroot_' . crc32($user_openid_trustroot->trustroot),
$this->element('label', ]
['class'=>'checkbox', );
'for' => 'openid_trustroot_' . crc32($user_openid_trustroot->trustroot)], $this->element(
$user_openid_trustroot->trustroot); 'label',
[
'class'=>'checkbox',
'for' => 'openid_trustroot_' . crc32($user_openid_trustroot->trustroot),
],
$user_openid_trustroot->trustroot
);
$this->elementEnd('li'); $this->elementEnd('li');
} }
} }
@ -363,7 +382,7 @@ class OpenidsettingsAction extends SettingsAction
$orig = clone($prefs); $orig = clone($prefs);
} }
$prefs->hide_profile_link = $this->booleanintstring('hide_profile_link'); $prefs->hide_profile_link = $this->boolean('hide_profile_link');
if ($orig instanceof User_openid_prefs) { if ($orig instanceof User_openid_prefs) {
$prefs->update($orig); $prefs->update($orig);

View File

@ -63,12 +63,12 @@ class User_openid_prefs extends Managed_DataObject
'description' => 'Per-user preferences for OpenID display', 'description' => 'Per-user preferences for OpenID display',
'fields' => [ 'fields' => [
'user_id' => [ 'user_id' => [
'type' => 'integer', 'type' => 'int',
'not null' => true, 'not null' => true,
'description' => 'User whose prefs we are saving' 'description' => 'User whose prefs we are saving'
], ],
'hide_profile_link' => [ 'hide_profile_link' => [
'type' => 'integer', 'type' => 'int',
'not null' => true, 'not null' => true,
'default' => 0, 'default' => 0,
'description' => 'Whether to hide profile links from profile block' 'description' => 'Whether to hide profile links from profile block'

View File

@ -1,25 +1,25 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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/>. /**
* @copyright 2008, 2009 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
require_once('Auth/OpenID.php'); require_once('Auth/OpenID.php');
require_once('Auth/OpenID/Consumer.php'); require_once('Auth/OpenID/Consumer.php');
@ -49,19 +49,19 @@ function oid_store()
} }
$db = DB::connect($dsn, $options); $db = DB::connect($dsn, $options);
if (PEAR::isError($db)) { if ((new PEAR)->isError($db)) {
throw new ServerException($db->getMessage()); throw new ServerException($db->getMessage());
} }
switch (common_config('db', 'type')) { switch (common_config('db', 'type')) {
case 'pgsql':
$store = new Auth_OpenID_PostgreSQLStore($db);
break;
case 'mysql': case 'mysql':
$store = new Auth_OpenID_MySQLStore($db); $store = new Auth_OpenID_MySQLStore($db);
break; break;
case 'postgresql':
$store = new Auth_OpenID_PostgreSQLStore($db);
break;
default: default:
throw new ServerException(_m('Unknown DB type for OpenID.')); throw new ServerException('Unknown DB type selected.');
} }
} }
return $store; return $store;
@ -90,9 +90,11 @@ function oid_clear_last()
function oid_set_last($openid_url) function oid_set_last($openid_url)
{ {
common_set_cookie(OPENID_COOKIE_KEY, common_set_cookie(
OPENID_COOKIE_KEY,
$openid_url, $openid_url,
time() + OPENID_COOKIE_EXPIRY); time() + OPENID_COOKIE_EXPIRY
);
} }
function oid_get_last() function oid_get_last()
@ -119,7 +121,7 @@ function oid_link_user($id, $canonical, $display)
$oid->created = common_sql_now(); $oid->created = common_sql_now();
if (!$oid->insert()) { if (!$oid->insert()) {
$err = &$_PEAR->getStaticProperty('DB_DataObject','lastError'); $err = &$_PEAR->getStaticProperty('DB_DataObject', 'lastError');
return false; return false;
} }
@ -149,9 +151,11 @@ function oid_check_immediate($openid_url, $backto=null)
$_SESSION['openid_immediate_backto'] = $backto; $_SESSION['openid_immediate_backto'] = $backto;
oid_authenticate($openid_url, oid_authenticate(
$openid_url,
'finishimmediate', 'finishimmediate',
true); true
);
} }
function oid_authenticate($openid_url, $returnto, $immediate=false) function oid_authenticate($openid_url, $returnto, $immediate=false)
@ -177,23 +181,27 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
common_log(LOG_ERR, __METHOD__ . ": mystery fail contacting $openid_url"); common_log(LOG_ERR, __METHOD__ . ": mystery fail contacting $openid_url");
// TRANS: OpenID plugin message. Given when an OpenID is not valid. // TRANS: OpenID plugin message. Given when an OpenID is not valid.
throw new ServerException(_m('Not a valid OpenID.')); throw new ServerException(_m('Not a valid OpenID.'));
} else if (Auth_OpenID::isFailure($auth_request)) { } elseif (Auth_OpenID::isFailure($auth_request)) {
common_log(LOG_ERR, __METHOD__ . ": OpenID fail to $openid_url: $auth_request->message"); common_log(LOG_ERR, __METHOD__ . ": OpenID fail to $openid_url: $auth_request->message");
// TRANS: OpenID plugin server error. Given when the OpenID authentication request fails. // TRANS: OpenID plugin server error. Given when the OpenID authentication request fails.
// TRANS: %s is the failure message. // TRANS: %s is the failure message.
throw new ServerException(sprintf(_m('OpenID failure: %s.'), $auth_request->message)); throw new ServerException(sprintf(_m('OpenID failure: %s.'), $auth_request->message));
} }
$sreg_request = Auth_OpenID_SRegRequest::build(// Required $sreg_request = Auth_OpenID_SRegRequest::build(
array(), // Required
[],
// Optional // Optional
array('nickname', [
'nickname',
'email', 'email',
'fullname', 'fullname',
'language', 'language',
'timezone', 'timezone',
'postcode', 'postcode',
'country')); 'country',
]
);
if ($sreg_request) { if ($sreg_request) {
$auth_request->addExtension($sreg_request); $auth_request->addExtension($sreg_request);
@ -224,9 +232,11 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
// autosubmitter for now. // autosubmitter for now.
// //
//if ($auth_request->shouldSendRedirect()) { //if ($auth_request->shouldSendRedirect()) {
$redirect_url = $auth_request->redirectURL($trust_root, $redirect_url = $auth_request->redirectURL(
$trust_root,
$process_url, $process_url,
$immediate); $immediate
);
if (Auth_OpenID::isFailure($redirect_url)) { if (Auth_OpenID::isFailure($redirect_url)) {
// TRANS: OpenID plugin server error. Given when the OpenID authentication request cannot be redirected. // TRANS: OpenID plugin server error. Given when the OpenID authentication request cannot be redirected.
// TRANS: %s is the failure message. // TRANS: %s is the failure message.
@ -266,11 +276,14 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
function _oid_print_instructions() function _oid_print_instructions()
{ {
common_element('div', 'instructions', common_element(
'div',
'instructions',
// TRANS: OpenID plugin user instructions. // TRANS: OpenID plugin user instructions.
_m('This form should automatically submit itself. '. _m('This form should automatically submit itself. '.
'If not, click the submit button to go to your '. 'If not, click the submit button to go to your '.
'OpenID provider.')); 'OpenID provider.')
);
} }
/** /**
@ -382,22 +395,22 @@ function oid_check_teams($response)
class AutosubmitAction extends Action class AutosubmitAction extends Action
{ {
var $form_html = null; public $form_html = null;
var $form_id = null; public $form_id = null;
function handle() public function handle()
{ {
parent::handle(); parent::handle();
$this->showPage(); $this->showPage();
} }
function title() public function title()
{ {
// TRANS: Title // TRANS: Title
return _m('OpenID Login Submission'); return _m('OpenID Login Submission');
} }
function showContent() public function showContent()
{ {
$this->raw('<p style="margin: 20px 80px">'); $this->raw('<p style="margin: 20px 80px">');
// @todo FIXME: This would be better using standard CSS class, but the present theme's a bit scary. // @todo FIXME: This would be better using standard CSS class, but the present theme's a bit scary.
@ -414,10 +427,13 @@ class AutosubmitAction extends Action
$this->raw($this->form_html); $this->raw($this->form_html);
} }
function showScripts() public function showScripts()
{ {
parent::showScripts(); parent::showScripts();
$this->element('script', null, $this->element(
'document.getElementById(\'' . $this->form_id . '\').submit();'); 'script',
null,
'document.getElementById(\'' . $this->form_id . '\').submit();'
);
} }
} }

View File

@ -1,44 +1,36 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* Data class to mark notices as bookmarks * Data class to mark notices as bookmarks
* *
* PHP version 5
*
* @category PollPlugin * @category PollPlugin
* @package StatusNet * @package GNUsocial
* @author Brion Vibber <brion@status.net> * @author Brion Vibber <brion@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2011 StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* For storing the poll options and such * For storing the poll options and such
* *
* @category PollPlugin * @copyright 2011 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Brion Vibber <brion@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -136,7 +128,9 @@ class Poll extends Managed_DataObject
$pr = new Poll_response(); $pr = new Poll_response();
$pr->poll_id = $this->id; $pr->poll_id = $this->id;
$pr->groupBy('selection'); $pr->groupBy('selection');
$pr->selectAdd('count(profile_id) as votes'); $pr->selectAdd();
$pr->selectAdd('selection');
$pr->selectAdd('COUNT(profile_id) AS votes');
$pr->find(); $pr->find();
$raw = array(); $raw = array();

View File

@ -1,44 +1,36 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* Data class to record responses to polls * Data class to record responses to polls
* *
* PHP version 5
*
* @category PollPlugin * @category PollPlugin
* @package StatusNet * @package GNUsocial
* @author Brion Vibber <brion@status.net> * @author Brion Vibber <brion@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2011, StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* For storing the poll options and such * For storing the poll options and such
* *
* @category PollPlugin * @copyright 2011, StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Brion Vibber <brion@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -69,7 +61,7 @@ class Poll_response extends Managed_DataObject
), ),
'primary key' => array('id'), 'primary key' => array('id'),
'unique keys' => array( 'unique keys' => array(
'poll_uri_key' => array('uri'), 'poll_response_uri_key' => array('uri'),
'poll_response_poll_id_profile_id_key' => array('poll_id', 'profile_id'), 'poll_response_poll_id_profile_id_key' => array('poll_id', 'profile_id'),
), ),
'indexes' => array( 'indexes' => array(

View File

@ -1,44 +1,37 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* Data class to record user prefs for polls * Data class to record user prefs for polls
* *
* PHP version 5
*
* @category PollPlugin * @category PollPlugin
* @package StatusNet * @package GNUsocial
* @author Brion Vibber <brion@status.net>
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2012, StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2012, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* For storing the poll prefs * For storing the poll prefs
* *
* @category PollPlugin * @copyright 2012, StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Brion Vibber <brion@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -46,7 +39,7 @@ class User_poll_prefs extends Managed_DataObject
{ {
public $__table = 'user_poll_prefs'; // table name public $__table = 'user_poll_prefs'; // table name
public $user_id; // int id public $user_id; // int id
public $hide_responses; // boolean public $hide_responses; // bool
public $created; // datetime public $created; // datetime
public $modified; // datetime public $modified; // datetime
@ -59,7 +52,7 @@ class User_poll_prefs extends Managed_DataObject
'description' => 'Record of user preferences for polls', 'description' => 'Record of user preferences for polls',
'fields' => array( 'fields' => array(
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'), 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
'hide_responses' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'Hide all poll responses'), 'hide_responses' => array('type' => 'bool', 'default' => false, 'description' => 'Hide all poll responses'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'), 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
), ),

View File

@ -1,47 +1,36 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Close a question to further answers * Close a question to further answers
* *
* 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 QnA * @category QnA
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2011 StatusNet, Inc. * @copyright 2011 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or late
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) {
// This check helps protect against security problems; defined('GNUSOCIAL') || die();
// your code file can't be executed directly from the web.
exit(1);
}
/** /**
* Close a question to new answers * Close a question to new answers
* *
* @category QnA
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2010 StatusNet, Inc. * @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or late
* @link http://status.net/
*/ */
class QnaclosequestionAction extends Action class QnaclosequestionAction extends Action
{ {
@ -57,7 +46,7 @@ class QnaclosequestionAction extends Action
* *
* @return string Action title * @return string Action title
*/ */
function title() public function title()
{ {
// TRANS: Page title for close a question // TRANS: Page title for close a question
return _m('Close question'); return _m('Close question');
@ -71,7 +60,7 @@ class QnaclosequestionAction extends Action
* @return boolean true * @return boolean true
* @throws ClientException * @throws ClientException
*/ */
function prepare(array $args = []) public function prepare(array $args = [])
{ {
parent::prepare($args); parent::prepare($args);
if ($this->boolean('ajax')) { if ($this->boolean('ajax')) {
@ -107,7 +96,7 @@ class QnaclosequestionAction extends Action
* *
* @return void * @return void
*/ */
function handle() public function handle()
{ {
parent::handle(); parent::handle();
@ -125,7 +114,7 @@ class QnaclosequestionAction extends Action
* *
* @return void * @return void
*/ */
function closeQuestion() public function closeQuestion()
{ {
$user = common_current_user(); $user = common_current_user();
@ -136,9 +125,8 @@ class QnaclosequestionAction extends Action
} }
$orig = clone($this->question); $orig = clone($this->question);
$this->question->closed = 1; $this->question->closed = true;
$this->question->update($orig); $this->question->update($orig);
} catch (ClientException $ce) { } catch (ClientException $ce) {
$this->error = $ce->getMessage(); $this->error = $ce->getMessage();
$this->showPage(); $this->showPage();
@ -166,7 +154,7 @@ class QnaclosequestionAction extends Action
* *
* @return void * @return void
*/ */
function showContent() public function showContent()
{ {
if (!empty($this->error)) { if (!empty($this->error)) {
$this->element('p', 'error', $this->error); $this->element('p', 'error', $this->error);
@ -184,7 +172,7 @@ class QnaclosequestionAction extends Action
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) public function isReadOnly($args)
{ {
if ($_SERVER['REQUEST_METHOD'] == 'GET' || if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') { $_SERVER['REQUEST_METHOD'] == 'HEAD') {

View File

@ -1,47 +1,36 @@
<?php <?php
/** // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2011, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* Revise an answer // the Free Software Foundation, either version 3 of the License, or
* // (at your option) any later version.
* PHP version 5 //
* // GNU social is distributed in the hope that it will be useful,
* This program is free software: you can redistribute it and/or modify // but WITHOUT ANY WARRANTY; without even the implied warranty of
* it under the terms of the GNU Affero General Public License as published by // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* the Free Software Foundation, either version 3 of the License, or // GNU Affero General Public License for more details.
* (at your option) any later version. //
* // You should have received a copy of the GNU Affero General Public License
* This program is distributed in the hope that it will be useful, // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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 QnA
* @package StatusNet
* @author Zach Copley <zach@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);
}
/** /**
* Revise an answer * Revise an answer
* *
* @category QnA * @category QnA
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2011 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
defined('GNUSOCIAL') || die();
/**
* Revise an answer
*
* @copyright 2010 StatusNet, Inc. * @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class QnareviseanswerAction extends Action class QnareviseanswerAction extends Action
{ {
@ -56,7 +45,7 @@ class QnareviseanswerAction extends Action
* *
* @return string Action title * @return string Action title
*/ */
function title() public function title()
{ {
// TRANS: Page title for revising a question // TRANS: Page title for revising a question
return _m('Revise answer'); return _m('Revise answer');
@ -70,7 +59,7 @@ class QnareviseanswerAction extends Action
* @return boolean true * @return boolean true
* @throws ClientException * @throws ClientException
*/ */
function prepare(array $args = []) public function prepare(array $args = [])
{ {
parent::prepare($args); parent::prepare($args);
if ($this->boolean('ajax')) { if ($this->boolean('ajax')) {
@ -110,7 +99,7 @@ class QnareviseanswerAction extends Action
* *
* @return void * @return void
*/ */
function handle() public function handle()
{ {
parent::handle(); parent::handle();
@ -119,7 +108,7 @@ class QnareviseanswerAction extends Action
if ($this->arg('revise')) { if ($this->arg('revise')) {
$this->showContent(); $this->showContent();
return; return;
} else if ($this->arg('best')) { } elseif ($this->arg('best')) {
if ($this->user->id == $this->question->profile_id) { if ($this->user->id == $this->question->profile_id) {
$this->markBest(); $this->markBest();
return; return;
@ -138,7 +127,7 @@ class QnareviseanswerAction extends Action
* *
* @return void * @return void
*/ */
function showContent() public function showContent()
{ {
if (!empty($this->error)) { if (!empty($this->error)) {
$this->element('p', 'error', $this->error); $this->element('p', 'error', $this->error);
@ -154,7 +143,7 @@ class QnareviseanswerAction extends Action
return; return;
} }
function showAjaxReviseForm() public function showAjaxReviseForm()
{ {
$this->startHTML('text/xml;charset=utf-8'); $this->startHTML('text/xml;charset=utf-8');
$this->elementStart('head'); $this->elementStart('head');
@ -173,7 +162,7 @@ class QnareviseanswerAction extends Action
* *
* @return void * @return void
*/ */
function markBest() public function markBest()
{ {
$question = $this->question; $question = $this->question;
$answer = $this->answer; $answer = $this->answer;
@ -181,12 +170,12 @@ class QnareviseanswerAction extends Action
try { try {
// close the question to further answers // close the question to further answers
$orig = clone($question); $orig = clone($question);
$question->closed = 1; $question->closed = true;
$result = $question->update($orig); $result = $question->update($orig);
// mark this answer an the best answer // mark this answer an the best answer
$orig = clone($answer); $orig = clone($answer);
$answer->best = 1; $answer->best = true;
$result = $answer->update($orig); $result = $answer->update($orig);
} catch (ClientException $ce) { } catch (ClientException $ce) {
$this->error = $ce->getMessage(); $this->error = $ce->getMessage();
@ -215,7 +204,7 @@ class QnareviseanswerAction extends Action
* *
* @return void * @return void
*/ */
function reviseAnswer() public function reviseAnswer()
{ {
$answer = $this->answer; $answer = $this->answer;
@ -255,7 +244,7 @@ class QnareviseanswerAction extends Action
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) public function isReadOnly($args)
{ {
if ($_SERVER['REQUEST_METHOD'] == 'GET' || if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') { $_SERVER['REQUEST_METHOD'] == 'HEAD') {

View File

@ -1,44 +1,36 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* Data class to save answers to questions * Data class to save answers to questions
* *
* PHP version 5
*
* @category QnA * @category QnA
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2011 StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('STATUSNET')) { defined('STATUSNET') || die();
exit(1);
}
/** /**
* For storing answers * For storing answers
* *
* @category QnA * @copyright 2011 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -51,7 +43,7 @@ class QnA_Answer extends Managed_DataObject
public $uri; // varchar(191) not 255 because utf8mb4 takes more space public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $question_id; // char(36) -> question.id UUID public $question_id; // char(36) -> question.id UUID
public $profile_id; // int -> question.id public $profile_id; // int -> question.id
public $best; // (boolean) int -> whether the question asker has marked this as the best answer public $best; // bool -> whether the question asker has marked this as the best answer
public $revisions; // int -> count of revisions to this answer public $revisions; // int -> count of revisions to this answer
public $content; // text -> response text public $content; // text -> response text
public $created; // datetime public $created; // datetime
@ -82,18 +74,18 @@ class QnA_Answer extends Managed_DataObject
'description' => 'UUID of question being responded to', 'description' => 'UUID of question being responded to',
), ),
'content' => array('type' => 'text'), // got a better name? 'content' => array('type' => 'text'), // got a better name?
'best' => array('type' => 'int', 'size' => 'tiny'), 'best' => array('type' => 'bool'),
'revisions' => array('type' => 'int'), 'revisions' => array('type' => 'int'),
'profile_id' => array('type' => 'int'), 'profile_id' => array('type' => 'int'),
'created' => array('type' => 'datetime', 'not null' => true), 'created' => array('type' => 'datetime', 'not null' => true),
), ),
'primary key' => array('id'), 'primary key' => array('id'),
'unique keys' => array( 'unique keys' => array(
'question_uri_key' => array('uri'), 'qna_answer_uri_key' => array('uri'),
'question_id_profile_id_key' => array('question_id', 'profile_id'), 'qna_answer_question_id_profile_id_key' => array('question_id', 'profile_id'),
), ),
'indexes' => array( 'indexes' => array(
'profile_id_question_id_index' => array('profile_id', 'question_id'), 'qna_answer_profile_id_question_id_idx' => array('profile_id', 'question_id'),
) )
); );
} }
@ -105,7 +97,7 @@ class QnA_Answer extends Managed_DataObject
* *
* @return QnA_Answer found response or null * @return QnA_Answer found response or null
*/ */
static function getByNotice($notice) public static function getByNotice($notice)
{ {
$answer = self::getKV('uri', $notice->uri); $answer = self::getKV('uri', $notice->uri);
if (empty($answer)) { if (empty($answer)) {
@ -119,17 +111,17 @@ class QnA_Answer extends Managed_DataObject
* *
* @return Notice * @return Notice
*/ */
function getNotice() public function getNotice()
{ {
return Notice::getKV('uri', $this->uri); return Notice::getKV('uri', $this->uri);
} }
static function fromNotice($notice) public static function fromNotice($notice)
{ {
return QnA_Answer::getKV('uri', $notice->uri); return QnA_Answer::getKV('uri', $notice->uri);
} }
function getUrl() public function getUrl()
{ {
return $this->getNotice()->getUrl(); return $this->getNotice()->getUrl();
} }
@ -139,29 +131,29 @@ class QnA_Answer extends Managed_DataObject
* *
* @return QnA_Question * @return QnA_Question
*/ */
function getQuestion() public function getQuestion()
{ {
$question = QnA_Question::getKV('id', $this->question_id); $question = QnA_Question::getKV('id', $this->question_id);
if (empty($question)) { if (empty($question)) {
// TRANS: Exception thown when getting a question with a non-existing ID. // TRANS: Exception thown when getting a question with a non-existing ID.
// TRANS: %s is the non-existing question ID. // TRANS: %s is the non-existing question ID.
throw new Exception(sprintf(_m('No question with ID %s'),$this->question_id)); throw new Exception(sprintf(_m('No question with ID %s'), $this->question_id));
} }
return $question; return $question;
} }
function getProfile() public function getProfile()
{ {
$profile = Profile::getKV('id', $this->profile_id); $profile = Profile::getKV('id', $this->profile_id);
if (empty($profile)) { if (empty($profile)) {
// TRANS: Exception thown when getting a profile with a non-existing ID. // TRANS: Exception thown when getting a profile with a non-existing ID.
// TRANS: %s is the non-existing profile ID. // TRANS: %s is the non-existing profile ID.
throw new Exception(sprintf(_m('No profile with ID %s'),$this->profile_id)); throw new Exception(sprintf(_m('No profile with ID %s'), $this->profile_id));
} }
return $profile; return $profile;
} }
function asHTML() public function asHTML()
{ {
return self::toHTML( return self::toHTML(
$this->getProfile(), $this->getProfile(),
@ -170,7 +162,7 @@ class QnA_Answer extends Managed_DataObject
); );
} }
function asString() public function asString()
{ {
return self::toString( return self::toString(
$this->getProfile(), $this->getProfile(),
@ -179,7 +171,7 @@ class QnA_Answer extends Managed_DataObject
); );
} }
static function toHTML($profile, $question, $answer) public static function toHTML($profile, $question, $answer)
{ {
$notice = $question->getNotice(); $notice = $question->getNotice();
@ -201,7 +193,7 @@ class QnA_Answer extends Managed_DataObject
htmlspecialchars( htmlspecialchars(
// Notification of how often an answer was revised. // Notification of how often an answer was revised.
// TRANS: %s is the number of answer revisions. // TRANS: %s is the number of answer revisions.
sprintf(_m('%s revision','%s revisions',$answer->revisions), $answer->revisions) sprintf(_m('%s revision', '%s revisions', $answer->revisions), $answer->revisions)
) )
); );
$out->elementEnd('span'); $out->elementEnd('span');
@ -212,7 +204,7 @@ class QnA_Answer extends Managed_DataObject
return $out->getString(); return $out->getString();
} }
static function toString($profile, $question, $answer) public static function toString($profile, $question, $answer)
{ {
// @todo FIXME: unused variable? // @todo FIXME: unused variable?
$notice = $question->getNotice(); $notice = $question->getNotice();
@ -237,7 +229,7 @@ class QnA_Answer extends Managed_DataObject
* *
* @return Notice saved notice * @return Notice saved notice
*/ */
static function saveNew($profile, $question, $text, $options = null) public static function saveNew($profile, $question, $text, $options = null)
{ {
if (empty($options)) { if (empty($options)) {
$options = array(); $options = array();
@ -248,7 +240,7 @@ class QnA_Answer extends Managed_DataObject
$answer->profile_id = $profile->id; $answer->profile_id = $profile->id;
$answer->question_id = $question->id; $answer->question_id = $question->id;
$answer->revisions = 0; $answer->revisions = 0;
$answer->best = 0; $answer->best = false;
$answer->content = $text; $answer->content = $text;
$answer->created = common_sql_now(); $answer->created = common_sql_now();
$answer->uri = common_local_url( $answer->uri = common_local_url(

View File

@ -1,44 +1,36 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* Data class to mark a notice as a question * Data class to mark a notice as a question
* *
* PHP version 5
*
* @category QnA * @category QnA
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2011 StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* For storing a question * For storing a question
* *
* @category QnA * @copyright 2011 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -52,7 +44,7 @@ class QnA_Question extends Managed_DataObject
public $profile_id; // int -> profile.id public $profile_id; // int -> profile.id
public $title; // text public $title; // text
public $description; // text public $description; // text
public $closed; // int (boolean) whether a question is closed public $closed; // bool -> whether a question is closed
public $created; // datetime public $created; // datetime
/** /**
@ -76,7 +68,7 @@ class QnA_Question extends Managed_DataObject
), ),
'profile_id' => array('type' => 'int'), 'profile_id' => array('type' => 'int'),
'title' => array('type' => 'text'), 'title' => array('type' => 'text'),
'closed' => array('type' => 'int', 'size' => 'tiny'), 'closed' => array('type' => 'bool'),
'description' => array('type' => 'text'), 'description' => array('type' => 'text'),
'created' => array( 'created' => array(
'type' => 'datetime', 'type' => 'datetime',
@ -85,7 +77,7 @@ class QnA_Question extends Managed_DataObject
), ),
'primary key' => array('id'), 'primary key' => array('id'),
'unique keys' => array( 'unique keys' => array(
'question_uri_key' => array('uri'), 'qna_question_uri_key' => array('uri'),
), ),
); );
} }
@ -97,28 +89,28 @@ class QnA_Question extends Managed_DataObject
* *
* @return Question found question or null * @return Question found question or null
*/ */
static function getByNotice($notice) public static function getByNotice($notice)
{ {
return self::getKV('uri', $notice->uri); return self::getKV('uri', $notice->uri);
} }
function getNotice() public function getNotice()
{ {
return Notice::getKV('uri', $this->uri); return Notice::getKV('uri', $this->uri);
} }
function getUrl() public function getUrl()
{ {
return $this->getNotice()->getUrl(); return $this->getNotice()->getUrl();
} }
function getProfile() public function getProfile()
{ {
$profile = Profile::getKV('id', $this->profile_id); $profile = Profile::getKV('id', $this->profile_id);
if (empty($profile)) { if (empty($profile)) {
// TRANS: Exception trown when getting a profile for a non-existing ID. // TRANS: Exception trown when getting a profile for a non-existing ID.
// TRANS: %s is the provided profile ID. // TRANS: %s is the provided profile ID.
throw new Exception(sprintf(_m('No profile with ID %s'),$this->profile_id)); throw new Exception(sprintf(_m('No profile with ID %s'), $this->profile_id));
} }
return $profile; return $profile;
} }
@ -130,7 +122,7 @@ class QnA_Question extends Managed_DataObject
* *
* @return Answer object or null * @return Answer object or null
*/ */
function getAnswer(Profile $profile) public function getAnswer(Profile $profile)
{ {
$a = new QnA_Answer(); $a = new QnA_Answer();
$a->question_id = $this->id; $a->question_id = $this->id;
@ -143,7 +135,7 @@ class QnA_Question extends Managed_DataObject
} }
} }
function getAnswers() public function getAnswers()
{ {
$a = new QnA_Answer(); $a = new QnA_Answer();
$a->question_id = $this->id; $a->question_id = $this->id;
@ -155,7 +147,7 @@ class QnA_Question extends Managed_DataObject
} }
} }
function countAnswers() public function countAnswers()
{ {
$a = new QnA_Answer(); $a = new QnA_Answer();
@ -164,22 +156,22 @@ class QnA_Question extends Managed_DataObject
return $a->count(); return $a->count();
} }
static function fromNotice($notice) public static function fromNotice($notice)
{ {
return QnA_Question::getKV('uri', $notice->uri); return QnA_Question::getKV('uri', $notice->uri);
} }
function asHTML() public function asHTML()
{ {
return self::toHTML($this->getProfile(), $this); return self::toHTML($this->getProfile(), $this);
} }
function asString() public function asString()
{ {
return self::toString($this->getProfile(), $this); return self::toString($this->getProfile(), $this);
} }
static function toHTML($profile, $question) public static function toHTML($profile, $question)
{ {
$notice = $question->getNotice(); $notice = $question->getNotice();
@ -205,7 +197,7 @@ class QnA_Question extends Managed_DataObject
$out->elementStart('span', 'answer-count'); $out->elementStart('span', 'answer-count');
// TRANS: Number of given answers to a question. // TRANS: Number of given answers to a question.
// TRANS: %s is the number of given answers. // TRANS: %s is the number of given answers.
$out->text(sprintf(_m('%s answer','%s answers',$cnt), $cnt)); $out->text(sprintf(_m('%s answer', '%s answers', $cnt), $cnt));
$out->elementEnd('span'); $out->elementEnd('span');
} }
@ -221,7 +213,7 @@ class QnA_Question extends Managed_DataObject
return $out->getString(); return $out->getString();
} }
static function toString($profile, $question, $answers) public static function toString($profile, $question, $answers)
{ {
return sprintf(htmlspecialchars($question->description)); return sprintf(htmlspecialchars($question->description));
} }
@ -237,7 +229,7 @@ class QnA_Question extends Managed_DataObject
* *
* @return Notice saved notice * @return Notice saved notice
*/ */
static function saveNew($profile, $title, $description, $options = array()) public static function saveNew($profile, $title, $description, $options = [])
{ {
$q = new QnA_Question(); $q = new QnA_Question();

View File

@ -1,44 +1,36 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* Data class to save users votes for * Data class to save users votes for
* *
* PHP version 5
*
* @category QnA * @category QnA
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2011 StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
/** /**
* For storing votes on question and answers * For storing votes on question and answers
* *
* @category QnA * @copyright 2011 StatusNet, Inc.
* @package StatusNet * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -87,11 +79,11 @@ class QnA_Vote extends Managed_DataObject
), ),
'primary key' => array('id'), 'primary key' => array('id'),
'indexes' => array( 'indexes' => array(
'profile_id_question_Id_index' => array( 'qna_vote_profile_id_question_id_idx' => array(
'profile_id', 'profile_id',
'question_id' 'question_id'
), ),
'profile_id_question_Id_index' => array( 'qna_vote_profile_id_question_id_idx' => array(
'profile_id', 'profile_id',
'answer_id' 'answer_id'
) )
@ -110,7 +102,7 @@ class QnA_Vote extends Managed_DataObject
* *
* @return Void * @return Void
*/ */
static function save($profile, $question, $answer, $vote) public static function save($profile, $question, $answer, $vote)
{ {
$v = new QnA_Vote(); $v = new QnA_Vote();
$v->id = UUID::gen(); $v->id = UUID::gen();

View File

@ -1,36 +1,18 @@
<?php <?php
/** // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2011, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* A channel for real-time browser data // the Free Software Foundation, either version 3 of the License, or
* // (at your option) any later version.
* PHP version 5 //
* // GNU social is distributed in the hope that it will be useful,
* This program is free software: you can redistribute it and/or modify // but WITHOUT ANY WARRANTY; without even the implied warranty of
* it under the terms of the GNU Affero General Public License as published by // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* the Free Software Foundation, either version 3 of the License, or // GNU Affero General Public License for more details.
* (at your option) any later version. //
* // You should have received a copy of the GNU Affero General Public License
* This program is distributed in the hope that it will be useful, // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* 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 Realtime
* @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')) {
exit(1);
}
/** /**
* A channel for real-time browser data * A channel for real-time browser data
@ -39,10 +21,19 @@ if (!defined('STATUSNET')) {
* so we can send real-time updates to their browser. * so we can send real-time updates to their browser.
* *
* @category Realtime * @category Realtime
* @package StatusNet * @package GNUsocial
* @author Evan Prodromou <evan@status.net> * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @copyright 2011 StatusNet, Inc.
* @link http://status.net/ * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/
defined('GNUSOCIAL') || die();
/**
* A channel for real-time browser data
*
* @copyright 2011 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* *
* @see DB_DataObject * @see DB_DataObject
*/ */
@ -88,7 +79,7 @@ class Realtime_channel extends Managed_DataObject
'length' => 32, 'length' => 32,
'not null' => true, 'not null' => true,
'description' => 'shared secret key for this channel'), 'description' => 'shared secret key for this channel'),
'audience' => array('type' => 'integer', 'audience' => array('type' => 'int',
'not null' => true, 'not null' => true,
'default' => 0, 'default' => 0,
'description' => 'reference count'), 'description' => 'reference count'),
@ -111,7 +102,7 @@ class Realtime_channel extends Managed_DataObject
); );
} }
static function saveNew($user_id, $action, $arg1, $arg2) public static function saveNew($user_id, $action, $arg1, $arg2)
{ {
$channel = new Realtime_channel(); $channel = new Realtime_channel();
@ -131,7 +122,7 @@ class Realtime_channel extends Managed_DataObject
return $channel; return $channel;
} }
static function getChannel($user_id, $action, $arg1, $arg2) public static function getChannel($user_id, $action, $arg1, $arg2)
{ {
$channel = self::fetchChannel($user_id, $action, $arg1, $arg2); $channel = self::fetchChannel($user_id, $action, $arg1, $arg2);
@ -152,7 +143,7 @@ class Realtime_channel extends Managed_DataObject
return $channel; return $channel;
} }
static function getAllChannels($action, $arg1, $arg2) public static function getAllChannels($action, $arg1, $arg2)
{ {
$channel = new Realtime_channel(); $channel = new Realtime_channel();
@ -170,9 +161,9 @@ class Realtime_channel extends Managed_DataObject
$channel->arg2 = $arg2; $channel->arg2 = $arg2;
} }
$channel->whereAdd('modified > "' . common_sql_date(time() - self::TIMEOUT) . '"'); $channel->whereAdd(sprintf("modified > TIMESTAMP '%s'", common_sql_date(time() - self::TIMEOUT)));
$channels = array(); $channels = [];
if ($channel->find()) { if ($channel->find()) {
$channels = $channel->fetchAll(); $channels = $channel->fetchAll();
@ -181,7 +172,7 @@ class Realtime_channel extends Managed_DataObject
return $channels; return $channels;
} }
static function fetchChannel($user_id, $action, $arg1, $arg2) public static function fetchChannel($user_id, $action, $arg1, $arg2)
{ {
$channel = new Realtime_channel(); $channel = new Realtime_channel();
@ -213,7 +204,7 @@ class Realtime_channel extends Managed_DataObject
} }
} }
function increment() public function increment()
{ {
// XXX: race // XXX: race
$orig = clone($this); $orig = clone($this);
@ -222,7 +213,7 @@ class Realtime_channel extends Managed_DataObject
$this->update($orig); $this->update($orig);
} }
function touch() public function touch()
{ {
// XXX: race // XXX: race
$orig = clone($this); $orig = clone($this);
@ -230,7 +221,7 @@ class Realtime_channel extends Managed_DataObject
$this->update($orig); $this->update($orig);
} }
function decrement() public function decrement()
{ {
// XXX: race // XXX: race
if ($this->audience == 1) { if ($this->audience == 1) {

View File

@ -1,23 +1,27 @@
#!/usr/bin/env php #!/usr/bin/env php
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social 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.
//
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
/* /*
* StatusNet - a distributed open-source microblogging tool
* Copyright (C) 2011, StatusNet, Inc.
*
* Script to print out current version of the software * Script to print out current version of the software
* *
* This program is free software: you can redistribute it and/or modify * @package Realtime
* it under the terms of the GNU Affero General Public License as published by * @author Mikael Nordfeldth <mmn@hethane.se>
* the Free Software Foundation, either version 3 of the License, or * @copyright 2011, StatusNet, Inc.
* (at your option) any later version. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
* 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/>.
*/ */
define('INSTALLDIR', realpath(__DIR__ . '/../../..')); define('INSTALLDIR', realpath(__DIR__ . '/../../..'));
@ -42,7 +46,7 @@ function cleanupChannels()
$rc->selectAdd(); $rc->selectAdd();
$rc->selectAdd('channel_key'); $rc->selectAdd('channel_key');
$rc->whereAdd('modified < "' . common_sql_date(time() - Realtime_channel::TIMEOUT) . '"'); $rc->whereAdd(sprintf("modified < TIMESTAMP '%s'", common_sql_date(time() - Realtime_channel::TIMEOUT)));
if ($rc->find()) { if ($rc->find()) {
$keys = $rc->fetchAll(); $keys = $rc->fetchAll();

Some files were not shown because too many files have changed in this diff Show More