Merge branch '0.9.x' into testing
This commit is contained in:
commit
2a1468ec8b
29
README
29
README
|
@ -358,7 +358,7 @@ It's possible to configure the software so it looks like this instead:
|
|||
|
||||
These "fancy URLs" are more readable and memorable for users. To use
|
||||
fancy URLs, you must either have Apache 2.x with .htaccess enabled and
|
||||
mod_redirect enabled, -OR- know how to configure "url redirection" in
|
||||
mod_rewrite enabled, -OR- know how to configure "url redirection" in
|
||||
your server.
|
||||
|
||||
1. Copy the htaccess.sample file to .htaccess in your StatusNet
|
||||
|
@ -384,6 +384,18 @@ like:
|
|||
If you changed your HTTP server configuration, you may need to restart
|
||||
the server first.
|
||||
|
||||
If it doesn't work, double-check that AllowOverride for the StatusNet
|
||||
directory is 'All' in your Apache configuration file. This is usually
|
||||
/etc/httpd.conf, /etc/apache/httpd.conf, or (on Debian and Ubuntu)
|
||||
/etc/apache2/sites-available/default. See the Apache documentation for
|
||||
.htaccess files for more details:
|
||||
|
||||
http://httpd.apache.org/docs/2.2/howto/htaccess.html
|
||||
|
||||
Also, check that mod_rewrite is installed and enabled:
|
||||
|
||||
http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html
|
||||
|
||||
Sphinx
|
||||
------
|
||||
|
||||
|
@ -1407,6 +1419,21 @@ contentlimit: max length of the plain-text content of a message.
|
|||
Default is null, meaning to use the site-wide text limit.
|
||||
0 means no limit.
|
||||
|
||||
logincommand
|
||||
------------
|
||||
|
||||
Configuration options for the login command.
|
||||
|
||||
disabled: whether to enable this command. If enabled, users who send
|
||||
the text 'login' to the site through any channel will
|
||||
receive a link to login to the site automatically in return.
|
||||
Possibly useful for users who primarily use an XMPP or SMS
|
||||
interface and can't be bothered to remember their site
|
||||
password. Note that the security implications of this are
|
||||
pretty serious and have not been thoroughly tested. You
|
||||
should enable it only after you've convinced yourself that
|
||||
it is safe. Default is 'false'.
|
||||
|
||||
Plugins
|
||||
=======
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
|
|||
return;
|
||||
}
|
||||
|
||||
mail_notify_message($message, $this->user, $this->other);
|
||||
$message->notify();
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlDirectMessage($message);
|
||||
|
|
136
actions/apistatusesretweet.php
Normal file
136
actions/apistatusesretweet.php
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Repeat a notice through the API
|
||||
*
|
||||
* 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
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apiauth.php';
|
||||
require_once INSTALLDIR . '/lib/mediafile.php';
|
||||
|
||||
/**
|
||||
* Repeat a notice through the API
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiStatusesRetweetAction extends ApiAuthAction
|
||||
{
|
||||
var $original = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
|
||||
$this->clientError(_('This method requires a POST.'),
|
||||
400, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->trimmed('id');
|
||||
|
||||
$this->original = Notice::staticGet('id', $id);
|
||||
|
||||
if (empty($this->original)) {
|
||||
$this->clientError(_('No such notice.'),
|
||||
400, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
if ($this->user->id == $notice->profile_id) {
|
||||
$this->clientError(_('Cannot repeat your own notice.'),
|
||||
400, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if ($profile->hasRepeated($id)) {
|
||||
$this->clientError(_('Already repeated that notice.'),
|
||||
400, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$repeat = $this->original->repeat($this->user->id, $this->source);
|
||||
|
||||
common_broadcast_notice($repeat);
|
||||
|
||||
$this->showNotice($repeat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the resulting notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showNotice($notice)
|
||||
{
|
||||
if (!empty($notice)) {
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlStatus($notice);
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->show_single_json_status($notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
116
actions/apistatusesretweets.php
Normal file
116
actions/apistatusesretweets.php
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show up to 100 repeats of a notice
|
||||
*
|
||||
* 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
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apiauth.php';
|
||||
require_once INSTALLDIR . '/lib/mediafile.php';
|
||||
|
||||
/**
|
||||
* Show up to 100 repeats of a notice
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiStatusesRetweetsAction extends ApiAuthAction
|
||||
{
|
||||
const MAXCOUNT = 100;
|
||||
|
||||
var $original = null;
|
||||
var $cnt = self::MAXCOUNT;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->trimmed('id');
|
||||
|
||||
$this->original = Notice::staticGet('id', $id);
|
||||
|
||||
if (empty($this->original)) {
|
||||
$this->clientError(_('No such notice.'),
|
||||
400, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cnt = $this->trimmed('count');
|
||||
|
||||
if (empty($cnt) || !is_integer($cnt)) {
|
||||
$cnt = 100;
|
||||
} else {
|
||||
$this->cnt = min((int)$cnt, self::MAXCOUNT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$strm = $this->original->repeatStream($this->cnt);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($strm);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -231,19 +231,22 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||
}
|
||||
}
|
||||
|
||||
$this->notice = Notice::saveNew(
|
||||
$this->user->id,
|
||||
html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8'),
|
||||
$this->source,
|
||||
1,
|
||||
$reply_to,
|
||||
null,
|
||||
null,
|
||||
empty($location) ? null : $location->lat,
|
||||
empty($location) ? null : $location->lon,
|
||||
empty($location) ? null : $location->location_id,
|
||||
empty($location) ? null : $location->location_ns
|
||||
);
|
||||
$content = html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$options = array('reply_to' => $reply_to);
|
||||
|
||||
if (!empty($location)) {
|
||||
$options['lat'] = $location->lat;
|
||||
$options['lon'] = $location->lon;
|
||||
$options['location_id'] = $location->location_id;
|
||||
$options['location_ns'] = $location->location_ns;
|
||||
}
|
||||
|
||||
$this->notice =
|
||||
Notice::saveNew($this->user->id,
|
||||
$content,
|
||||
$this->source,
|
||||
$options);
|
||||
|
||||
if (isset($upload)) {
|
||||
$upload->attachToNotice($this->notice);
|
||||
|
|
|
@ -101,6 +101,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
|
|||
function showTimeline()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(
|
||||
|
@ -121,20 +122,21 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
|
|||
$profile->getBestName(),
|
||||
$this->user->nickname
|
||||
);
|
||||
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() .
|
||||
ltrim($_SERVER['QUERY_STRING'], 'p=');
|
||||
$this->showAtomTimeline(
|
||||
$this->notices, $title, $id, $link, $subtitle,
|
||||
null, $selfuri
|
||||
null, $selfuri, $logo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
|
|
|
@ -110,24 +110,26 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
|||
function showTimeline()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(_("%s and friends"), $this->user->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:FriendsTimeline:" . $this->user->id;
|
||||
$link = common_local_url(
|
||||
'all', array('nickname' => $this->user->nickname)
|
||||
);
|
||||
'all', array('nickname' => $this->user->nickname)
|
||||
);
|
||||
$subtitle = sprintf(
|
||||
_('Updates from %1$s and friends on %2$s!'),
|
||||
$this->user->nickname, $sitename
|
||||
);
|
||||
_('Updates from %1$s and friends on %2$s!'),
|
||||
$this->user->nickname, $sitename
|
||||
);
|
||||
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
|
@ -135,17 +137,17 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
|||
|
||||
if (isset($target_id)) {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/friends_timeline/' .
|
||||
$target_id . '.atom';
|
||||
'api/statuses/friends_timeline/' .
|
||||
$target_id . '.atom';
|
||||
} else {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/friends_timeline.atom';
|
||||
'api/statuses/friends_timeline.atom';
|
||||
}
|
||||
|
||||
$this->showAtomTimeline(
|
||||
$this->notices, $title, $id, $link,
|
||||
$subtitle, null, $selfuri
|
||||
);
|
||||
$this->notices, $title, $id, $link,
|
||||
$subtitle, null, $selfuri, $logo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
|
@ -167,17 +169,13 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
|||
$notices = array();
|
||||
|
||||
if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
|
||||
$notice = $this->user->noticeInbox(
|
||||
($this->page-1) * $this->count,
|
||||
$this->count, $this->since_id,
|
||||
$this->max_id, $this->since
|
||||
);
|
||||
$notice = $this->user->ownFriendsTimeline(($this->page-1) * $this->count,
|
||||
$this->count, $this->since_id,
|
||||
$this->max_id, $this->since);
|
||||
} else {
|
||||
$notice = $this->user->noticesWithFriends(
|
||||
($this->page-1) * $this->count,
|
||||
$this->count, $this->since_id,
|
||||
$this->max_id, $this->since
|
||||
);
|
||||
$notice = $this->user->friendsTimeline(($this->page-1) * $this->count,
|
||||
$this->count, $this->since_id,
|
||||
$this->max_id, $this->since);
|
||||
}
|
||||
|
||||
while ($notice->fetch()) {
|
||||
|
@ -231,14 +229,14 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
|||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -105,6 +105,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
|||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
$avatar = $this->group->homepage_logo;
|
||||
$title = sprintf(_("%s timeline"), $this->group->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:GroupTimeline:" . $this->group->id;
|
||||
|
@ -117,13 +118,14 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
|||
$this->group->nickname,
|
||||
$sitename
|
||||
);
|
||||
$logo = ($avatar) ? $avatar : User_group::defaultLogo(AVATAR_PROFILE_SIZE);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() .
|
||||
|
@ -136,7 +138,8 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
|||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$selfuri
|
||||
$selfuri,
|
||||
$logo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
|
|
249
actions/apitimelinehome.php
Normal file
249
actions/apitimelinehome.php
Normal file
|
@ -0,0 +1,249 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the home timeline
|
||||
*
|
||||
* 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
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apibareauth.php';
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the target user.
|
||||
* This is the equivalent of 'You and friends' page accessed via Web.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @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 ApiTimelineHomeAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
common_debug("api home_timeline");
|
||||
$this->user = $this->getTargetUser($this->arg('id'));
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_('No such user.'), 404, $this->format);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showTimeline()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(_("%s and friends"), $this->user->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:HomeTimeline:" . $this->user->id;
|
||||
$link = common_local_url(
|
||||
'all', array('nickname' => $this->user->nickname)
|
||||
);
|
||||
$subtitle = sprintf(
|
||||
_('Updates from %1$s and friends on %2$s!'),
|
||||
$this->user->nickname, $sitename
|
||||
);
|
||||
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
$target_id = $this->arg('id');
|
||||
|
||||
if (isset($target_id)) {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/home_timeline/' .
|
||||
$target_id . '.atom';
|
||||
} else {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/home_timeline.atom';
|
||||
}
|
||||
|
||||
$this->showAtomTimeline(
|
||||
$this->notices, $title, $id, $link,
|
||||
$subtitle, null, $selfuri, $logo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
|
||||
$notice = $this->user->noticeInbox(
|
||||
($this->page-1) * $this->count,
|
||||
$this->count, $this->since_id,
|
||||
$this->max_id, $this->since
|
||||
);
|
||||
} else {
|
||||
$notice = $this->user->noticesWithFriends(
|
||||
($this->page-1) * $this->count,
|
||||
$this->count, $this->since_id,
|
||||
$this->max_id, $this->since
|
||||
);
|
||||
}
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -110,6 +110,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
|
|||
function showTimeline()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(
|
||||
|
@ -126,20 +127,21 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
|
|||
_('%1$s updates that reply to updates from %2$s / %3$s.'),
|
||||
$sitename, $this->user->nickname, $profile->getBestName()
|
||||
);
|
||||
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() .
|
||||
ltrim($_SERVER['QUERY_STRING'], 'p=');
|
||||
$this->showAtomTimeline(
|
||||
$this->notices, $title, $id, $link, $subtitle,
|
||||
null, $selfuri
|
||||
null, $selfuri, $logo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
|
|
|
@ -103,6 +103,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
|
|||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
$sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
|
||||
$title = sprintf(_("%s public timeline"), $sitename);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:PublicTimeline";
|
||||
|
@ -114,13 +115,13 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
|
|||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $sitelogo);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() . 'api/statuses/public_timeline.atom';
|
||||
$this->showAtomTimeline(
|
||||
$this->notices, $title, $id, $link,
|
||||
$subtitle, null, $selfuri
|
||||
$subtitle, null, $selfuri, $sitelogo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
|
|
126
actions/apitimelineretweetedbyme.php
Normal file
126
actions/apitimelineretweetedbyme.php
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show authenticating user's most recent repeats
|
||||
*
|
||||
* 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
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apiauth.php';
|
||||
require_once INSTALLDIR . '/lib/mediafile.php';
|
||||
|
||||
/**
|
||||
* Show authenticating user's most recent repeats
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiTimelineRetweetedByMeAction extends ApiAuthAction
|
||||
{
|
||||
const DEFAULTCOUNT = 20;
|
||||
const MAXCOUNT = 200;
|
||||
const MAXNOTICES = 3200;
|
||||
|
||||
var $repeats = null;
|
||||
var $cnt = self::DEFAULTCOUNT;
|
||||
var $page = 1;
|
||||
var $since_id = null;
|
||||
var $max_id = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cnt = $this->int('count', self::DEFAULTCOUNT, self::MAXCOUNT, 1);
|
||||
|
||||
$page = $this->int('page', 1, (self::MAXNOTICES/$this->cnt));
|
||||
|
||||
$since_id = $this->int('since_id');
|
||||
|
||||
$max_id = $this->int('max_id');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* show a timeline of the user's repeated notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$offset = ($this->page-1) * $this->cnt;
|
||||
$limit = $this->cnt;
|
||||
|
||||
$strm = $this->auth_user->repeatedByMe($offset, $limit, $this->since_id, $this->max_id);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($strm);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
case 'atom':
|
||||
$profile = $this->auth_user->getProfile();
|
||||
|
||||
$title = sprintf(_("Repeated by %s"), $this->auth_user->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:RepeatedByMe:" . $this->auth_user->id;
|
||||
$link = common_local_url('showstream',
|
||||
array('nickname' => $this->auth_user->nickname));
|
||||
|
||||
$this->showAtomTimeline($strm, $title, $id, $link);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
125
actions/apitimelineretweetedtome.php
Normal file
125
actions/apitimelineretweetedtome.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show most recent notices that are repeats in user's inbox
|
||||
*
|
||||
* 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
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apiauth.php';
|
||||
|
||||
/**
|
||||
* Show most recent notices that are repeats in user's inbox
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiTimelineRetweetedToMeAction extends ApiAuthAction
|
||||
{
|
||||
const DEFAULTCOUNT = 20;
|
||||
const MAXCOUNT = 200;
|
||||
const MAXNOTICES = 3200;
|
||||
|
||||
var $repeats = null;
|
||||
var $cnt = self::DEFAULTCOUNT;
|
||||
var $page = 1;
|
||||
var $since_id = null;
|
||||
var $max_id = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cnt = $this->int('count', self::DEFAULTCOUNT, self::MAXCOUNT, 1);
|
||||
|
||||
$page = $this->int('page', 1, (self::MAXNOTICES/$this->cnt));
|
||||
|
||||
$since_id = $this->int('since_id');
|
||||
|
||||
$max_id = $this->int('max_id');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* show a timeline of the user's repeated notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$offset = ($this->page-1) * $this->cnt;
|
||||
$limit = $this->cnt;
|
||||
|
||||
$strm = $this->auth_user->repeatedToMe($offset, $limit, $this->since_id, $this->max_id);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($strm);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
case 'atom':
|
||||
$profile = $this->auth_user->getProfile();
|
||||
|
||||
$title = sprintf(_("Repeated to %s"), $this->auth_user->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id;
|
||||
$link = common_local_url('all',
|
||||
array('nickname' => $this->auth_user->nickname));
|
||||
|
||||
$this->showAtomTimeline($strm, $title, $id, $link);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
126
actions/apitimelineretweetsofme.php
Normal file
126
actions/apitimelineretweetsofme.php
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show authenticating user's most recent notices that have been repeated
|
||||
*
|
||||
* 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
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apiauth.php';
|
||||
require_once INSTALLDIR . '/lib/mediafile.php';
|
||||
|
||||
/**
|
||||
* Show authenticating user's most recent notices that have been repeated
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
|
||||
{
|
||||
const DEFAULTCOUNT = 20;
|
||||
const MAXCOUNT = 200;
|
||||
const MAXNOTICES = 3200;
|
||||
|
||||
var $repeats = null;
|
||||
var $cnt = self::DEFAULTCOUNT;
|
||||
var $page = 1;
|
||||
var $since_id = null;
|
||||
var $max_id = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cnt = $this->int('count', self::DEFAULTCOUNT, self::MAXCOUNT, 1);
|
||||
|
||||
$page = $this->int('page', 1, (self::MAXNOTICES/$this->cnt));
|
||||
|
||||
$since_id = $this->int('since_id');
|
||||
|
||||
$max_id = $this->int('max_id');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* show a timeline of the user's repeated notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$offset = ($this->page-1) * $this->cnt;
|
||||
$limit = $this->cnt;
|
||||
|
||||
$strm = $this->auth_user->repeatsOfMe($offset, $limit, $this->since_id, $this->max_id);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($strm);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
case 'atom':
|
||||
$profile = $this->auth_user->getProfile();
|
||||
|
||||
$title = sprintf(_("Repeats of %s"), $this->auth_user->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:RepeatsOfMe:" . $this->auth_user->id;
|
||||
$link = common_local_url('showstream',
|
||||
array('nickname' => $this->auth_user->nickname));
|
||||
|
||||
$this->showAtomTimeline($strm, $title, $id, $link);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -98,6 +98,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
|||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
$sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
|
||||
$title = sprintf(_("Notices tagged with %s"), $this->tag);
|
||||
$link = common_local_url(
|
||||
'tag',
|
||||
|
@ -116,7 +117,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
|||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
|
||||
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $sitelogo);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() .
|
||||
|
@ -129,7 +130,8 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
|||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$selfuri
|
||||
$selfuri,
|
||||
$sitelogo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
|
|
|
@ -112,6 +112,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||
function showTimeline()
|
||||
{
|
||||
$profile = $this->user->getProfile();
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(_("%s timeline"), $this->user->nickname);
|
||||
|
@ -125,6 +126,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||
_('Updates from %1$s on %2$s!'),
|
||||
$this->user->nickname, $sitename
|
||||
);
|
||||
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||
|
||||
// FriendFeed's SUP protocol
|
||||
// Also added RSS and Atom feeds
|
||||
|
@ -139,7 +141,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices, $title, $link,
|
||||
$subtitle, $suplink
|
||||
$subtitle, $suplink, $logo
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
@ -153,7 +155,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||
}
|
||||
$this->showAtomTimeline(
|
||||
$this->notices, $title, $id, $link,
|
||||
$subtitle, $suplink, $selfuri
|
||||
$subtitle, $suplink, $selfuri, $logo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
|
|
|
@ -31,15 +31,15 @@ class FileAction extends Action
|
|||
parent::prepare($args);
|
||||
$this->id = $this->trimmed('notice');
|
||||
if (empty($this->id)) {
|
||||
$this->clientError(_('No notice id'));
|
||||
$this->clientError(_('No notice ID.'));
|
||||
}
|
||||
$notice = Notice::staticGet('id', $this->id);
|
||||
if (empty($notice)) {
|
||||
$this->clientError(_('No notice'));
|
||||
$this->clientError(_('No notice.'));
|
||||
}
|
||||
$atts = $notice->attachments();
|
||||
if (empty($atts)) {
|
||||
$this->clientError(_('No attachments'));
|
||||
$this->clientError(_('No attachments.'));
|
||||
}
|
||||
foreach ($atts as $att) {
|
||||
if (!empty($att->filename)) {
|
||||
|
@ -48,7 +48,7 @@ class FileAction extends Action
|
|||
}
|
||||
}
|
||||
if (empty($this->filerec)) {
|
||||
$this->clientError(_('No uploaded attachments'));
|
||||
$this->clientError(_('No uploaded attachments.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -88,14 +88,14 @@ class groupRssAction extends Rss10Action
|
|||
}
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname'), 404);
|
||||
$this->clientError(_('No nickname.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->group = User_group::staticGet('nickname', $nickname);
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ class NewmessageAction extends Action
|
|||
return;
|
||||
}
|
||||
|
||||
$this->notify($user, $this->other, $message);
|
||||
$message->notify();
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
|
@ -247,12 +247,6 @@ class NewmessageAction extends Action
|
|||
}
|
||||
}
|
||||
|
||||
function notify($from, $to, $message)
|
||||
{
|
||||
mail_notify_message($message, $from, $to);
|
||||
// XXX: Jabber, SMS notifications... probably queued
|
||||
}
|
||||
|
||||
// Do nothing (override)
|
||||
|
||||
function showNoticeForm()
|
||||
|
|
|
@ -187,10 +187,12 @@ class NewnoticeAction extends Action
|
|||
}
|
||||
}
|
||||
|
||||
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
||||
($replyto == 'false') ? null : $replyto,
|
||||
null, null,
|
||||
$lat, $lon, $location_id, $location_ns);
|
||||
$notice = Notice::saveNew($user->id, $content_shortened, 'web',
|
||||
array('reply_to' => ($replyto == 'false') ? null : $replyto,
|
||||
'lat' => $lat,
|
||||
'lon' => $lon,
|
||||
'location_id' => $location_id,
|
||||
'location_ns' => $location_ns));
|
||||
|
||||
if (isset($upload)) {
|
||||
$upload->attachToNotice($notice);
|
||||
|
|
126
actions/repeat.php
Normal file
126
actions/repeat.php
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Repeat action.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 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')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeat action
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class RepeatAction extends Action
|
||||
{
|
||||
var $user = null;
|
||||
var $notice = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = common_current_user();
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_("Only logged-in users can repeat notices."));
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->trimmed('notice');
|
||||
|
||||
if (empty($id)) {
|
||||
$this->clientError(_("No notice specified."));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->notice = Notice::staticGet('id', $id);
|
||||
|
||||
if (empty($this->notice)) {
|
||||
$this->clientError(_("No notice specified."));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->user->id == $this->notice->profile_id) {
|
||||
$this->clientError(_("You can't repeat your own notice."));
|
||||
return false;
|
||||
}
|
||||
|
||||
$token = $this->trimmed('token-'.$id);
|
||||
|
||||
if (empty($token) || $token != common_session_token()) {
|
||||
$this->clientError(_("There was a problem with your session token. Try again, please."));
|
||||
return false;
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if ($profile->hasRepeated($id)) {
|
||||
$this->clientError(_("You already repeated that notice."));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args query arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
$repeat = $this->notice->repeat($this->user->id, 'web');
|
||||
|
||||
common_broadcast_notice($repeat);
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
$this->element('title', null, _('Repeated'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$this->element('p', array('id' => 'repeat_response',
|
||||
'class' => 'repeated'),
|
||||
_('Repeated!'));
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
// FIXME!
|
||||
}
|
||||
}
|
||||
}
|
|
@ -269,4 +269,50 @@ class ProfileNoticeListItem extends NoticeListItem
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* show a link to the author of repeat
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showRepeat()
|
||||
{
|
||||
if (!empty($this->repeat)) {
|
||||
|
||||
// FIXME: this code is almost identical to default; need to refactor
|
||||
|
||||
$attrs = array('href' => $this->profile->profileurl,
|
||||
'class' => 'url');
|
||||
|
||||
if (!empty($this->profile->fullname)) {
|
||||
$attrs['title'] = $this->profile->fullname . ' (' . $this->profile->nickname . ')';
|
||||
}
|
||||
|
||||
$this->out->elementStart('span', 'repeat');
|
||||
|
||||
$this->out->elementStart('a', $attrs);
|
||||
|
||||
$avatar = $this->profile->getAvatar(AVATAR_MINI_SIZE);
|
||||
|
||||
$this->out->element('img', array('src' => ($avatar) ?
|
||||
$avatar->displayUrl() :
|
||||
Avatar::defaultImage(AVATAR_MINI_SIZE),
|
||||
'class' => 'avatar photo',
|
||||
'width' => AVATAR_MINI_SIZE,
|
||||
'height' => AVATAR_MINI_SIZE,
|
||||
'alt' =>
|
||||
($this->profile->fullname) ?
|
||||
$this->profile->fullname :
|
||||
$this->profile->nickname));
|
||||
|
||||
$this->out->elementEnd('a');
|
||||
|
||||
$text_link = XMLStringer::estring('a', $attrs, $this->profile->nickname);
|
||||
|
||||
$this->out->raw(sprintf(_('Repeat of %s'), $text_link));
|
||||
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,13 +30,13 @@ class TagotherAction extends Action
|
|||
{
|
||||
parent::prepare($args);
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('Not logged in'), 403);
|
||||
$this->clientError(_('Not logged in.'), 403);
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->trimmed('id');
|
||||
if (!$id) {
|
||||
$this->clientError(_('No id argument.'));
|
||||
$this->clientError(_('No ID argument.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class UserbyidAction extends Action
|
|||
parent::handle($args);
|
||||
$id = $this->trimmed('id');
|
||||
if (!$id) {
|
||||
$this->clientError(_('No id.'));
|
||||
$this->clientError(_('No ID.'));
|
||||
}
|
||||
$user = User::staticGet($id);
|
||||
if (!$user) {
|
||||
|
@ -88,4 +88,3 @@ class UserbyidAction extends Action
|
|||
common_redirect($url, 303);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,20 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
|||
|
||||
class Memcached_DataObject extends DB_DataObject
|
||||
{
|
||||
/**
|
||||
* Destructor to free global memory resources associated with
|
||||
* this data object when it's unset or goes out of scope.
|
||||
* DB_DataObject doesn't do this yet by itself.
|
||||
*/
|
||||
|
||||
function __destruct()
|
||||
{
|
||||
$this->free();
|
||||
if (method_exists('DB_DataObject', '__destruct')) {
|
||||
parent::__destruct();
|
||||
}
|
||||
}
|
||||
|
||||
function &staticGet($cls, $k, $v=null)
|
||||
{
|
||||
if (is_null($v)) {
|
||||
|
|
|
@ -89,4 +89,12 @@ class Message extends Memcached_DataObject
|
|||
$contentlimit = self::maxContent();
|
||||
return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit));
|
||||
}
|
||||
|
||||
function notify()
|
||||
{
|
||||
$from = User::staticGet('id', $this->from_profile);
|
||||
$to = User::staticGet('id', $this->to_profile);
|
||||
|
||||
mail_notify_message($this, $from, $to);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,13 +55,13 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
public $__table = 'notice'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $profile_id; // int(4) not_null
|
||||
public $profile_id; // int(4) multiple_key not_null
|
||||
public $uri; // varchar(255) unique_key
|
||||
public $content; // text()
|
||||
public $rendered; // text()
|
||||
public $content; // text
|
||||
public $rendered; // text
|
||||
public $url; // varchar(255)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
public $created; // datetime multiple_key not_null default_0000-00-00%2000%3A00%3A00
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
public $reply_to; // int(4)
|
||||
public $is_local; // tinyint(1)
|
||||
public $source; // varchar(32)
|
||||
|
@ -70,9 +70,11 @@ class Notice extends Memcached_DataObject
|
|||
public $lon; // decimal(10,7)
|
||||
public $location_id; // int(4)
|
||||
public $location_ns; // int(4)
|
||||
public $repeat_of; // int(4)
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) {
|
||||
function staticGet($k,$v=NULL)
|
||||
{
|
||||
return Memcached_DataObject::staticGet('Notice',$k,$v);
|
||||
}
|
||||
|
||||
|
@ -113,6 +115,12 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
//Null any notices that are replies to this notice
|
||||
$this->query(sprintf("UPDATE notice set reply_to = null WHERE reply_to = %d", $this->id));
|
||||
|
||||
//Null any notices that are repeats of this notice
|
||||
//XXX: probably need to uncache these, too
|
||||
|
||||
$this->query(sprintf("UPDATE notice set repeat_of = null WHERE repeat_of = %d", $this->id));
|
||||
|
||||
$related = array('Reply',
|
||||
'Fave',
|
||||
'Notice_tag',
|
||||
|
@ -167,9 +175,18 @@ class Notice extends Memcached_DataObject
|
|||
}
|
||||
}
|
||||
|
||||
static function saveNew($profile_id, $content, $source=null,
|
||||
$is_local=Notice::LOCAL_PUBLIC, $reply_to=null, $uri=null, $created=null,
|
||||
$lat=null, $lon=null, $location_id=null, $location_ns=null) {
|
||||
static function saveNew($profile_id, $content, $source, $options=null) {
|
||||
|
||||
if (!empty($options)) {
|
||||
extract($options);
|
||||
if (!isset($reply_to)) {
|
||||
$reply_to = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($is_local)) {
|
||||
$is_local = Notice::LOCAL_PUBLIC;
|
||||
}
|
||||
|
||||
$profile = Profile::staticGet($profile_id);
|
||||
|
||||
|
@ -225,7 +242,14 @@ class Notice extends Memcached_DataObject
|
|||
$notice->source = $source;
|
||||
$notice->uri = $uri;
|
||||
|
||||
$notice->reply_to = self::getReplyTo($reply_to, $profile_id, $source, $final);
|
||||
// Handle repeat case
|
||||
|
||||
if (isset($repeat_of)) {
|
||||
$notice->repeat_of = $repeat_of;
|
||||
$notice->reply_to = $repeat_of;
|
||||
} else {
|
||||
$notice->reply_to = self::getReplyTo($reply_to, $profile_id, $source, $final);
|
||||
}
|
||||
|
||||
if (!empty($notice->reply_to)) {
|
||||
$reply = Notice::staticGet('id', $notice->reply_to);
|
||||
|
@ -423,10 +447,60 @@ class Notice extends Memcached_DataObject
|
|||
$this->blowTagCache($blowLast);
|
||||
$this->blowGroupCache($blowLast);
|
||||
$this->blowConversationCache($blowLast);
|
||||
$this->blowRepeatCache();
|
||||
$profile = Profile::staticGet($this->profile_id);
|
||||
$profile->blowNoticeCount();
|
||||
}
|
||||
|
||||
function blowRepeatCache()
|
||||
{
|
||||
if (!empty($this->repeat_of)) {
|
||||
$cache = common_memcache();
|
||||
if (!empty($cache)) {
|
||||
// XXX: only blow if <100 in cache
|
||||
$ck = common_cache_key('notice:repeats:'.$this->repeat_of);
|
||||
$result = $cache->delete($ck);
|
||||
|
||||
$user = User::staticGet('id', $this->profile_id);
|
||||
|
||||
if (!empty($user)) {
|
||||
$uk = common_cache_key('user:repeated_by_me:'.$user->id);
|
||||
$cache->delete($uk);
|
||||
$user->free();
|
||||
unset($user);
|
||||
}
|
||||
|
||||
$original = Notice::staticGet('id', $this->repeat_of);
|
||||
|
||||
if (!empty($original)) {
|
||||
$originalUser = User::staticGet('id', $original->profile_id);
|
||||
if (!empty($originalUser)) {
|
||||
$ouk = common_cache_key('user:repeats_of_me:'.$originalUser->id);
|
||||
$cache->delete($ouk);
|
||||
$originalUser->free();
|
||||
unset($originalUser);
|
||||
}
|
||||
$original->free();
|
||||
unset($original);
|
||||
}
|
||||
|
||||
$ni = new Notice_inbox();
|
||||
|
||||
$ni->notice_id = $this->id;
|
||||
|
||||
if ($ni->find()) {
|
||||
while ($ni->fetch()) {
|
||||
$tmk = common_cache_key('user:repeated_to_me:'.$ni->user_id);
|
||||
$cache->delete($tmk);
|
||||
}
|
||||
}
|
||||
|
||||
$ni->free();
|
||||
unset($ni);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function blowConversationCache($blowLast=false)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
|
@ -456,8 +530,18 @@ class Notice extends Memcached_DataObject
|
|||
if ($member->find()) {
|
||||
while ($member->fetch()) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:' . $member->profile_id));
|
||||
if (empty($this->repeat_of)) {
|
||||
$cache->delete(common_cache_key('user:friends_timeline:' . $member->profile_id));
|
||||
$cache->delete(common_cache_key('user:friends_timeline_own:' . $member->profile_id));
|
||||
}
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id . ';last'));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:' . $member->profile_id . ';last'));
|
||||
if (empty($this->repeat_of)) {
|
||||
$cache->delete(common_cache_key('user:friends_timeline:' . $member->profile_id . ';last'));
|
||||
$cache->delete(common_cache_key('user:friends_timeline_own:' . $member->profile_id . ';last'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -505,9 +589,17 @@ class Notice extends Memcached_DataObject
|
|||
while ($user->fetch()) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id));
|
||||
if (empty($this->repeat_of)) {
|
||||
$cache->delete(common_cache_key('user:friends_timeline:'.$user->id));
|
||||
$cache->delete(common_cache_key('user:friends_timeline_own:'.$user->id));
|
||||
}
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id.';last'));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id.';last'));
|
||||
if (empty($this->repeat_of)) {
|
||||
$cache->delete(common_cache_key('user:friends_timeline:'.$user->id.';last'));
|
||||
$cache->delete(common_cache_key('user:friends_timeline_own:'.$user->id.';last'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$user->free();
|
||||
|
@ -581,193 +673,6 @@ class Notice extends Memcached_DataObject
|
|||
}
|
||||
}
|
||||
|
||||
# XXX: too many args; we need to move to named params or even a separate
|
||||
# class for notice streams
|
||||
|
||||
static function getStream($qry, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0, $order=null, $since=null) {
|
||||
|
||||
if (common_config('memcached', 'enabled')) {
|
||||
|
||||
# Skip the cache if this is a since, since_id or max_id qry
|
||||
if ($since_id > 0 || $max_id > 0 || $since) {
|
||||
return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since);
|
||||
} else {
|
||||
return Notice::getCachedStream($qry, $cachekey, $offset, $limit, $order);
|
||||
}
|
||||
}
|
||||
|
||||
return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since);
|
||||
}
|
||||
|
||||
static function getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since) {
|
||||
|
||||
$needAnd = false;
|
||||
$needWhere = true;
|
||||
|
||||
if (preg_match('/\bWHERE\b/i', $qry)) {
|
||||
$needWhere = false;
|
||||
$needAnd = true;
|
||||
}
|
||||
|
||||
if ($since_id > 0) {
|
||||
|
||||
if ($needWhere) {
|
||||
$qry .= ' WHERE ';
|
||||
$needWhere = false;
|
||||
} else {
|
||||
$qry .= ' AND ';
|
||||
}
|
||||
|
||||
$qry .= ' notice.id > ' . $since_id;
|
||||
}
|
||||
|
||||
if ($max_id > 0) {
|
||||
|
||||
if ($needWhere) {
|
||||
$qry .= ' WHERE ';
|
||||
$needWhere = false;
|
||||
} else {
|
||||
$qry .= ' AND ';
|
||||
}
|
||||
|
||||
$qry .= ' notice.id <= ' . $max_id;
|
||||
}
|
||||
|
||||
if ($since) {
|
||||
|
||||
if ($needWhere) {
|
||||
$qry .= ' WHERE ';
|
||||
$needWhere = false;
|
||||
} else {
|
||||
$qry .= ' AND ';
|
||||
}
|
||||
|
||||
$qry .= ' notice.created > \'' . date('Y-m-d H:i:s', $since) . '\'';
|
||||
}
|
||||
|
||||
# Allow ORDER override
|
||||
|
||||
if ($order) {
|
||||
$qry .= $order;
|
||||
} else {
|
||||
$qry .= ' ORDER BY notice.created DESC, notice.id DESC ';
|
||||
}
|
||||
|
||||
if (common_config('db','type') == 'pgsql') {
|
||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
} else {
|
||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||
}
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->query($qry);
|
||||
|
||||
return $notice;
|
||||
}
|
||||
|
||||
# XXX: this is pretty long and should probably be broken up into
|
||||
# some helper functions
|
||||
|
||||
static function getCachedStream($qry, $cachekey, $offset, $limit, $order) {
|
||||
|
||||
# If outside our cache window, just go to the DB
|
||||
|
||||
if ($offset + $limit > NOTICE_CACHE_WINDOW) {
|
||||
return Notice::getStreamDirect($qry, $offset, $limit, null, null, $order, null);
|
||||
}
|
||||
|
||||
# Get the cache; if we can't, just go to the DB
|
||||
|
||||
$cache = common_memcache();
|
||||
|
||||
if (empty($cache)) {
|
||||
return Notice::getStreamDirect($qry, $offset, $limit, null, null, $order, null);
|
||||
}
|
||||
|
||||
# Get the notices out of the cache
|
||||
|
||||
$notices = $cache->get(common_cache_key($cachekey));
|
||||
|
||||
# On a cache hit, return a DB-object-like wrapper
|
||||
|
||||
if ($notices !== false) {
|
||||
$wrapper = new ArrayWrapper(array_slice($notices, $offset, $limit));
|
||||
return $wrapper;
|
||||
}
|
||||
|
||||
# If the cache was invalidated because of new data being
|
||||
# added, we can try and just get the new stuff. We keep an additional
|
||||
# copy of the data at the key + ';last'
|
||||
|
||||
# No cache hit. Try to get the *last* cached version
|
||||
|
||||
$last_notices = $cache->get(common_cache_key($cachekey) . ';last');
|
||||
|
||||
if ($last_notices) {
|
||||
|
||||
# Reverse-chron order, so last ID is last.
|
||||
|
||||
$last_id = $last_notices[0]->id;
|
||||
|
||||
# XXX: this assumes monotonically increasing IDs; a fair
|
||||
# bet with our DB.
|
||||
|
||||
$new_notice = Notice::getStreamDirect($qry, 0, NOTICE_CACHE_WINDOW,
|
||||
$last_id, null, $order, null);
|
||||
|
||||
if ($new_notice) {
|
||||
$new_notices = array();
|
||||
while ($new_notice->fetch()) {
|
||||
$new_notices[] = clone($new_notice);
|
||||
}
|
||||
$new_notice->free();
|
||||
$notices = array_slice(array_merge($new_notices, $last_notices),
|
||||
0, NOTICE_CACHE_WINDOW);
|
||||
|
||||
# Store the array in the cache for next time
|
||||
|
||||
$result = $cache->set(common_cache_key($cachekey), $notices);
|
||||
$result = $cache->set(common_cache_key($cachekey) . ';last', $notices);
|
||||
|
||||
# return a wrapper of the array for use now
|
||||
|
||||
return new ArrayWrapper(array_slice($notices, $offset, $limit));
|
||||
}
|
||||
}
|
||||
|
||||
# Otherwise, get the full cache window out of the DB
|
||||
|
||||
$notice = Notice::getStreamDirect($qry, 0, NOTICE_CACHE_WINDOW, null, null, $order, null);
|
||||
|
||||
# If there are no hits, just return the value
|
||||
|
||||
if (empty($notice)) {
|
||||
return $notice;
|
||||
}
|
||||
|
||||
# Pack results into an array
|
||||
|
||||
$notices = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
|
||||
# Store the array in the cache for next time
|
||||
|
||||
$result = $cache->set(common_cache_key($cachekey), $notices);
|
||||
$result = $cache->set(common_cache_key($cachekey) . ';last', $notices);
|
||||
|
||||
# return a wrapper of the array for use now
|
||||
|
||||
$wrapper = new ArrayWrapper(array_slice($notices, $offset, $limit));
|
||||
|
||||
return $wrapper;
|
||||
}
|
||||
|
||||
function getStreamByIds($ids)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
|
@ -1423,4 +1328,72 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
return $location;
|
||||
}
|
||||
|
||||
function repeat($repeater_id, $source)
|
||||
{
|
||||
$author = Profile::staticGet('id', $this->profile_id);
|
||||
|
||||
// FIXME: truncate on long repeats...?
|
||||
|
||||
$content = sprintf(_('RT @%1$s %2$s'),
|
||||
$author->nickname,
|
||||
$this->content);
|
||||
|
||||
return self::saveNew($repeater_id, $content, $source,
|
||||
array('repeat_of' => $this->id));
|
||||
}
|
||||
|
||||
// These are supposed to be in chron order!
|
||||
|
||||
function repeatStream($limit=100)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
|
||||
if (empty($cache)) {
|
||||
$ids = $this->_repeatStreamDirect($limit);
|
||||
} else {
|
||||
$idstr = $cache->get(common_cache_key('notice:repeats:'.$this->id));
|
||||
if (!empty($idstr)) {
|
||||
$ids = explode(',', $idstr);
|
||||
} else {
|
||||
$ids = $this->_repeatStreamDirect(100);
|
||||
$cache->set(common_cache_key('notice:repeats:'.$this->id), implode(',', $ids));
|
||||
}
|
||||
if ($limit < 100) {
|
||||
// We do a max of 100, so slice down to limit
|
||||
$ids = array_slice($ids, 0, $limit);
|
||||
}
|
||||
}
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _repeatStreamDirect($limit)
|
||||
{
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->selectAdd(); // clears it
|
||||
$notice->selectAdd('id');
|
||||
|
||||
$notice->repeat_of = $this->id;
|
||||
|
||||
$notice->orderBy('created'); // NB: asc!
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$notice->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($notice->find()) {
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -716,4 +716,15 @@ class Profile extends Memcached_DataObject
|
|||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function hasRepeated($notice_id)
|
||||
{
|
||||
// XXX: not really a pkey, but should work
|
||||
|
||||
$notice = Memcached_DataObject::pkeyGet('Notice',
|
||||
array('profile_id' => $this->id,
|
||||
'repeat_of' => $notice_id));
|
||||
|
||||
return !empty($notice);
|
||||
}
|
||||
}
|
||||
|
|
230
classes/User.php
230
classes/User.php
|
@ -473,6 +473,77 @@ class User extends Memcached_DataObject
|
|||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function friendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_friendsTimelineDirect'),
|
||||
array(false),
|
||||
'user:friends_timeline:'.$this->id,
|
||||
$offset, $limit, $since_id, $before_id, $since);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function ownFriendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_friendsTimelineDirect'),
|
||||
array(true),
|
||||
'user:friends_timeline_own:'.$this->id,
|
||||
$offset, $limit, $since_id, $before_id, $since);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _friendsTimelineDirect($own, $offset, $limit, $since_id, $max_id, $since)
|
||||
{
|
||||
$qry =
|
||||
'SELECT notice.id AS id ' .
|
||||
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
|
||||
'WHERE notice_inbox.user_id = ' . $this->id . ' ' .
|
||||
'AND notice.repeat_of IS NULL ';
|
||||
|
||||
if (!$own) {
|
||||
// XXX: autoload notice inbox for constant
|
||||
$inbox = new Notice_inbox();
|
||||
|
||||
$qry .= 'AND notice_inbox.source != ' . NOTICE_INBOX_SOURCE_GATEWAY . ' ';
|
||||
}
|
||||
|
||||
if ($since_id != 0) {
|
||||
$qry .= 'AND notice.id > ' . $since_id . ' ';
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$qry .= 'AND notice.id <= ' . $max_id . ' ';
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$qry .= 'AND notice.modified > \'' . date('Y-m-d H:i:s', $since) . '\' ';
|
||||
}
|
||||
|
||||
// NOTE: we sort by fave time, not by notice time!
|
||||
|
||||
$qry .= 'ORDER BY notice.id DESC ';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$qry .= "LIMIT $limit OFFSET $offset";
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->query($qry);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function blowFavesCache()
|
||||
{
|
||||
$cache = common_memcache();
|
||||
|
@ -741,4 +812,163 @@ class User extends Memcached_DataObject
|
|||
$profile = $this->getProfile();
|
||||
return $profile->isSilenced();
|
||||
}
|
||||
|
||||
function repeatedByMe($offset=0, $limit=20, $since_id=null, $max_id=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_repeatedByMeDirect'),
|
||||
array(),
|
||||
'user:repeated_by_me:'.$this->id,
|
||||
$offset, $limit, $since_id, $max_id, null);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _repeatedByMeDirect($offset, $limit, $since_id, $max_id, $since)
|
||||
{
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->selectAdd(); // clears it
|
||||
$notice->selectAdd('id');
|
||||
|
||||
$notice->profile_id = $this->id;
|
||||
$notice->whereAdd('repeat_of IS NOT NULL');
|
||||
|
||||
$notice->orderBy('id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$notice->limit($offset, $limit);
|
||||
}
|
||||
|
||||
if ($since_id != 0) {
|
||||
$notice->whereAdd('id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$notice->whereAdd('id <= ' . $max_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$notice->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($notice->find()) {
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function repeatsOfMe($offset=0, $limit=20, $since_id=null, $max_id=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_repeatsOfMeDirect'),
|
||||
array(),
|
||||
'user:repeats_of_me:'.$this->id,
|
||||
$offset, $limit, $since_id, $max_id, null);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _repeatsOfMeDirect($offset, $limit, $since_id, $max_id, $since)
|
||||
{
|
||||
$qry =
|
||||
'SELECT DISTINCT original.id AS id ' .
|
||||
'FROM notice original JOIN notice rept ON original.id = rept.repeat_of ' .
|
||||
'WHERE original.profile_id = ' . $this->id . ' ';
|
||||
|
||||
if ($since_id != 0) {
|
||||
$qry .= 'AND original.id > ' . $since_id . ' ';
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$qry .= 'AND original.id <= ' . $max_id . ' ';
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$qry .= 'AND original.modified > \'' . date('Y-m-d H:i:s', $since) . '\' ';
|
||||
}
|
||||
|
||||
// NOTE: we sort by fave time, not by notice time!
|
||||
|
||||
$qry .= 'ORDER BY original.id DESC ';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$qry .= "LIMIT $limit OFFSET $offset";
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->query($qry);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_repeatedToMeDirect'),
|
||||
array(),
|
||||
'user:repeated_to_me:'.$this->id,
|
||||
$offset, $limit, $since_id, $max_id, null);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _repeatedToMeDirect($offset, $limit, $since_id, $max_id, $since)
|
||||
{
|
||||
$qry =
|
||||
'SELECT notice.id AS id ' .
|
||||
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
|
||||
'WHERE notice_inbox.user_id = ' . $this->id . ' ' .
|
||||
'AND notice.repeat_of IS NOT NULL ';
|
||||
|
||||
if ($since_id != 0) {
|
||||
$qry .= 'AND notice.id > ' . $since_id . ' ';
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$qry .= 'AND notice.id <= ' . $max_id . ' ';
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$qry .= 'AND notice.modified > \'' . date('Y-m-d H:i:s', $since) . '\' ';
|
||||
}
|
||||
|
||||
// NOTE: we sort by fave time, not by notice time!
|
||||
|
||||
$qry .= 'ORDER BY notice.id DESC ';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$qry .= "LIMIT $limit OFFSET $offset";
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->query($qry);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
[avatar]
|
||||
profile_id = 129
|
||||
original = 17
|
||||
|
@ -306,6 +307,7 @@ lat = 1
|
|||
lon = 1
|
||||
location_id = 1
|
||||
location_ns = 1
|
||||
repeat_of = 1
|
||||
|
||||
[notice__keys]
|
||||
id = N
|
||||
|
|
|
@ -4,8 +4,10 @@ alter table notice
|
|||
add column lon decimal(10,7) comment 'longitude',
|
||||
add column location_id integer comment 'location id if possible',
|
||||
add column location_ns integer comment 'namespace for location',
|
||||
add column repeat_of integer comment 'notice this is a repeat of' references notice (id),
|
||||
drop index notice_profile_id_idx,
|
||||
add index notice_profile_id_idx (profile_id,created,id);
|
||||
add index notice_profile_id_idx (profile_id,created,id),
|
||||
add index notice_repeatof_idx (repeat_of);
|
||||
|
||||
alter table message
|
||||
modify column content text comment 'message content';
|
||||
|
|
|
@ -74,6 +74,7 @@ ALTER TABLE notice ADD COLUMN lat decimal(10, 7) /* comment 'latitude'*/;
|
|||
ALTER TABLE notice ADD COLUMN lon decimal(10,7) /* comment 'longitude'*/;
|
||||
ALTER TABLE notice ADD COLUMN location_id integer /* comment 'location id if possible'*/ ;
|
||||
ALTER TABLE notice ADD COLUMN location_ns integer /* comment 'namespace for location'*/;
|
||||
ALTER TABLE notice ADD COLUMN repeat_of integer /* comment 'notice this is a repeat of' */ references notice (id);
|
||||
|
||||
ALTER TABLE profile ADD COLUMN lat decimal(10,7) /*comment 'latitude'*/ ;
|
||||
ALTER TABLE profile ADD COLUMN lon decimal(10,7) /*comment 'longitude'*/;
|
||||
|
|
|
@ -129,11 +129,13 @@ create table notice (
|
|||
lon decimal(10,7) comment 'longitude',
|
||||
location_id integer comment 'location id if possible',
|
||||
location_ns integer comment 'namespace for location',
|
||||
repeat_of integer comment 'notice this is a repeat of' references notice (id),
|
||||
|
||||
index notice_profile_id_idx (profile_id,created,id),
|
||||
index notice_conversation_idx (conversation),
|
||||
index notice_created_idx (created),
|
||||
index notice_replyto_idx (reply_to),
|
||||
index notice_repeatof_idx (repeat_of),
|
||||
FULLTEXT(content)
|
||||
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
|
||||
|
|
|
@ -135,7 +135,9 @@ create table notice (
|
|||
lat decimal(10,7) /* comment 'latitude'*/ ,
|
||||
lon decimal(10,7) /* comment 'longitude'*/ ,
|
||||
location_id integer /* comment 'location id if possible'*/ ,
|
||||
location_ns integer /* comment 'namespace for location'*/
|
||||
location_ns integer /* comment 'namespace for location'*/ ,
|
||||
repeat_of integer /* comment 'notice this is a repeat of' */ references notice (id) ,
|
||||
|
||||
/* FULLTEXT(content) */
|
||||
);
|
||||
|
||||
|
|
|
@ -315,6 +315,10 @@ var SN = { // StatusNet
|
|||
$('.form_disfavor').each(function() { SN.U.FormXHR($(this)); });
|
||||
},
|
||||
|
||||
NoticeRepeat: function() {
|
||||
$('.form_repeat').each(function() { SN.U.FormXHR($(this)); });
|
||||
},
|
||||
|
||||
NoticeAttachments: function() {
|
||||
$('.notice a.attachment').each(function() {
|
||||
SN.U.NoticeWithAttachment($(this).closest('.notice'));
|
||||
|
@ -448,6 +452,7 @@ var SN = { // StatusNet
|
|||
Notices: function() {
|
||||
if ($('body.user_in').length > 0) {
|
||||
SN.U.NoticeFavor();
|
||||
SN.U.NoticeRepeat();
|
||||
SN.U.NoticeReply();
|
||||
}
|
||||
|
||||
|
|
|
@ -951,6 +951,36 @@ class Action extends HTMLOutputter // lawsuit
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Integer value of an argument
|
||||
*
|
||||
* @param string $key query key we're interested in
|
||||
* @param string $defValue optional default value (default null)
|
||||
* @param string $maxValue optional max value (default null)
|
||||
* @param string $minValue optional min value (default null)
|
||||
*
|
||||
* @return integer integer value
|
||||
*/
|
||||
|
||||
function int($key, $defValue=null, $maxValue=null, $minValue=null)
|
||||
{
|
||||
$arg = strtolower($this->trimmed($key));
|
||||
|
||||
if (is_null($arg) || !is_integer($arg)) {
|
||||
return $defValue;
|
||||
}
|
||||
|
||||
if (!is_null($maxValue)) {
|
||||
$arg = min($arg, $maxValue);
|
||||
}
|
||||
|
||||
if (!is_null($minValue)) {
|
||||
$arg = max($arg, $minValue);
|
||||
}
|
||||
|
||||
return $arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server error
|
||||
*
|
||||
|
|
73
lib/api.php
73
lib/api.php
|
@ -53,13 +53,14 @@ if (!defined('STATUSNET')) {
|
|||
|
||||
class ApiAction extends Action
|
||||
{
|
||||
var $format = null;
|
||||
var $user = null;
|
||||
var $page = null;
|
||||
var $count = null;
|
||||
var $max_id = null;
|
||||
var $since_id = null;
|
||||
var $since = null;
|
||||
var $format = null;
|
||||
var $user = null;
|
||||
var $auth_user = null;
|
||||
var $page = null;
|
||||
var $count = null;
|
||||
var $max_id = null;
|
||||
var $since_id = null;
|
||||
var $since = null;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
|
@ -134,17 +135,19 @@ class ApiAction extends Action
|
|||
$twitter_user['protected'] = false; # not supported by StatusNet yet
|
||||
$twitter_user['followers_count'] = $profile->subscriberCount();
|
||||
|
||||
$user = $profile->getUser();
|
||||
$design = null;
|
||||
$user = $profile->getUser();
|
||||
|
||||
// Note: some profiles don't have an associated user
|
||||
|
||||
$defaultDesign = Design::siteDesign();
|
||||
|
||||
if (!empty($user)) {
|
||||
$design = $user->getDesign();
|
||||
}
|
||||
|
||||
if (empty($design)) {
|
||||
$design = Design::siteDesign();
|
||||
}
|
||||
|
||||
$color = Design::toWebColor(empty($design->backgroundcolor) ? $defaultDesign->backgroundcolor : $design->backgroundcolor);
|
||||
$twitter_user['profile_background_color'] = ($color == null) ? '' : '#'.$color->hexValue();
|
||||
$color = Design::toWebColor(empty($design->textcolor) ? $defaultDesign->textcolor : $design->textcolor);
|
||||
|
@ -163,7 +166,7 @@ class ApiAction extends Action
|
|||
|
||||
$timezone = 'UTC';
|
||||
|
||||
if (!empty($user) && !empty($user->timezone)) {
|
||||
if ($user->timezone) {
|
||||
$timezone = $user->timezone;
|
||||
}
|
||||
|
||||
|
@ -188,13 +191,14 @@ class ApiAction extends Action
|
|||
$twitter_user['following'] = false;
|
||||
$twitter_user['notifications'] = false;
|
||||
|
||||
if (isset($apidata['user'])) {
|
||||
if (isset($this->auth_user)) {
|
||||
|
||||
$twitter_user['following'] = $apidata['user']->isSubscribed($profile);
|
||||
$twitter_user['following'] = $this->auth_user->isSubscribed($profile);
|
||||
|
||||
// Notifications on?
|
||||
$sub = Subscription::pkeyGet(array('subscriber' =>
|
||||
$apidata['user']->id, 'subscribed' => $profile->id));
|
||||
$this->auth_user->id,
|
||||
'subscribed' => $profile->id));
|
||||
|
||||
if ($sub) {
|
||||
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
|
||||
|
@ -213,6 +217,21 @@ class ApiAction extends Action
|
|||
}
|
||||
|
||||
function twitterStatusArray($notice, $include_user=true)
|
||||
{
|
||||
$base = $this->twitterSimpleStatusArray($notice, $include_user);
|
||||
|
||||
if (!empty($notice->repeat_of)) {
|
||||
$original = Notice::staticGet('id', $notice->repeat_of);
|
||||
if (!empty($original)) {
|
||||
$original_array = $this->twitterSimpleStatusArray($original, $include_user);
|
||||
$base['retweeted_status'] = $original_array;
|
||||
}
|
||||
}
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
function twitterSimpleStatusArray($notice, $include_user=true)
|
||||
{
|
||||
$profile = $notice->getProfile();
|
||||
|
||||
|
@ -446,9 +465,9 @@ class ApiAction extends Action
|
|||
}
|
||||
}
|
||||
|
||||
function showTwitterXmlStatus($twitter_status)
|
||||
function showTwitterXmlStatus($twitter_status, $tag='status')
|
||||
{
|
||||
$this->elementStart('status');
|
||||
$this->elementStart($tag);
|
||||
foreach($twitter_status as $element => $value) {
|
||||
switch ($element) {
|
||||
case 'user':
|
||||
|
@ -463,11 +482,14 @@ class ApiAction extends Action
|
|||
case 'geo':
|
||||
$this->showGeoRSS($value);
|
||||
break;
|
||||
case 'retweeted_status':
|
||||
$this->showTwitterXmlStatus($value, 'retweeted_status');
|
||||
break;
|
||||
default:
|
||||
$this->element($element, null, $value);
|
||||
}
|
||||
}
|
||||
$this->elementEnd('status');
|
||||
$this->elementEnd($tag);
|
||||
}
|
||||
|
||||
function showTwitterXmlGroup($twitter_group)
|
||||
|
@ -586,7 +608,7 @@ class ApiAction extends Action
|
|||
$this->endDocument('xml');
|
||||
}
|
||||
|
||||
function showRssTimeline($notice, $title, $link, $subtitle, $suplink=null)
|
||||
function showRssTimeline($notice, $title, $link, $subtitle, $suplink=null, $logo=null)
|
||||
{
|
||||
|
||||
$this->initDocument('rss');
|
||||
|
@ -600,6 +622,15 @@ class ApiAction extends Action
|
|||
'href' => $suplink,
|
||||
'type' => 'application/json'));
|
||||
}
|
||||
|
||||
if (!is_null($logo)) {
|
||||
$this->elementStart('image');
|
||||
$this->element('link', null, $link);
|
||||
$this->element('title', null, $title);
|
||||
$this->element('url', null, $logo);
|
||||
$this->elementEnd('image');
|
||||
}
|
||||
|
||||
$this->element('description', null, $subtitle);
|
||||
$this->element('language', null, 'en-us');
|
||||
$this->element('ttl', null, '40');
|
||||
|
@ -619,7 +650,7 @@ class ApiAction extends Action
|
|||
$this->endTwitterRss();
|
||||
}
|
||||
|
||||
function showAtomTimeline($notice, $title, $id, $link, $subtitle=null, $suplink=null, $selfuri=null)
|
||||
function showAtomTimeline($notice, $title, $id, $link, $subtitle=null, $suplink=null, $selfuri=null, $logo=null)
|
||||
{
|
||||
|
||||
$this->initDocument('atom');
|
||||
|
@ -628,6 +659,10 @@ class ApiAction extends Action
|
|||
$this->element('id', null, $id);
|
||||
$this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null);
|
||||
|
||||
if (!is_null($logo)) {
|
||||
$this->element('logo',null,$logo);
|
||||
}
|
||||
|
||||
if (!is_null($suplink)) {
|
||||
# For FriendFeed's SUP protocol
|
||||
$this->element('link', array('rel' => 'http://api.friendfeed.com/2008/03#sup',
|
||||
|
|
|
@ -53,8 +53,6 @@ require_once INSTALLDIR . '/lib/api.php';
|
|||
class ApiAuthAction extends ApiAction
|
||||
{
|
||||
|
||||
var $auth_user = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running, and output basic auth header if needed
|
||||
*
|
||||
|
|
|
@ -372,6 +372,7 @@ class MessageCommand extends Command
|
|||
}
|
||||
$message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source());
|
||||
if ($message) {
|
||||
$message->notify();
|
||||
$channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other));
|
||||
} else {
|
||||
$channel->error($this->user, _('Error sending direct message.'));
|
||||
|
@ -379,6 +380,65 @@ class MessageCommand extends Command
|
|||
}
|
||||
}
|
||||
|
||||
class RepeatCommand extends Command
|
||||
{
|
||||
var $other = null;
|
||||
function __construct($user, $other)
|
||||
{
|
||||
parent::__construct($user);
|
||||
$this->other = $other;
|
||||
}
|
||||
|
||||
function execute($channel)
|
||||
{
|
||||
if(substr($this->other,0,1)=='#'){
|
||||
//repeating a specific notice_id
|
||||
|
||||
$notice = Notice::staticGet(substr($this->other,1));
|
||||
if (!$notice) {
|
||||
$channel->error($this->user, _('Notice with that id does not exist'));
|
||||
return;
|
||||
}
|
||||
$recipient = $notice->getProfile();
|
||||
}else{
|
||||
//repeating a given user's last notice
|
||||
|
||||
$recipient =
|
||||
common_relative_profile($this->user, common_canonical_nickname($this->other));
|
||||
|
||||
if (!$recipient) {
|
||||
$channel->error($this->user, _('No such user.'));
|
||||
return;
|
||||
}
|
||||
$notice = $recipient->getCurrentNotice();
|
||||
if (!$notice) {
|
||||
$channel->error($this->user, _('User has no last notice'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->user->id == $notice->profile_id)
|
||||
{
|
||||
$channel->error($this->user, _('Cannot repeat your own notice'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($recipient->hasRepeated($notice->id)) {
|
||||
$channel->error($this->user, _('Already repeated that notice'));
|
||||
return;
|
||||
}
|
||||
|
||||
$repeat = $notice->repeat($this->user->id, $channel->source);
|
||||
|
||||
if ($repeat) {
|
||||
common_broadcast_notice($repeat);
|
||||
$channel->output($this->user, sprintf(_('Notice from %s repeated'), $recipient->nickname));
|
||||
} else {
|
||||
$channel->error($this->user, _('Error repeating notice.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ReplyCommand extends Command
|
||||
{
|
||||
var $other = null;
|
||||
|
@ -433,8 +493,9 @@ class ReplyCommand extends Command
|
|||
return;
|
||||
}
|
||||
|
||||
$notice = Notice::saveNew($this->user->id, $this->text, $channel->source(), 1,
|
||||
$notice->id);
|
||||
$notice = Notice::saveNew($this->user->id, $this->text, $channel->source(),
|
||||
array('reply_to' => $notice->id));
|
||||
|
||||
if ($notice) {
|
||||
$channel->output($this->user, sprintf(_('Reply to %s sent'), $recipient->nickname));
|
||||
} else {
|
||||
|
@ -695,6 +756,8 @@ class HelpCommand extends Command
|
|||
"whois <nickname> - get profile info on user\n".
|
||||
"fav <nickname> - add user's last notice as a 'fave'\n".
|
||||
"fav #<notice_id> - add notice with the given id as a 'fave'\n".
|
||||
"repeat #<notice_id> - repeat a notice with a given id\n".
|
||||
"repeat <nickname> - repeat the last notice from user\n".
|
||||
"reply #<notice_id> - reply to notice with a given id\n".
|
||||
"reply <nickname> - reply to the last notice from user\n".
|
||||
"join <group> - join group\n".
|
||||
|
|
|
@ -169,6 +169,19 @@ class CommandInterpreter
|
|||
} else {
|
||||
return new ReplyCommand($user, $other, $extra);
|
||||
}
|
||||
case 'repeat':
|
||||
case 'rp':
|
||||
case 'rt':
|
||||
case 'rd':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new RepeatCommand($user, $other);
|
||||
}
|
||||
case 'whois':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
|
|
|
@ -229,4 +229,6 @@ $default =
|
|||
array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth
|
||||
'omb' =>
|
||||
array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates
|
||||
'logincommand' =>
|
||||
array('disabled' => true),
|
||||
);
|
||||
|
|
|
@ -272,6 +272,7 @@ function get_nice_language_list()
|
|||
function get_all_languages() {
|
||||
return array(
|
||||
'ar' => array('q' => 0.8, 'lang' => 'ar', 'name' => 'Arabic', 'direction' => 'rtl'),
|
||||
'arz' => array('q' => 0.8, 'lang' => 'arz', 'name' => 'Egyptian Spoken Arabic', 'direction' => 'rtl'),
|
||||
'bg' => array('q' => 0.8, 'lang' => 'bg', 'name' => 'Bulgarian', 'direction' => 'ltr'),
|
||||
'ca' => array('q' => 0.5, 'lang' => 'ca', 'name' => 'Catalan', 'direction' => 'ltr'),
|
||||
'cs' => array('q' => 0.5, 'lang' => 'cs', 'name' => 'Czech', 'direction' => 'ltr'),
|
||||
|
@ -286,6 +287,7 @@ function get_all_languages() {
|
|||
'ga' => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Galician', 'direction' => 'ltr'),
|
||||
'he' => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'),
|
||||
'hsb' => array('q' => 0.8, 'lang' => 'hsb', 'name' => 'Upper Sorbian', 'direction' => 'ltr'),
|
||||
'ia' => array('q' => 0.8, 'lang' => 'ia', 'name' => 'Interlingua', 'direction' => 'ltr'),
|
||||
'is' => array('q' => 0.1, 'lang' => 'is', 'name' => 'Icelandic', 'direction' => 'ltr'),
|
||||
'it' => array('q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'),
|
||||
'jp' => array('q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', 'direction' => 'ltr'),
|
||||
|
|
|
@ -147,6 +147,10 @@ class NoticeListItem extends Widget
|
|||
|
||||
var $notice = null;
|
||||
|
||||
/** The notice that was repeated. */
|
||||
|
||||
var $repeat = null;
|
||||
|
||||
/** The profile of the author of the notice, extracted once for convenience. */
|
||||
|
||||
var $profile = null;
|
||||
|
@ -162,8 +166,18 @@ class NoticeListItem extends Widget
|
|||
function __construct($notice, $out=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
$this->notice = $notice;
|
||||
$this->profile = $notice->getProfile();
|
||||
if (!empty($notice->repeat_of)) {
|
||||
$original = Notice::staticGet('id', $notice->repeat_of);
|
||||
if (empty($original)) { // could have been deleted
|
||||
$this->notice = $notice;
|
||||
} else {
|
||||
$this->notice = $original;
|
||||
$this->repeat = $notice;
|
||||
}
|
||||
} else {
|
||||
$this->notice = $notice;
|
||||
}
|
||||
$this->profile = $this->notice->getProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,6 +216,7 @@ class NoticeListItem extends Widget
|
|||
$this->showNoticeSource();
|
||||
$this->showNoticeLocation();
|
||||
$this->showContext();
|
||||
$this->showRepeat();
|
||||
$this->out->elementEnd('div');
|
||||
}
|
||||
|
||||
|
@ -212,6 +227,7 @@ class NoticeListItem extends Widget
|
|||
$this->out->elementStart('div', 'notice-options');
|
||||
$this->showFaveForm();
|
||||
$this->showReplyLink();
|
||||
$this->showRepeatForm();
|
||||
$this->showDeleteLink();
|
||||
$this->out->elementEnd('div');
|
||||
}
|
||||
|
@ -227,8 +243,9 @@ class NoticeListItem extends Widget
|
|||
{
|
||||
// XXX: RDFa
|
||||
// TODO: add notice_type class e.g., notice_video, notice_image
|
||||
$id = (empty($this->repeat)) ? $this->notice->id : $this->repeat->id;
|
||||
$this->out->elementStart('li', array('class' => 'hentry notice',
|
||||
'id' => 'notice-' . $this->notice->id));
|
||||
'id' => 'notice-' . $id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -507,6 +524,40 @@ class NoticeListItem extends Widget
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show a link to the author of repeat
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showRepeat()
|
||||
{
|
||||
if (!empty($this->repeat)) {
|
||||
|
||||
$repeater = Profile::staticGet('id', $this->repeat->profile_id);
|
||||
|
||||
$attrs = array('href' => $repeater->profileurl,
|
||||
'class' => 'url');
|
||||
|
||||
if (!empty($repeater->fullname)) {
|
||||
$attrs['title'] = $repeater->fullname . ' (' . $repeater->nickname . ')';
|
||||
}
|
||||
|
||||
$this->out->elementStart('span', 'repeat vcard');
|
||||
|
||||
$this->out->raw(_('Repeated by'));
|
||||
|
||||
$avatar = $repeater->getAvatar(AVATAR_MINI_SIZE);
|
||||
|
||||
$this->out->elementStart('a', $attrs);
|
||||
|
||||
$this->out->element('span', 'nickname', $repeater->nickname);
|
||||
$this->out->elementEnd('a');
|
||||
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show a link to reply to the current notice
|
||||
*
|
||||
|
@ -540,17 +591,41 @@ class NoticeListItem extends Widget
|
|||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$todel = (empty($this->repeat)) ? $this->notice : $this->repeat;
|
||||
|
||||
if (!empty($user) &&
|
||||
($this->notice->profile_id == $user->id || $user->hasRight(Right::DELETEOTHERSNOTICE))) {
|
||||
($todel->profile_id == $user->id || $user->hasRight(Right::DELETEOTHERSNOTICE))) {
|
||||
|
||||
$deleteurl = common_local_url('deletenotice',
|
||||
array('notice' => $this->notice->id));
|
||||
array('notice' => $todel->id));
|
||||
$this->out->element('a', array('href' => $deleteurl,
|
||||
'class' => 'notice_delete',
|
||||
'title' => _('Delete this notice')), _('Delete'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show the form to repeat a notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showRepeatForm()
|
||||
{
|
||||
$user = common_current_user();
|
||||
if ($user && $user->id != $this->notice->profile_id) {
|
||||
$profile = $user->getProfile();
|
||||
if ($profile->hasRepeated($this->notice->id)) {
|
||||
$this->out->element('span', array('class' => 'repeated',
|
||||
'title' => _('Notice repeated')),
|
||||
_('Repeated'));
|
||||
} else {
|
||||
$rf = new RepeatForm($this->out, $this->notice);
|
||||
$rf->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* finish the notice
|
||||
*
|
||||
|
|
|
@ -359,9 +359,8 @@ class StatusNetOAuthDataStore extends OAuthDataStore
|
|||
$notice = Notice::saveNew($author->id,
|
||||
$omb_notice->getContent(),
|
||||
'omb',
|
||||
false,
|
||||
null,
|
||||
$omb_notice->getIdentifierURI());
|
||||
array('is_local' => Notice::REMOTE_OMB,
|
||||
'uri' => $omb_notice->getIdentifierURI()));
|
||||
|
||||
common_broadcast_notice($notice, true);
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ class ProfileFormAction extends Action
|
|||
if ($action) {
|
||||
common_redirect(common_local_url($action, $args), 303);
|
||||
} else {
|
||||
$this->clientError(_("No return-to arguments"));
|
||||
$this->clientError(_("No return-to arguments."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,6 +134,6 @@ class ProfileFormAction extends Action
|
|||
|
||||
function handlePost()
|
||||
{
|
||||
$this->serverError(_("unimplemented method"));
|
||||
$this->serverError(_("Unimplemented method."));
|
||||
}
|
||||
}
|
||||
|
|
145
lib/repeatform.php
Normal file
145
lib/repeatform.php
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for repeating a notice
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Form
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form for repeating a notice
|
||||
*
|
||||
* @category Form
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class RepeatForm extends Form
|
||||
{
|
||||
/**
|
||||
* Notice to repeat
|
||||
*/
|
||||
|
||||
var $notice = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param HTMLOutputter $out output channel
|
||||
* @param Notice $notice notice to repeat
|
||||
*/
|
||||
|
||||
function __construct($out=null, $notice=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->notice = $notice;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return int ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'repeat-' . $this->notice->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('repeat');
|
||||
}
|
||||
|
||||
/**
|
||||
* Include a session token for CSRF protection
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function sessionToken()
|
||||
{
|
||||
$this->out->hidden('token-' . $this->notice->id,
|
||||
common_session_token());
|
||||
}
|
||||
|
||||
/**
|
||||
* Legend of the Form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function formLegend()
|
||||
{
|
||||
$this->out->element('legend', null, _('Repeat this notice'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$this->out->hidden('notice-n'.$this->notice->id,
|
||||
$this->notice->id,
|
||||
'notice');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('repeat-submit-' . $this->notice->id,
|
||||
_('Repeat'), 'submit', null, _('Repeat this notice'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Class of the form.
|
||||
*
|
||||
* @return string the form's class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_repeat';
|
||||
}
|
||||
}
|
|
@ -99,6 +99,7 @@ class Router
|
|||
'groupblock', 'groupunblock',
|
||||
'sandbox', 'unsandbox',
|
||||
'silence', 'unsilence',
|
||||
'repeat',
|
||||
'deleteuser');
|
||||
|
||||
foreach ($main as $a) {
|
||||
|
@ -282,12 +283,13 @@ class Router
|
|||
array('action' => 'ApiTimelineFriends',
|
||||
'id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json|rss|atom)'));
|
||||
|
||||
$m->connect('api/statuses/home_timeline.:format',
|
||||
array('action' => 'ApiTimelineFriends',
|
||||
array('action' => 'ApiTimelineHome',
|
||||
'format' => '(xml|json|rss|atom)'));
|
||||
|
||||
$m->connect('api/statuses/home_timeline/:id.:format',
|
||||
array('action' => 'ApiTimelineFriends',
|
||||
array('action' => 'ApiTimelineHome',
|
||||
'id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json|rss|atom)'));
|
||||
|
||||
|
@ -318,6 +320,18 @@ class Router
|
|||
'id' => '[a-zA-Z0-9]+',
|
||||
'format' => '(xml|json|rss|atom)'));
|
||||
|
||||
$m->connect('api/statuses/retweeted_by_me.:format',
|
||||
array('action' => 'ApiTimelineRetweetedByMe',
|
||||
'format' => '(xml|json|atom)'));
|
||||
|
||||
$m->connect('api/statuses/retweeted_to_me.:format',
|
||||
array('action' => 'ApiTimelineRetweetedToMe',
|
||||
'format' => '(xml|json|atom)'));
|
||||
|
||||
$m->connect('api/statuses/retweets_of_me.:format',
|
||||
array('action' => 'ApiTimelineRetweetsOfMe',
|
||||
'format' => '(xml|json|atom)'));
|
||||
|
||||
$m->connect('api/statuses/friends.:format',
|
||||
array('action' => 'ApiUserFriends',
|
||||
'format' => '(xml|json)'));
|
||||
|
@ -358,6 +372,16 @@ class Router
|
|||
'id' => '[0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/statuses/retweet/:id.:format',
|
||||
array('action' => 'ApiStatusesRetweet',
|
||||
'id' => '[0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
$m->connect('api/statuses/retweets/:id.:format',
|
||||
array('action' => 'ApiStatusesRetweets',
|
||||
'id' => '[0-9]+',
|
||||
'format' => '(xml|json)'));
|
||||
|
||||
// users
|
||||
|
||||
$m->connect('api/users/show.:format',
|
||||
|
|
File diff suppressed because it is too large
Load Diff
5326
locale/arz/LC_MESSAGES/statusnet.po
Normal file
5326
locale/arz/LC_MESSAGES/statusnet.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
5402
locale/ia/LC_MESSAGES/statusnet.po
Normal file
5402
locale/ia/LC_MESSAGES/statusnet.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -445,8 +445,9 @@ class FacebookAction extends Action
|
|||
$replyto = $this->trimmed('inreplyto');
|
||||
|
||||
try {
|
||||
$notice = Notice::saveNew($user->id, $content,
|
||||
'web', 1, ($replyto == 'false') ? null : $replyto);
|
||||
$notice = Notice::saveNew($user->id, $content, 'web',
|
||||
array('reply_to' => ($replyto == 'false') ? null : $replyto));
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->showPage($e->getMessage());
|
||||
return;
|
||||
|
|
61
plugins/Gravatar/locale/Gravatar.po
Normal file
61
plugins/Gravatar/locale/Gravatar.po
Normal file
|
@ -0,0 +1,61 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-12-11 16:27-0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: GravatarPlugin.php:57
|
||||
msgid "Set Gravatar"
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:60
|
||||
msgid "If you want to use your Gravatar image, click \"Add\"."
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:65
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:75
|
||||
msgid "Remove Gravatar"
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:78
|
||||
msgid "If you want to remove your Gravatar image, click \"Remove\"."
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:83
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:88
|
||||
msgid "To use a Gravatar first enter in an email address."
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:137
|
||||
msgid "You do not have a email set in your profile."
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:155
|
||||
msgid "Failed to save Gravatar to the DB."
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:159
|
||||
msgid "Gravatar added."
|
||||
msgstr ""
|
||||
|
||||
#: GravatarPlugin.php:177
|
||||
msgid "Gravatar removed."
|
||||
msgstr ""
|
|
@ -103,7 +103,7 @@ class OpenidserverAction extends Action
|
|||
$response = $this->generateDenyResponse($request);
|
||||
} else {
|
||||
//invalid
|
||||
$this->clientError(sprintf(_m('You are not authorized to use the identity %s'),$request->identity),$code=403);
|
||||
$this->clientError(sprintf(_m('You are not authorized to use the identity %s.'),$request->identity),$code=403);
|
||||
}
|
||||
} else {
|
||||
$response = $this->oserver->handleRequest($request);
|
||||
|
|
|
@ -59,6 +59,7 @@ class RealtimePlugin extends Plugin
|
|||
{
|
||||
$this->replyurl = common_local_url('newnotice');
|
||||
$this->favorurl = common_local_url('favor');
|
||||
$this->repeaturl = common_local_url('repeat');
|
||||
// FIXME: need to find a better way to pass this pattern in
|
||||
$this->deleteurl = common_local_url('deletenotice',
|
||||
array('notice' => '0000000000'));
|
||||
|
@ -266,6 +267,24 @@ class RealtimePlugin extends Plugin
|
|||
$profile = $notice->getProfile();
|
||||
$arr['user']['profile_url'] = $profile->profileurl;
|
||||
|
||||
// Add needed repeat data
|
||||
|
||||
if (!empty($notice->repeat_of)) {
|
||||
$original = Notice::staticGet('id', $notice->repeat_of);
|
||||
if (!empty($original)) {
|
||||
$arr['retweeted_status']['url'] = $original->bestUrl();
|
||||
$arr['retweeted_status']['html'] = htmlspecialchars($original->rendered);
|
||||
$arr['retweeted_status']['source'] = htmlspecialchars($original->source);
|
||||
$originalProfile = $original->getProfile();
|
||||
$arr['retweeted_status']['user']['profile_url'] = $originalProfile->profileurl;
|
||||
if (!empty($original->reply_to)) {
|
||||
$originalReply = Notice::staticGet('id', $original->reply_to);
|
||||
$arr['retweeted_status']['in_reply_to_status_url'] = $originalReply->bestUrl();
|
||||
}
|
||||
}
|
||||
$original = null;
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
|
@ -297,7 +316,7 @@ class RealtimePlugin extends Plugin
|
|||
|
||||
function _updateInitialize($timeline, $user_id)
|
||||
{
|
||||
return "RealtimeUpdate.init($user_id, \"$this->replyurl\", \"$this->favorurl\", \"$this->deleteurl\"); ";
|
||||
return "RealtimeUpdate.init($user_id, \"$this->replyurl\", \"$this->favorurl\", \"$this->repeaturl\", \"$this->deleteurl\"); ";
|
||||
}
|
||||
|
||||
function _connect()
|
||||
|
|
|
@ -32,6 +32,7 @@ RealtimeUpdate = {
|
|||
_userid: 0,
|
||||
_replyurl: '',
|
||||
_favorurl: '',
|
||||
_repeaturl: '',
|
||||
_deleteurl: '',
|
||||
_updatecounter: 0,
|
||||
_maxnotices: 50,
|
||||
|
@ -40,11 +41,12 @@ RealtimeUpdate = {
|
|||
_paused:false,
|
||||
_queuedNotices:[],
|
||||
|
||||
init: function(userid, replyurl, favorurl, deleteurl)
|
||||
init: function(userid, replyurl, favorurl, repeaturl, deleteurl)
|
||||
{
|
||||
RealtimeUpdate._userid = userid;
|
||||
RealtimeUpdate._replyurl = replyurl;
|
||||
RealtimeUpdate._favorurl = favorurl;
|
||||
RealtimeUpdate._repeaturl = repeaturl;
|
||||
RealtimeUpdate._deleteurl = deleteurl;
|
||||
|
||||
RealtimeUpdate._documenttitle = document.title;
|
||||
|
@ -95,6 +97,7 @@ RealtimeUpdate = {
|
|||
|
||||
SN.U.FormXHR($('#'+noticeItemID+' .form_favor'));
|
||||
SN.U.NoticeReplyTo($('#'+noticeItemID));
|
||||
SN.U.FormXHR($('#'+noticeItemID+' .form_repeat'));
|
||||
SN.U.NoticeWithAttachment($('#'+noticeItemID));
|
||||
},
|
||||
|
||||
|
@ -113,11 +116,24 @@ RealtimeUpdate = {
|
|||
|
||||
makeNoticeItem: function(data)
|
||||
{
|
||||
if (data.hasOwnProperty('retweeted_status')) {
|
||||
original = data['retweeted_status'];
|
||||
repeat = data;
|
||||
data = original;
|
||||
unique = repeat['id'];
|
||||
responsible = repeat['user'];
|
||||
} else {
|
||||
original = null;
|
||||
repeat = null;
|
||||
unique = data['id'];
|
||||
responsible = data['user'];
|
||||
}
|
||||
|
||||
user = data['user'];
|
||||
html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
|
||||
ni = "<li class=\"hentry notice\" id=\"notice-"+data['id']+"\">"+
|
||||
ni = "<li class=\"hentry notice\" id=\"notice-"+unique+"\">"+
|
||||
"<div class=\"entry-title\">"+
|
||||
"<span class=\"vcard author\">"+
|
||||
"<a href=\""+user['profile_url']+"\" class=\"url\">"+
|
||||
|
@ -139,20 +155,31 @@ RealtimeUpdate = {
|
|||
ni = ni+" <a class=\"response\" href=\""+data['in_reply_to_status_url']+"\">in context</a>";
|
||||
}
|
||||
|
||||
ni = ni+"</div>"+
|
||||
"<div class=\"notice-options\">";
|
||||
if (repeat) {
|
||||
ru = repeat['user'];
|
||||
ni = ni + "<span class=\"repeat vcard\">Repeated by " +
|
||||
"<a href=\"" + ru['profile_url'] + "\" class=\"url\">" +
|
||||
"<span class=\"nickname\">"+ ru['screen_name'] + "</span></a></span>";
|
||||
}
|
||||
|
||||
ni = ni+"</div>";
|
||||
|
||||
ni = ni + "<div class=\"notice-options\">";
|
||||
|
||||
if (RealtimeUpdate._userid != 0) {
|
||||
var input = $("form#form_notice fieldset input#token");
|
||||
var session_key = input.val();
|
||||
ni = ni+RealtimeUpdate.makeFavoriteForm(data['id'], session_key);
|
||||
ni = ni+RealtimeUpdate.makeReplyLink(data['id'], data['user']['screen_name']);
|
||||
if (RealtimeUpdate._userid == data['user']['id']) {
|
||||
if (RealtimeUpdate._userid == responsible['id']) {
|
||||
ni = ni+RealtimeUpdate.makeDeleteLink(data['id']);
|
||||
} else if (RealtimeUpdate._userid != user['id']) {
|
||||
ni = ni+RealtimeUpdate.makeRepeatForm(data['id'], session_key);
|
||||
}
|
||||
}
|
||||
|
||||
ni = ni+"</div>"+
|
||||
ni = ni+"</div>";
|
||||
|
||||
"</li>";
|
||||
return ni;
|
||||
},
|
||||
|
@ -177,7 +204,22 @@ RealtimeUpdate = {
|
|||
var rl;
|
||||
rl = "<a class=\"notice_reply\" href=\""+RealtimeUpdate._replyurl+"?replyto="+nickname+"\" title=\"Reply to this notice\">Reply <span class=\"notice_id\">"+id+"</span></a>";
|
||||
return rl;
|
||||
},
|
||||
},
|
||||
|
||||
makeRepeatForm: function(id, session_key)
|
||||
{
|
||||
var rf;
|
||||
rf = "<form id=\"repeat-"+id+"\" class=\"form_repeat\" method=\"post\" action=\""+RealtimeUpdate._repeaturl+"\">"+
|
||||
"<fieldset>"+
|
||||
"<legend>Favor this notice</legend>"+
|
||||
"<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
|
||||
"<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
|
||||
"<input type=\"submit\" id=\"repeat-submit-"+id+"\" name=\"repeat-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Repeat this notice\"/>"+
|
||||
"</fieldset>"+
|
||||
"</form>";
|
||||
|
||||
return rf;
|
||||
},
|
||||
|
||||
makeDeleteLink: function(id)
|
||||
{
|
||||
|
|
|
@ -300,7 +300,7 @@ class TemplateAction extends Action
|
|||
|
||||
// verify that user is admin
|
||||
if (!($user->id == 1))
|
||||
$this->clientError(_('only User #1 can update the template'), $code = 401);
|
||||
$this->clientError(_('Only User #1 can update the template.'), $code = 401);
|
||||
|
||||
// open the old template
|
||||
$tpl_file = $this->templateFolder() . '/index.html';
|
||||
|
|
|
@ -179,7 +179,7 @@ function broadcast_oauth($notice, $flink) {
|
|||
try {
|
||||
$status = $client->statusesUpdate($statustxt);
|
||||
} catch (OAuthClientException $e) {
|
||||
return process_error($e, $flink);
|
||||
return process_error($e, $flink, $notice);
|
||||
}
|
||||
|
||||
if (empty($status)) {
|
||||
|
@ -188,8 +188,11 @@ function broadcast_oauth($notice, $flink) {
|
|||
// or the Twitter API might just be behaving flakey.
|
||||
|
||||
$errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' .
|
||||
'trying to send update for %1$s (user id %2$s).',
|
||||
$user->nickname, $user->id);
|
||||
'trying to post notice %d for User %s (user id %d).',
|
||||
$notice->id,
|
||||
$user->nickname,
|
||||
$user->id);
|
||||
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
|
||||
return false;
|
||||
|
@ -197,8 +200,12 @@ function broadcast_oauth($notice, $flink) {
|
|||
|
||||
// Notice crossed the great divide
|
||||
|
||||
$msg = sprintf('Twitter bridge - posted notice %s to Twitter using OAuth.',
|
||||
$notice->id);
|
||||
$msg = sprintf('Twitter bridge - posted notice %d to Twitter using ' .
|
||||
'OAuth for User %s (user id %d).',
|
||||
$notice->id,
|
||||
$user->nickname,
|
||||
$user->id);
|
||||
|
||||
common_log(LOG_INFO, $msg);
|
||||
|
||||
return true;
|
||||
|
@ -215,62 +222,69 @@ function broadcast_basicauth($notice, $flink)
|
|||
|
||||
try {
|
||||
$status = $client->statusesUpdate($statustxt);
|
||||
} catch (HTTP_Request2_Exception $e) {
|
||||
return process_error($e, $flink);
|
||||
} catch (BasicAuthException $e) {
|
||||
return process_error($e, $flink, $notice);
|
||||
}
|
||||
|
||||
if (empty($status)) {
|
||||
|
||||
$errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' .
|
||||
'trying to send update for %1$s (user id %2$s).',
|
||||
$user->nickname, $user->id);
|
||||
'trying to post notice %d for %s (user id %d).',
|
||||
$notice->id,
|
||||
$user->nickname,
|
||||
$user->id);
|
||||
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
|
||||
$errmsg = sprintf('No data returned by Twitter API when ' .
|
||||
'trying to send update for %1$s (user id %2$s).',
|
||||
$user->nickname, $user->id);
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
$errmsg = sprintf('No data returned by Twitter API when ' .
|
||||
'trying to post notice %d for %s (user id %d).',
|
||||
$notice->id,
|
||||
$user->nickname,
|
||||
$user->id);
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
$msg = sprintf('Twitter bridge - posted notice %s to Twitter using basic auth.',
|
||||
$notice->id);
|
||||
$msg = sprintf('Twitter bridge - posted notice %d to Twitter using ' .
|
||||
'HTTP basic auth for User %s (user id %d).',
|
||||
$notice->id,
|
||||
$user->nickname,
|
||||
$user->id);
|
||||
|
||||
common_log(LOG_INFO, $msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function process_error($e, $flink)
|
||||
function process_error($e, $flink, $notice)
|
||||
{
|
||||
$user = $flink->getUser();
|
||||
$errmsg = $e->getMessage();
|
||||
$delivered = false;
|
||||
$user = $flink->getUser();
|
||||
$code = $e->getCode();
|
||||
|
||||
switch($errmsg) {
|
||||
case 'The requested URL returned error: 401':
|
||||
$logmsg = sprintf('Twiter bridge - User %1$s (user id: %2$s) has an invalid ' .
|
||||
'Twitter screen_name/password combo or an invalid acesss token.',
|
||||
$user->nickname, $user->id);
|
||||
$delivered = true;
|
||||
remove_twitter_link($flink);
|
||||
break;
|
||||
case 'The requested URL returned error: 403':
|
||||
$logmsg = sprintf('Twitter bridge - User %1$s (user id: %2$s) has exceeded ' .
|
||||
'his/her Twitter request limit.',
|
||||
$user->nickname, $user->id);
|
||||
break;
|
||||
default:
|
||||
$logmsg = sprintf('Twitter bridge - cURL error trying to send notice to Twitter ' .
|
||||
'for user %1$s (user id: %2$s) - ' .
|
||||
'code: %3$s message: %4$s.',
|
||||
$user->nickname, $user->id,
|
||||
$e->getCode(), $e->getMessage());
|
||||
break;
|
||||
}
|
||||
$logmsg = sprintf('Twitter bridge - %d posting notice %d for ' .
|
||||
'User %s (user id: %d): %s.',
|
||||
$code,
|
||||
$notice->id,
|
||||
$user->nickname,
|
||||
$user->id,
|
||||
$e->getMessage());
|
||||
|
||||
common_log(LOG_WARNING, $logmsg);
|
||||
|
||||
return $delivered;
|
||||
if ($code == 401) {
|
||||
|
||||
// Probably a revoked or otherwise bad access token - nuke!
|
||||
|
||||
remove_twitter_link($flink);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
// For every other case, it's probably some flakiness so try
|
||||
// sending the notice again later (requeue).
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function format_status($notice)
|
||||
|
|
|
@ -31,6 +31,20 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* General Exception wrapper for HTTP basic auth errors
|
||||
*
|
||||
* @category Integration
|
||||
* @package StatusNet
|
||||
* @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 BasicAuthException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for talking to the Twitter API with HTTP Basic Auth.
|
||||
*
|
||||
|
@ -169,12 +183,13 @@ class TwitterBasicAuthClient
|
|||
}
|
||||
|
||||
/**
|
||||
* Make a HTTP request using cURL.
|
||||
* Make an HTTP request
|
||||
*
|
||||
* @param string $url Where to make the request
|
||||
* @param array $params post parameters
|
||||
*
|
||||
* @return mixed the request
|
||||
* @throws BasicAuthException
|
||||
*/
|
||||
function httpRequest($url, $params = null, $auth = true)
|
||||
{
|
||||
|
@ -199,6 +214,12 @@ class TwitterBasicAuthClient
|
|||
$response = $request->get($url);
|
||||
}
|
||||
|
||||
$code = $response->getStatus();
|
||||
|
||||
if ($code < 200 || $code >= 400) {
|
||||
throw new BasicAuthException($response->getBody(), $code);
|
||||
}
|
||||
|
||||
return $response->getBody();
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ function read_input_line($prompt)
|
|||
*/
|
||||
function readline_emulation($prompt)
|
||||
{
|
||||
if(file_exists(trim(shell_exec('which bash')))) {
|
||||
if(CONSOLE_INTERACTIVE && file_exists(trim(shell_exec('which bash')))) {
|
||||
$encPrompt = escapeshellarg($prompt);
|
||||
$command = "read -er -p $encPrompt && echo \"\$REPLY\"";
|
||||
$encCommand = escapeshellarg($command);
|
||||
|
@ -103,7 +103,9 @@ function readline_emulation($prompt)
|
|||
if (feof(STDIN)) {
|
||||
return false;
|
||||
}
|
||||
print $prompt;
|
||||
if (CONSOLE_INTERACTIVE) {
|
||||
print $prompt;
|
||||
}
|
||||
return fgets(STDIN);
|
||||
}
|
||||
|
||||
|
@ -123,13 +125,16 @@ function console_help()
|
|||
print "Type ctrl+D or enter 'exit' to exit.\n";
|
||||
}
|
||||
|
||||
|
||||
print "StatusNet interactive PHP console... type ctrl+D or enter 'exit' to exit.\n";
|
||||
$prompt = common_config('site', 'name') . '> ';
|
||||
if (CONSOLE_INTERACTIVE) {
|
||||
print "StatusNet interactive PHP console... type ctrl+D or enter 'exit' to exit.\n";
|
||||
$prompt = common_config('site', 'name') . '> ';
|
||||
}
|
||||
while (!feof(STDIN)) {
|
||||
$line = read_input_line($prompt);
|
||||
if ($line === false) {
|
||||
print "\n";
|
||||
if (CONSOLE_INTERACTIVE) {
|
||||
print "\n";
|
||||
}
|
||||
break;
|
||||
} elseif ($line !== '') {
|
||||
try {
|
||||
|
@ -154,5 +159,7 @@ while (!feof(STDIN)) {
|
|||
print get_class($e) . ": " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
print "\n";
|
||||
if (CONSOLE_INTERACTIVE) {
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
|
77
scripts/useremail.php
Executable file
77
scripts/useremail.php
Executable file
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 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/>.
|
||||
*/
|
||||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||
|
||||
$shortoptions = 'i:n:e:';
|
||||
$longoptions = array('id=', 'nickname=', 'email=');
|
||||
|
||||
$helptext = <<<END_OF_USEREMAIL_HELP
|
||||
useremail.php [options]
|
||||
Queries a user's registered email address, or queries the users with a given registered email.
|
||||
|
||||
-i --id id of the user to query
|
||||
-n --nickname nickname of the user to query
|
||||
-e --email email address to query
|
||||
|
||||
END_OF_USEREMAIL_HELP;
|
||||
|
||||
require_once INSTALLDIR.'/scripts/commandline.inc';
|
||||
|
||||
if (have_option('i', 'id')) {
|
||||
$id = get_option_value('i', 'id');
|
||||
$user = User::staticGet('id', $id);
|
||||
if (empty($user)) {
|
||||
print "Can't find user with ID $id\n";
|
||||
exit(1);
|
||||
}
|
||||
} else if (have_option('n', 'nickname')) {
|
||||
$nickname = get_option_value('n', 'nickname');
|
||||
$user = User::staticGet('nickname', $nickname);
|
||||
if (empty($user)) {
|
||||
print "Can't find user with nickname '$nickname'\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($user)) {
|
||||
if (empty($user->email)) {
|
||||
print "No email registered for user '$user->nickname'\n";
|
||||
} else {
|
||||
print "$user->email\n";
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (have_option('e', 'email')) {
|
||||
$user = new User();
|
||||
$user->email = get_option_value('e', 'email');
|
||||
$user->find(false);
|
||||
if (!$user->fetch()) {
|
||||
print "No users with email $user->email\n";
|
||||
exit(0);
|
||||
}
|
||||
do {
|
||||
print "$user->id $user->nickname\n";
|
||||
} while ($user->fetch());
|
||||
} else {
|
||||
print "You must provide either an ID, email, or a nickname.\n";
|
||||
exit(1);
|
||||
}
|
|
@ -195,17 +195,6 @@ class XMPPDaemon extends Daemon
|
|||
} else if ($this->is_otr($pl['body'])) {
|
||||
$this->log(LOG_INFO, 'Ignoring OTR from ' . $from);
|
||||
return;
|
||||
} else if ($this->is_direct($pl['body'])) {
|
||||
$this->log(LOG_INFO, 'Got a direct message ' . $from);
|
||||
|
||||
preg_match_all('/d[\ ]*([a-z0-9]{1,64})/', $pl['body'], $to);
|
||||
|
||||
$to = preg_replace('/^d([\ ])*/', '', $to[0][0]);
|
||||
$body = preg_replace('/d[\ ]*('. $to .')[\ ]*/', '', $pl['body']);
|
||||
|
||||
$this->log(LOG_INFO, 'Direct message from '. $user->nickname . ' to ' . $to);
|
||||
|
||||
$this->add_direct($user, $body, $to, $from);
|
||||
} else {
|
||||
|
||||
$this->log(LOG_INFO, 'Posting a notice from ' . $user->nickname);
|
||||
|
@ -284,15 +273,6 @@ class XMPPDaemon extends Daemon
|
|||
}
|
||||
}
|
||||
|
||||
function is_direct($txt)
|
||||
{
|
||||
if (strtolower(substr($txt, 0, 2))=='d ') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function from_site($address, $msg)
|
||||
{
|
||||
$text = '['.common_config('site', 'name') . '] ' . $msg;
|
||||
|
|
|
@ -964,7 +964,7 @@ float:left;
|
|||
font-size:0.95em;
|
||||
margin-left:59px;
|
||||
min-width:60%;
|
||||
max-width:74%;
|
||||
max-width:70%;
|
||||
}
|
||||
#showstream .notice div.entry-content,
|
||||
#shownotice .notice div.entry-content {
|
||||
|
@ -982,10 +982,21 @@ font-size:1.025em;
|
|||
display:inline-block;
|
||||
}
|
||||
|
||||
.entry-content .repeat {
|
||||
display:block;
|
||||
}
|
||||
.entry-content .repeat .photo {
|
||||
float:none;
|
||||
margin-right:1px;
|
||||
position:relative;
|
||||
top:4px;
|
||||
left:0;
|
||||
}
|
||||
|
||||
.notice-options {
|
||||
position:relative;
|
||||
font-size:0.95em;
|
||||
width:90px;
|
||||
width:125px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
|
@ -994,17 +1005,20 @@ float:left;
|
|||
}
|
||||
.notice-options .notice_delete,
|
||||
.notice-options .notice_reply,
|
||||
.notice-options .form_repeat,
|
||||
.notice-options .form_favor,
|
||||
.notice-options .form_disfavor {
|
||||
.notice-options .form_disfavor,
|
||||
.notice-options .repeated {
|
||||
float:left;
|
||||
margin-left:20%;
|
||||
margin-left:14%;
|
||||
}
|
||||
.notice-options .form_favor,
|
||||
.notice-options .form_disfavor {
|
||||
margin-left:0;
|
||||
}
|
||||
.notice-options input,
|
||||
.notice-options a {
|
||||
.notice-options a,
|
||||
.notice-options .repeated {
|
||||
text-indent:-9999px;
|
||||
outline:none;
|
||||
}
|
||||
|
@ -1024,16 +1038,19 @@ border-radius:0;
|
|||
-moz-border-radius:0;
|
||||
-webkit-border-radius:0;
|
||||
}
|
||||
.notice-options .form_repeat legend,
|
||||
.notice-options .form_favor legend,
|
||||
.notice-options .form_disfavor legend {
|
||||
display:none;
|
||||
}
|
||||
.notice-options .form_repeat fieldset,
|
||||
.notice-options .form_favor fieldset,
|
||||
.notice-options .form_disfavor fieldset {
|
||||
border:0;
|
||||
padding:0;
|
||||
}
|
||||
.notice-options a {
|
||||
.notice-options a,
|
||||
.notice-options .repeated {
|
||||
width:16px;
|
||||
height:16px;
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.1 KiB |
BIN
theme/base/images/icons/twotone/green/recycle-02.gif
Normal file
BIN
theme/base/images/icons/twotone/green/recycle-02.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 B |
BIN
theme/base/images/icons/twotone/green/recycle.gif
Normal file
BIN
theme/base/images/icons/twotone/green/recycle.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 B |
|
@ -160,6 +160,7 @@ opacity:0;
|
|||
.notice-options form.form_favor input.submit,
|
||||
.notice-options form.form_disfavor input.submit,
|
||||
.notice-options .notice_delete,
|
||||
.notice-options form.form_repeat input.submit,
|
||||
#new_group a,
|
||||
.pagination .nav_prev a,
|
||||
.pagination .nav_next a,
|
||||
|
@ -172,7 +173,8 @@ button.close,
|
|||
.entity_moderation p,
|
||||
.entity_sandbox input.submit,
|
||||
.entity_silence input.submit,
|
||||
.entity_delete input.submit {
|
||||
.entity_delete input.submit,
|
||||
.notice-options .repeated {
|
||||
background-image:url(../../base/images/icons/icons-01.gif);
|
||||
background-repeat:no-repeat;
|
||||
background-color:transparent;
|
||||
|
@ -334,6 +336,12 @@ background-position:0 -526px;
|
|||
.notice-options .notice_delete {
|
||||
background-position:0 -658px;
|
||||
}
|
||||
.notice-options form.form_repeat input.submit {
|
||||
background-position:0 -1582px;
|
||||
}
|
||||
.notice-options .repeated {
|
||||
background-position:0 -1648px;
|
||||
}
|
||||
|
||||
.notices div.entry-content,
|
||||
.notices div.notice-options {
|
||||
|
|
|
@ -160,6 +160,7 @@ opacity:0;
|
|||
.notice-options form.form_favor input.submit,
|
||||
.notice-options form.form_disfavor input.submit,
|
||||
.notice-options .notice_delete,
|
||||
.notice-options form.form_repeat input.submit,
|
||||
#new_group a,
|
||||
.pagination .nav_prev a,
|
||||
.pagination .nav_next a,
|
||||
|
@ -172,7 +173,8 @@ button.close,
|
|||
.entity_moderation p,
|
||||
.entity_sandbox input.submit,
|
||||
.entity_silence input.submit,
|
||||
.entity_delete input.submit {
|
||||
.entity_delete input.submit,
|
||||
.notice-options .repeated {
|
||||
background-image:url(../../base/images/icons/icons-01.gif);
|
||||
background-repeat:no-repeat;
|
||||
background-color:transparent;
|
||||
|
@ -333,6 +335,12 @@ background-position:0 -526px;
|
|||
.notice-options .notice_delete {
|
||||
background-position:0 -658px;
|
||||
}
|
||||
.notice-options form.form_repeat input.submit {
|
||||
background-position:0 -1582px;
|
||||
}
|
||||
.notice-options .repeated {
|
||||
background-position:0 -1648px;
|
||||
}
|
||||
|
||||
.notices div.entry-content,
|
||||
.notices div.notice-options {
|
||||
|
|
Loading…
Reference in New Issue
Block a user