Merge commit 'origin/0.9.x' into 0.9.x
This commit is contained in:
commit
9d3829df9d
12
EVENTS.txt
12
EVENTS.txt
@ -290,6 +290,18 @@ StartRegistrationTry: before validating and saving a new user
|
||||
EndRegistrationTry: after saving a new user (note: no profile or user object!)
|
||||
- $action: action object being shown
|
||||
|
||||
StartAvatarFormData: before displaying avatar form
|
||||
- $action: action object being shown
|
||||
|
||||
EndAvatarFormData: after displaying avatar form
|
||||
- $action: action object being shown
|
||||
|
||||
StartAvatarSaveForm: before saving the avatar
|
||||
- $action: action object being shown
|
||||
|
||||
EndAvatarSaveForm: after saving the avatar
|
||||
- $action: action object being shown
|
||||
|
||||
StartNewQueueManager: before trying to start a new queue manager; good for plugins implementing new queue manager classes
|
||||
- $qm: empty queue manager to set
|
||||
|
||||
|
@ -144,7 +144,7 @@ class AllAction extends ProfileAction
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$nl = new InboxNoticeList($this->notice, $this->user, $this);
|
||||
$nl = new NoticeList($this->notice, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
@ -168,87 +168,3 @@ class AllAction extends ProfileAction
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InboxNoticeList extends NoticeList
|
||||
{
|
||||
var $owner = null;
|
||||
|
||||
function __construct($notice, $owner, $out=null)
|
||||
{
|
||||
parent::__construct($notice, $out);
|
||||
$this->owner = $owner;
|
||||
}
|
||||
|
||||
function newListItem($notice)
|
||||
{
|
||||
return new InboxNoticeListItem($notice, $this->owner, $this->out);
|
||||
}
|
||||
}
|
||||
|
||||
class InboxNoticeListItem extends NoticeListItem
|
||||
{
|
||||
var $owner = null;
|
||||
var $ib = null;
|
||||
|
||||
function __construct($notice, $owner, $out=null)
|
||||
{
|
||||
parent::__construct($notice, $out);
|
||||
$this->owner = $owner;
|
||||
|
||||
$this->ib = Notice_inbox::pkeyGet(array('user_id' => $owner->id,
|
||||
'notice_id' => $notice->id));
|
||||
}
|
||||
|
||||
function showAuthor()
|
||||
{
|
||||
parent::showAuthor();
|
||||
if ($this->ib->source == NOTICE_INBOX_SOURCE_FORWARD) {
|
||||
$this->out->element('span', 'forward', _('Fwd'));
|
||||
}
|
||||
}
|
||||
|
||||
function showEnd()
|
||||
{
|
||||
if ($this->ib->source == NOTICE_INBOX_SOURCE_FORWARD) {
|
||||
|
||||
$forward = new Forward();
|
||||
|
||||
// FIXME: scary join!
|
||||
|
||||
$forward->query('SELECT profile_id '.
|
||||
'FROM forward JOIN subscription ON forward.profile_id = subscription.subscribed '.
|
||||
'WHERE subscription.subscriber = ' . $this->owner->id . ' '.
|
||||
'AND forward.notice_id = ' . $this->notice->id . ' '.
|
||||
'ORDER BY forward.created ');
|
||||
|
||||
$n = 0;
|
||||
|
||||
$firstForwarder = null;
|
||||
|
||||
while ($forward->fetch()) {
|
||||
if (empty($firstForwarder)) {
|
||||
$firstForwarder = Profile::staticGet('id', $forward->profile_id);
|
||||
}
|
||||
$n++;
|
||||
}
|
||||
|
||||
$forward->free();
|
||||
unset($forward);
|
||||
|
||||
$this->out->elementStart('span', 'forwards');
|
||||
|
||||
$link = XMLStringer::estring('a', array('href' => $firstForwarder->profileurl),
|
||||
$firstForwarder->nickname);
|
||||
|
||||
if ($n == 1) {
|
||||
$this->out->raw(sprintf(_('Forwarded by %s'), $link));
|
||||
} else {
|
||||
// XXX: use that cool ngettext thing
|
||||
$this->out->raw(sprintf(_('Forwarded by %s and %d other(s)'), $link, $n - 1));
|
||||
}
|
||||
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
parent::showEnd();
|
||||
}
|
||||
}
|
||||
|
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,6 +110,7 @@ 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');
|
||||
@ -121,13 +122,14 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
||||
_('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':
|
||||
|
||||
@ -144,7 +146,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
||||
|
||||
$this->showAtomTimeline(
|
||||
$this->notices, $title, $id, $link,
|
||||
$subtitle, null, $selfuri
|
||||
$subtitle, null, $selfuri, $logo
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
|
@ -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':
|
||||
|
@ -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':
|
||||
|
@ -118,53 +118,56 @@ class AvatarsettingsAction extends AccountSettingsAction
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, _('Avatar settings'));
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
if (Event::handle('StartAvatarFormData', array($this))) {
|
||||
$this->elementStart('ul', 'form_data');
|
||||
if ($original) {
|
||||
$this->elementStart('li', array('id' => 'avatar_original',
|
||||
'class' => 'avatar_view'));
|
||||
$this->element('h2', null, _("Original"));
|
||||
$this->elementStart('div', array('id'=>'avatar_original_view'));
|
||||
$this->element('img', array('src' => $original->url,
|
||||
'width' => $original->width,
|
||||
'height' => $original->height,
|
||||
'alt' => $user->nickname));
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
if ($original) {
|
||||
$this->elementStart('li', array('id' => 'avatar_original',
|
||||
'class' => 'avatar_view'));
|
||||
$this->element('h2', null, _("Original"));
|
||||
$this->elementStart('div', array('id'=>'avatar_original_view'));
|
||||
$this->element('img', array('src' => $original->url,
|
||||
'width' => $original->width,
|
||||
'height' => $original->height,
|
||||
'alt' => $user->nickname));
|
||||
$this->elementEnd('div');
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
|
||||
if ($avatar) {
|
||||
$this->elementStart('li', array('id' => 'avatar_preview',
|
||||
'class' => 'avatar_view'));
|
||||
$this->element('h2', null, _("Preview"));
|
||||
$this->elementStart('div', array('id'=>'avatar_preview_view'));
|
||||
$this->element('img', array('src' => $original->url,
|
||||
'width' => AVATAR_PROFILE_SIZE,
|
||||
'height' => AVATAR_PROFILE_SIZE,
|
||||
'alt' => $user->nickname));
|
||||
$this->elementEnd('div');
|
||||
$this->submit('delete', _('Delete'));
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
|
||||
$this->elementStart('li', array ('id' => 'settings_attach'));
|
||||
$this->element('input', array('name' => 'avatarfile',
|
||||
'type' => 'file',
|
||||
'id' => 'avatarfile'));
|
||||
$this->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||
'type' => 'hidden',
|
||||
'id' => 'MAX_FILE_SIZE',
|
||||
'value' => ImageFile::maxFileSizeInt()));
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
|
||||
if ($avatar) {
|
||||
$this->elementStart('li', array('id' => 'avatar_preview',
|
||||
'class' => 'avatar_view'));
|
||||
$this->element('h2', null, _("Preview"));
|
||||
$this->elementStart('div', array('id'=>'avatar_preview_view'));
|
||||
$this->element('img', array('src' => $original->url,
|
||||
'width' => AVATAR_PROFILE_SIZE,
|
||||
'height' => AVATAR_PROFILE_SIZE,
|
||||
'alt' => $user->nickname));
|
||||
$this->elementEnd('div');
|
||||
$this->submit('delete', _('Delete'));
|
||||
$this->elementStart('ul', 'form_actions');
|
||||
$this->elementStart('li');
|
||||
$this->submit('upload', _('Upload'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
}
|
||||
|
||||
$this->elementStart('li', array ('id' => 'settings_attach'));
|
||||
$this->element('input', array('name' => 'avatarfile',
|
||||
'type' => 'file',
|
||||
'id' => 'avatarfile'));
|
||||
$this->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||
'type' => 'hidden',
|
||||
'id' => 'MAX_FILE_SIZE',
|
||||
'value' => ImageFile::maxFileSizeInt()));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->elementStart('ul', 'form_actions');
|
||||
$this->elementStart('li');
|
||||
$this->submit('upload', _('Upload'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
Event::handle('EndAvatarFormData', array($this));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
@ -266,15 +269,18 @@ class AvatarsettingsAction extends AccountSettingsAction
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->arg('upload')) {
|
||||
$this->uploadAvatar();
|
||||
} else if ($this->arg('crop')) {
|
||||
$this->cropAvatar();
|
||||
} else if ($this->arg('delete')) {
|
||||
$this->deleteAvatar();
|
||||
} else {
|
||||
$this->showForm(_('Unexpected form submission.'));
|
||||
|
||||
if (Event::handle('StartAvatarSaveForm', array($this))) {
|
||||
if ($this->arg('upload')) {
|
||||
$this->uploadAvatar();
|
||||
} else if ($this->arg('crop')) {
|
||||
$this->cropAvatar();
|
||||
} else if ($this->arg('delete')) {
|
||||
$this->deleteAvatar();
|
||||
} else {
|
||||
$this->showForm(_('Unexpected form submission.'));
|
||||
}
|
||||
Event::handle('EndAvatarSaveForm', array($this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,12 +77,13 @@ class LoginAction extends Action
|
||||
parent::handle($args);
|
||||
|
||||
$disabled = common_config('logincommand','disabled');
|
||||
$disabled = isset($disabled) && $disabled;
|
||||
|
||||
if (common_is_real_login()) {
|
||||
$this->clientError(_('Already logged in.'));
|
||||
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->checkLogin();
|
||||
} else if (!isset($disabled) && isset($args['user_id']) && isset($args['token'])){
|
||||
} else if (!$disabled && isset($args['user_id']) && isset($args['token'])){
|
||||
$this->checkLogin($args['user_id'],$args['token']);
|
||||
} else {
|
||||
common_ensure_session();
|
||||
|
@ -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);
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Forward action.
|
||||
* Repeat action.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
@ -33,7 +33,7 @@ if (!defined('STATUSNET')) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward action
|
||||
* Repeat action
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
@ -42,7 +42,7 @@ if (!defined('STATUSNET')) {
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ForwardAction extends Action
|
||||
class RepeatAction extends Action
|
||||
{
|
||||
var $user = null;
|
||||
var $notice = null;
|
||||
@ -54,7 +54,7 @@ class ForwardAction extends Action
|
||||
$this->user = common_current_user();
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_("Only logged-in users can forward notices."));
|
||||
$this->clientError(_("Only logged-in users can repeat notices."));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ class ForwardAction extends Action
|
||||
}
|
||||
|
||||
if ($this->user->id == $this->notice->profile_id) {
|
||||
$this->clientError(_("You can't forward your own notice."));
|
||||
$this->clientError(_("You can't repeat your own notice."));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -86,8 +86,8 @@ class ForwardAction extends Action
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if ($profile->hasForwarded($id)) {
|
||||
$this->clientError(_("You already forwarded that notice."));
|
||||
if ($profile->hasRepeated($id)) {
|
||||
$this->clientError(_("You already repeated that notice."));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -104,15 +104,15 @@ class ForwardAction extends Action
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
$forward = Forward::saveNew($this->user->id, $this->notice->id);
|
||||
$repeat = $this->notice->repeat($this->user->id, 'web');
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
$this->element('title', null, _('Forwarded'));
|
||||
$this->element('title', null, _('Repeated'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$this->element('p', array('id' => 'forward_response'), _('Forwarded!'));
|
||||
$this->element('p', array('id' => 'repeat_response'), _('Repeated!'));
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
} else {
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,126 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2009, StatusNet, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Table Definition for location_namespace
|
||||
*/
|
||||
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Forward extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'forward'; // table name
|
||||
public $profile_id; // int(4) primary_key not_null
|
||||
public $notice_id; // int(4) primary_key not_null
|
||||
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Forward',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
function &pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Forward', $kv);
|
||||
}
|
||||
|
||||
static function saveNew($profile_id, $notice_id)
|
||||
{
|
||||
$forward = new Forward();
|
||||
|
||||
$forward->profile_id = $profile_id;
|
||||
$forward->notice_id = $notice_id;
|
||||
$forward->created = common_sql_now();
|
||||
|
||||
$forward->query('BEGIN');
|
||||
|
||||
if (!$forward->insert()) {
|
||||
throw new ServerException(_("Couldn't insert forward."));
|
||||
}
|
||||
|
||||
$ni = $forward->addToInboxes();
|
||||
|
||||
$forward->query('COMMIT');
|
||||
|
||||
$forward->blowCache($ni);
|
||||
|
||||
return $forward;
|
||||
}
|
||||
|
||||
function addToInboxes()
|
||||
{
|
||||
$inbox = new Notice_inbox();
|
||||
|
||||
$user = new User();
|
||||
|
||||
$user->query('SELECT user.* FROM user JOIN subscription ON user.id = subscription.subscriber '.
|
||||
'WHERE subscription.subscribed = '.$this->profile_id);
|
||||
|
||||
$ni = array();
|
||||
|
||||
$notice = Notice::staticGet('id', $this->notice_id);
|
||||
|
||||
$author = Profile::staticGet('id', $notice->profile_id);
|
||||
|
||||
while ($user->fetch()) {
|
||||
$inbox = Notice_inbox::pkeyGet(array('user_id' => $user->id,
|
||||
'notice_id' => $this->notice_id));
|
||||
|
||||
if (empty($inbox)) {
|
||||
if (!$user->hasBlocked($author)) {
|
||||
$ni[$user->id] = NOTICE_INBOX_SOURCE_FORWARD;
|
||||
}
|
||||
} else {
|
||||
$inbox->free();
|
||||
}
|
||||
}
|
||||
|
||||
$user->free();
|
||||
$author->free();
|
||||
|
||||
unset($user);
|
||||
unset($author);
|
||||
|
||||
Notice_inbox::bulkInsert($this->notice_id, $this->created, $ni);
|
||||
|
||||
return $ni;
|
||||
}
|
||||
|
||||
function blowCache($ni)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
|
||||
if (!empty($cache)) {
|
||||
foreach ($ni as $id => $source) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$id));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$id));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$id.';last'));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$id.';last'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -39,4 +39,17 @@ class Login_token extends Memcached_DataObject
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
/*
|
||||
DB_DataObject calculates the sequence key(s) by taking the first key returned by the keys() function.
|
||||
In this case, the keys() function returns user_id as the first key. user_id is not a sequence, but
|
||||
DB_DataObject's sequenceKey() will incorrectly think it is. Then, since the sequenceKey() is a numeric
|
||||
type, but is not set to autoincrement in the database, DB_DataObject will create a _seq table and
|
||||
manage the sequence itself. This is not the correct behavior for the user_id in this class.
|
||||
So we override that incorrect behavior, and simply say there is no sequence key.
|
||||
*/
|
||||
function sequenceKey()
|
||||
{
|
||||
return array(false,false);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
@ -581,193 +655,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();
|
||||
@ -788,10 +675,24 @@ class Notice extends Memcached_DataObject
|
||||
return $notice;
|
||||
}
|
||||
$notice->whereAdd('id in (' . implode(', ', $ids) . ')');
|
||||
$notice->orderBy('id DESC');
|
||||
|
||||
$notice->find();
|
||||
return $notice;
|
||||
|
||||
$temp = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$temp[$notice->id] = clone($notice);
|
||||
}
|
||||
|
||||
$wrapped = array();
|
||||
|
||||
foreach ($ids as $id) {
|
||||
if (array_key_exists($id, $temp)) {
|
||||
$wrapped[] = $temp[$id];
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayWrapper($wrapped);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1409,4 +1310,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;
|
||||
}
|
||||
}
|
||||
|
@ -717,11 +717,14 @@ class Profile extends Memcached_DataObject
|
||||
return $result;
|
||||
}
|
||||
|
||||
function hasForwarded($notice_id)
|
||||
function hasRepeated($notice_id)
|
||||
{
|
||||
$forward = Forward::pkeyGet(array('profile_id' => $this->id,
|
||||
'notice_id' => $notice_id));
|
||||
// XXX: not really a pkey, but should work
|
||||
|
||||
return (!empty($forward));
|
||||
$notice = Memcached_DataObject::pkeyGet('Notice',
|
||||
array('profile_id' => $this->id,
|
||||
'repeat_of' => $notice_id));
|
||||
|
||||
return !empty($notice);
|
||||
}
|
||||
}
|
||||
|
159
classes/User.php
159
classes/User.php
@ -741,4 +741,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;
|
||||
}
|
||||
}
|
||||
|
@ -196,15 +196,6 @@ id = K
|
||||
service = K
|
||||
uri = U
|
||||
|
||||
[forward]
|
||||
profile_id = 129
|
||||
notice_id = 129
|
||||
created = 142
|
||||
|
||||
[forward__keys]
|
||||
profile_id = K
|
||||
notice_id = K
|
||||
|
||||
[group_alias]
|
||||
alias = 130
|
||||
group_id = 129
|
||||
@ -316,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';
|
||||
@ -82,15 +84,3 @@ create table login_token (
|
||||
|
||||
constraint primary key (user_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table forward (
|
||||
|
||||
profile_id integer not null comment 'profile who forwarded the notice' references profile (id),
|
||||
notice_id integer not null comment 'notice they forwarded' references notice (id),
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
|
||||
constraint primary key (profile_id, notice_id)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
|
@ -39,6 +39,16 @@ create table profile_role (
|
||||
|
||||
);
|
||||
|
||||
create table location_namespace (
|
||||
|
||||
id integer /*comment 'identity for this namespace'*/,
|
||||
description text /* comment 'description of the namespace'*/ ,
|
||||
created integer not null /*comment 'date the record was created*/ ,
|
||||
/* modified timestamp comment 'date this record was modified',*/
|
||||
primary key (id)
|
||||
|
||||
);
|
||||
|
||||
create table login_token (
|
||||
user_id integer not null /* comment 'user owning this token'*/ references "user" (id),
|
||||
token char(32) not null /* comment 'token useable for logging in'*/,
|
||||
@ -64,8 +74,10 @@ 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'*/;
|
||||
ALTER TABLE profile ADD COLUMN location_id integer /* comment 'location id if possible'*/;
|
||||
ALTER TABLE profile ADD COLUMN location_ns integer /* comment 'namespace for location'*/;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -585,14 +587,3 @@ create table login_token (
|
||||
constraint primary key (user_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table forward (
|
||||
|
||||
profile_id integer not null comment 'profile who forwarded the notice' references profile (id),
|
||||
notice_id integer not null comment 'notice they forwarded' references notice (id),
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
|
||||
constraint primary key (profile_id, notice_id)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
|
@ -64,7 +64,7 @@ create table "user" (
|
||||
emailnotifyfav integer default 1 /* comment 'Notify by email of favorites' */,
|
||||
emailnotifynudge integer default 1 /* comment 'Notify by email of nudges' */,
|
||||
emailnotifymsg integer default 1 /* comment 'Notify by email of direct messages' */,
|
||||
emailnotifyattn integer default 1 /* command 'Notify by email of @-replies' */,
|
||||
emailnotifyattn integer default 1 /* command 'Notify by email of @-replies' */,
|
||||
emailmicroid integer default 1 /* comment 'whether to publish email microid' */,
|
||||
language varchar(50) /* comment 'preferred language' */,
|
||||
timezone varchar(50) /* comment 'timezone' */,
|
||||
@ -82,7 +82,7 @@ create table "user" (
|
||||
uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
|
||||
autosubscribe integer default 0 /* comment 'automatically subscribe to users who subscribe to us' */,
|
||||
urlshorteningservice varchar(50) default 'ur1.ca' /* comment 'service to use for auto-shortening URLs' */,
|
||||
inboxed integer default 0 /* comment 'has an inbox been created for this user?' */,
|
||||
inboxed integer default 0 /* comment 'has an inbox been created for this user?' */,
|
||||
design_id integer /* comment 'id of a design' */references design(id),
|
||||
viewdesigns integer default 1 /* comment 'whether to view user-provided designs'*/,
|
||||
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
|
||||
@ -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) */
|
||||
);
|
||||
|
||||
@ -298,7 +300,7 @@ create table foreign_user (
|
||||
nickname varchar(255) /* comment 'nickname on foreign service' */,
|
||||
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
|
||||
modified timestamp /* comment 'date this record was modified' */,
|
||||
|
||||
|
||||
primary key (id, service)
|
||||
);
|
||||
|
||||
@ -308,7 +310,7 @@ create table foreign_link (
|
||||
service int not null /* comment 'foreign key to service' */ references foreign_service (id),
|
||||
credentials varchar(255) /* comment 'authc credentials, typically a password' */,
|
||||
noticesync int not null default 1 /* comment 'notice synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies' */,
|
||||
friendsync int not null default 2 /* comment 'friend synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming */,
|
||||
friendsync int not null default 2 /* comment 'friend synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming */,
|
||||
profilesync int not null default 1 /* comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming' */,
|
||||
last_noticesync timestamp default null /* comment 'last time notices were imported' */,
|
||||
last_friendsync timestamp default null /* comment 'last time friends were imported' */,
|
||||
@ -324,7 +326,7 @@ create table foreign_subscription (
|
||||
subscriber int not null /* comment 'subscriber on foreign service' */ ,
|
||||
subscribed int not null /* comment 'subscribed user' */ ,
|
||||
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
|
||||
|
||||
|
||||
primary key (service, subscriber, subscribed)
|
||||
);
|
||||
create index foreign_subscription_subscriber_idx on foreign_subscription using btree(subscriber);
|
||||
@ -354,7 +356,7 @@ create table message (
|
||||
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
|
||||
modified timestamp /* comment 'date this record was modified' */,
|
||||
source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */
|
||||
|
||||
|
||||
);
|
||||
create index message_from_idx on message using btree(from_profile);
|
||||
create index message_to_idx on message using btree(to_profile);
|
||||
@ -409,7 +411,6 @@ create table user_group (
|
||||
mini_logo varchar(255) /* comment 'mini logo' */,
|
||||
design_id integer /*comment 'id of a design' */ references design(id),
|
||||
|
||||
|
||||
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
|
||||
modified timestamp /* comment 'date this record was modified' */
|
||||
|
||||
@ -447,16 +448,15 @@ create table group_inbox (
|
||||
);
|
||||
create index group_inbox_created_idx on group_inbox using btree(created);
|
||||
|
||||
|
||||
/*attachments and URLs stuff */
|
||||
create sequence file_seq;
|
||||
create table file (
|
||||
id bigint default nextval('file_seq') primary key /* comment 'unique identifier' */,
|
||||
url varchar(255) unique,
|
||||
mimetype varchar(50),
|
||||
size integer,
|
||||
title varchar(255),
|
||||
date integer,
|
||||
url varchar(255) unique,
|
||||
mimetype varchar(50),
|
||||
size integer,
|
||||
title varchar(255),
|
||||
date integer,
|
||||
protected integer,
|
||||
filename text /* comment 'if a local file, name of the file' */,
|
||||
modified timestamp default CURRENT_TIMESTAMP /* comment 'date this record was modified'*/
|
||||
@ -467,38 +467,38 @@ create table file_oembed (
|
||||
file_id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
|
||||
version varchar(20),
|
||||
type varchar(20),
|
||||
mimetype varchar(50),
|
||||
mimetype varchar(50),
|
||||
provider varchar(50),
|
||||
provider_url varchar(255),
|
||||
width integer,
|
||||
height integer,
|
||||
html text,
|
||||
title varchar(255),
|
||||
author_name varchar(50),
|
||||
author_url varchar(255),
|
||||
url varchar(255)
|
||||
author_name varchar(50),
|
||||
author_url varchar(255),
|
||||
url varchar(255)
|
||||
);
|
||||
|
||||
create sequence file_redirection_seq;
|
||||
create table file_redirection (
|
||||
url varchar(255) primary key,
|
||||
file_id bigint,
|
||||
redirections integer,
|
||||
url varchar(255) primary key,
|
||||
file_id bigint,
|
||||
redirections integer,
|
||||
httpcode integer
|
||||
);
|
||||
|
||||
create sequence file_thumbnail_seq;
|
||||
create table file_thumbnail (
|
||||
file_id bigint primary key,
|
||||
url varchar(255) unique,
|
||||
width integer,
|
||||
height integer
|
||||
file_id bigint primary key,
|
||||
url varchar(255) unique,
|
||||
width integer,
|
||||
height integer
|
||||
);
|
||||
|
||||
create sequence file_to_post_seq;
|
||||
create table file_to_post (
|
||||
file_id bigint,
|
||||
post_id bigint,
|
||||
file_id bigint,
|
||||
post_id bigint,
|
||||
|
||||
primary key (file_id, post_id)
|
||||
);
|
||||
@ -527,7 +527,7 @@ create table session (
|
||||
id varchar(32) primary key /* comment 'session ID'*/,
|
||||
session_data text /* comment 'session data'*/,
|
||||
created timestamp not null DEFAULT CURRENT_TIMESTAMP /* comment 'date this record was created'*/,
|
||||
modified integer DEFAULT extract(epoch from CURRENT_TIMESTAMP) /* comment 'date this record was modified'*/
|
||||
modified integer DEFAULT extract(epoch from CURRENT_TIMESTAMP) /* comment 'date this record was modified'*/
|
||||
);
|
||||
|
||||
create index session_modified_idx on session (modified);
|
||||
@ -543,7 +543,6 @@ create table deleted_notice (
|
||||
|
||||
CREATE index deleted_notice_profile_id_idx on deleted_notice (profile_id);
|
||||
|
||||
|
||||
/* Textsearch stuff */
|
||||
|
||||
create index textsearch_idx on profile using gist(textsearch);
|
||||
@ -551,7 +550,6 @@ create index noticecontent_idx on notice using gist(to_tsvector('english',conten
|
||||
create trigger textsearchupdate before insert or update on profile for each row
|
||||
execute procedure tsvector_update_trigger(textsearch, 'pg_catalog.english', nickname, fullname, location, bio, homepage);
|
||||
|
||||
|
||||
create table config (
|
||||
|
||||
section varchar(32) /* comment 'configuration section'*/,
|
||||
@ -572,6 +570,16 @@ create table profile_role (
|
||||
|
||||
);
|
||||
|
||||
create table location_namespace (
|
||||
|
||||
id integer /*comment 'identity for this namespace'*/,
|
||||
description text /* comment 'description of the namespace'*/ ,
|
||||
created integer not null /*comment 'date the record was created*/ ,
|
||||
/* modified timestamp comment 'date this record was modified',*/
|
||||
primary key (id)
|
||||
|
||||
);
|
||||
|
||||
create table login_token (
|
||||
user_id integer not null /* comment 'user owning this token'*/ references "user" (id),
|
||||
token char(32) not null /* comment 'token useable for logging in'*/,
|
||||
|
49
js/util.js
49
js/util.js
@ -57,21 +57,31 @@ var SN = { // StatusNet
|
||||
U: { // Utils
|
||||
FormNoticeEnhancements: function(form) {
|
||||
form_id = form.attr('id');
|
||||
$('#'+form_id+' #'+SN.C.S.NoticeDataText).unbind('keyup');
|
||||
$('#'+form_id+' #'+SN.C.S.NoticeDataText).unbind('keydown');
|
||||
if (maxLength > 0) {
|
||||
$('#'+form_id+' #'+SN.C.S.NoticeDataText).bind('keyup', function(e) {
|
||||
|
||||
if (jQuery.data(form[0], 'ElementData') === undefined) {
|
||||
MaxLength = $('#'+form_id+' #'+SN.C.S.NoticeTextCount).text();
|
||||
if (typeof(MaxLength) == 'undefined') {
|
||||
MaxLength = SN.C.I.MaxLength;
|
||||
}
|
||||
jQuery.data(form[0], 'ElementData', {MaxLength:MaxLength});
|
||||
|
||||
SN.U.Counter(form);
|
||||
|
||||
NDT = $('#'+form_id+' #'+SN.C.S.NoticeDataText);
|
||||
|
||||
NDT.bind('keyup', function(e) {
|
||||
SN.U.Counter(form);
|
||||
});
|
||||
// run once in case there's something in there
|
||||
SN.U.Counter(form);
|
||||
|
||||
NDT.bind('keydown', function(e) {
|
||||
SN.U.SubmitOnReturn(e, form);
|
||||
});
|
||||
}
|
||||
else {
|
||||
$('#'+form_id+' #'+SN.C.S.NoticeTextCount).text(jQuery.data(form[0], 'ElementData').MaxLength);
|
||||
}
|
||||
|
||||
$('#'+form_id+' #'+SN.C.S.NoticeDataText).bind('keydown', function(e) {
|
||||
SN.U.SubmitOnReturn(e, form);
|
||||
});
|
||||
|
||||
if($('body')[0].id != 'conversation') {
|
||||
if ($('body')[0].id != 'conversation') {
|
||||
$('#'+form_id+' textarea').focus();
|
||||
}
|
||||
},
|
||||
@ -91,15 +101,14 @@ var SN = { // StatusNet
|
||||
Counter: function(form) {
|
||||
SN.C.I.FormNoticeCurrent = form;
|
||||
form_id = form.attr('id');
|
||||
if (typeof(maxLength) == "undefined") {
|
||||
maxLength = SN.C.I.MaxLength;
|
||||
}
|
||||
|
||||
if (maxLength <= 0) {
|
||||
var MaxLength = jQuery.data(form[0], 'ElementData').MaxLength;
|
||||
|
||||
if (MaxLength <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var remaining = maxLength - $('#'+form_id+' #'+SN.C.S.NoticeDataText).val().length;
|
||||
var remaining = MaxLength - $('#'+form_id+' #'+SN.C.S.NoticeDataText).val().length;
|
||||
var counter = $('#'+form_id+' #'+SN.C.S.NoticeTextCount);
|
||||
|
||||
if (remaining.toString() != counter.text()) {
|
||||
@ -306,8 +315,8 @@ var SN = { // StatusNet
|
||||
$('.form_disfavor').each(function() { SN.U.FormXHR($(this)); });
|
||||
},
|
||||
|
||||
NoticeForward: function() {
|
||||
$('.form_forward').each(function() { SN.U.FormXHR($(this)); });
|
||||
NoticeRepeat: function() {
|
||||
$('.form_repeat').each(function() { SN.U.FormXHR($(this)); });
|
||||
},
|
||||
|
||||
NoticeAttachments: function() {
|
||||
@ -443,7 +452,7 @@ var SN = { // StatusNet
|
||||
Notices: function() {
|
||||
if ($('body.user_in').length > 0) {
|
||||
SN.U.NoticeFavor();
|
||||
SN.U.NoticeForward();
|
||||
SN.U.NoticeRepeat();
|
||||
SN.U.NoticeReply();
|
||||
}
|
||||
|
||||
@ -457,6 +466,8 @@ var SN = { // StatusNet
|
||||
$('.form_group_join').each(function() { SN.U.FormXHR($(this)); });
|
||||
$('.form_group_leave').each(function() { SN.U.FormXHR($(this)); });
|
||||
$('.form_user_nudge').each(function() { SN.U.FormXHR($(this)); });
|
||||
|
||||
SN.U.NewDirectMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
50
lib/api.php
50
lib/api.php
@ -134,17 +134,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 +165,7 @@ class ApiAction extends Action
|
||||
|
||||
$timezone = 'UTC';
|
||||
|
||||
if (!empty($user) && !empty($user->timezone)) {
|
||||
if ($user->timezone) {
|
||||
$timezone = $user->timezone;
|
||||
}
|
||||
|
||||
@ -213,6 +215,20 @@ class ApiAction extends Action
|
||||
}
|
||||
|
||||
function twitterStatusArray($notice, $include_user=true)
|
||||
{
|
||||
$base = $this->twitterSimpleStatusArray($notice, $include_user);
|
||||
|
||||
if (empty($notice->repeat_of)) {
|
||||
return $base;
|
||||
} else {
|
||||
$original = Notice::staticGet('id', $notice->repeat_of);
|
||||
$original_array = $this->twitterSimpleStatusArray($original, $include_user);
|
||||
$original_array['retweeted_status'] = $base;
|
||||
return $original_array;
|
||||
}
|
||||
}
|
||||
|
||||
function twitterSimpleStatusArray($notice, $include_user=true)
|
||||
{
|
||||
$profile = $notice->getProfile();
|
||||
|
||||
@ -446,9 +462,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 +479,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 +605,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 +619,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 +647,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 +656,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',
|
||||
|
@ -433,8 +433,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 {
|
||||
@ -584,7 +585,8 @@ class LoginCommand extends Command
|
||||
function execute($channel)
|
||||
{
|
||||
$disabled = common_config('logincommand','disabled');
|
||||
if(isset($disabled)) {
|
||||
$disabled = isset($disabled) && $disabled;
|
||||
if($disabled) {
|
||||
$channel->error($this->user, _('Login command is disabled'));
|
||||
return;
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ if (!function_exists('npgettext')) {
|
||||
*/
|
||||
function _m($msg/*, ...*/)
|
||||
{
|
||||
$domain = _mdomain(debug_backtrace(false));
|
||||
$domain = _mdomain(debug_backtrace());
|
||||
$args = func_get_args();
|
||||
switch(count($args)) {
|
||||
case 1: return dgettext($domain, $msg);
|
||||
@ -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'),
|
||||
|
@ -154,8 +154,6 @@ class MessageForm extends Form
|
||||
|
||||
$contentLimit = Message::maxContent();
|
||||
|
||||
$this->out->inlineScript('maxLength = ' . $contentLimit . ';');
|
||||
|
||||
if ($contentLimit > 0) {
|
||||
$this->out->elementStart('dl', 'form_note');
|
||||
$this->out->element('dt', null, _('Available characters'));
|
||||
|
@ -178,8 +178,6 @@ class NoticeForm extends Form
|
||||
|
||||
$contentLimit = Notice::maxContent();
|
||||
|
||||
$this->out->inlineScript('maxLength = ' . $contentLimit . ';');
|
||||
|
||||
if ($contentLimit > 0) {
|
||||
$this->out->elementStart('dl', 'form_note');
|
||||
$this->out->element('dt', null, _('Available characters'));
|
||||
|
@ -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,7 +227,7 @@ class NoticeListItem extends Widget
|
||||
$this->out->elementStart('div', 'notice-options');
|
||||
$this->showFaveForm();
|
||||
$this->showReplyLink();
|
||||
$this->showForwardForm();
|
||||
$this->showRepeatForm();
|
||||
$this->showDeleteLink();
|
||||
$this->out->elementEnd('div');
|
||||
}
|
||||
@ -508,6 +523,52 @@ 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');
|
||||
|
||||
$this->out->elementStart('a', $attrs);
|
||||
|
||||
$avatar = $repeater->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' =>
|
||||
($repeater->fullname) ?
|
||||
$repeater->fullname :
|
||||
$repeater->nickname));
|
||||
|
||||
$this->out->elementEnd('a');
|
||||
|
||||
$text_link = XMLStringer::estring('a', $attrs, $repeater->nickname);
|
||||
|
||||
$this->out->raw(sprintf(_('Repeated by %s'), $text_link));
|
||||
|
||||
$this->out->elementEnd('span');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show a link to reply to the current notice
|
||||
*
|
||||
@ -531,26 +592,6 @@ class NoticeListItem extends Widget
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show the form to forward a notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showForwardForm()
|
||||
{
|
||||
$user = common_current_user();
|
||||
if ($user && $user->id != $this->notice->profile_id) {
|
||||
$profile = $user->getProfile();
|
||||
if ($profile->hasForwarded($this->notice->id)) {
|
||||
$this->out->text(_('Forwarded'));
|
||||
} else {
|
||||
$ff = new ForwardForm($this->out, $this->notice);
|
||||
$ff->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if the user is the author, let them delete the notice
|
||||
*
|
||||
@ -572,6 +613,26 @@ class NoticeListItem extends Widget
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->text(_('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);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for forwarding a notice
|
||||
* Form for repeating a notice
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
@ -27,14 +27,12 @@
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/form.php';
|
||||
|
||||
/**
|
||||
* Form for forwarding a notice
|
||||
* Form for repeating a notice
|
||||
*
|
||||
* @category Form
|
||||
* @package StatusNet
|
||||
@ -43,10 +41,10 @@ require_once INSTALLDIR.'/lib/form.php';
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ForwardForm extends Form
|
||||
class RepeatForm extends Form
|
||||
{
|
||||
/**
|
||||
* Notice to forward
|
||||
* Notice to repeat
|
||||
*/
|
||||
|
||||
var $notice = null;
|
||||
@ -55,7 +53,7 @@ class ForwardForm extends Form
|
||||
* Constructor
|
||||
*
|
||||
* @param HTMLOutputter $out output channel
|
||||
* @param Notice $notice notice to forward
|
||||
* @param Notice $notice notice to repeat
|
||||
*/
|
||||
|
||||
function __construct($out=null, $notice=null)
|
||||
@ -73,7 +71,7 @@ class ForwardForm extends Form
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'forward-' . $this->notice->id;
|
||||
return 'repeat-' . $this->notice->id;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,7 +82,7 @@ class ForwardForm extends Form
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('forward');
|
||||
return common_local_url('repeat');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,7 +104,7 @@ class ForwardForm extends Form
|
||||
*/
|
||||
function formLegend()
|
||||
{
|
||||
$this->out->element('legend', null, _('Forward this notice'));
|
||||
$this->out->element('legend', null, _('Repeat this notice'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,8 +128,8 @@ class ForwardForm extends Form
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('forward-submit-' . $this->notice->id,
|
||||
_('Forward'), 'submit', null, _('Forward this notice'));
|
||||
$this->out->submit('repeat-submit-' . $this->notice->id,
|
||||
_('Repeat'), 'submit', null, _('Repeat this notice'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,6 +140,6 @@ class ForwardForm extends Form
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_forward';
|
||||
return 'form_repeat';
|
||||
}
|
||||
}
|
@ -99,7 +99,8 @@ class Router
|
||||
'groupblock', 'groupunblock',
|
||||
'sandbox', 'unsandbox',
|
||||
'silence', 'unsilence',
|
||||
'deleteuser', 'forward');
|
||||
'repeat',
|
||||
'deleteuser');
|
||||
|
||||
foreach ($main as $a) {
|
||||
$m->connect('main/'.$a, array('action' => $a));
|
||||
@ -318,6 +319,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 +371,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
5214
locale/arz/LC_MESSAGES/statusnet.po
Normal file
5214
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
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
@ -43,4 +43,19 @@ class User_username extends Memcached_DataObject
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function table() {
|
||||
return array(
|
||||
'user_id' => DB_DATAOBJECT_INT,
|
||||
'username' => DB_DATAOBJECT_STR,
|
||||
'provider_name' => DB_DATAOBJECT_STR ,
|
||||
'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME
|
||||
);
|
||||
}
|
||||
|
||||
// now define the keys.
|
||||
function keys() {
|
||||
return array('provider_name', 'username');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
188
plugins/Gravatar/GravatarPlugin.php
Normal file
188
plugins/Gravatar/GravatarPlugin.php
Normal file
@ -0,0 +1,188 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2009, StatusNet, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @package GravatarPlugin
|
||||
* @maintainer Eric Helgeson <erichelgeson@gmail.com>
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class GravatarPlugin extends Plugin
|
||||
{
|
||||
function onInitializePlugin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartAvatarFormData($action) {
|
||||
$user = common_current_user();
|
||||
$hasGravatar = $this->hasGravatar($user->id);
|
||||
|
||||
if($hasGravatar) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function onEndAvatarFormData(&$action) {
|
||||
$user = common_current_user();
|
||||
$hasGravatar = $this->hasGravatar($user->id);
|
||||
|
||||
if(!empty($user->email) && !$hasGravatar) { //and not gravatar already set
|
||||
$action->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_gravatar_add',
|
||||
'class' => 'form_settings',
|
||||
'action' =>
|
||||
common_local_url('avatarsettings')));
|
||||
$action->elementStart('fieldset', array('id' => 'settings_gravatar_add'));
|
||||
$action->element('legend', null, _m('Set Gravatar'));
|
||||
$action->hidden('token', common_session_token());
|
||||
$action->element('p', 'form_guide',
|
||||
_m('If you want to use your Gravatar image, click "Add".'));
|
||||
$action->element('input', array('type' => 'submit',
|
||||
'id' => 'settings_gravatar_add_action-submit',
|
||||
'name' => 'add',
|
||||
'class' => 'submit',
|
||||
'value' => _m('Add')));
|
||||
$action->elementEnd('fieldset');
|
||||
$action->elementEnd('form');
|
||||
} elseif($hasGravatar) {
|
||||
$action->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_gravatar_remove',
|
||||
'class' => 'form_settings',
|
||||
'action' =>
|
||||
common_local_url('avatarsettings')));
|
||||
$action->elementStart('fieldset', array('id' => 'settings_gravatar_remove'));
|
||||
$action->element('legend', null, _m('Remove Gravatar'));
|
||||
$action->hidden('token', common_session_token());
|
||||
$action->element('p', 'form_guide',
|
||||
_m('If you want to remove your Gravatar image, click "Remove".'));
|
||||
$action->element('input', array('type' => 'submit',
|
||||
'id' => 'settings_gravatar_remove_action-submit',
|
||||
'name' => 'remove',
|
||||
'class' => 'submit',
|
||||
'value' => _m('Remove')));
|
||||
$action->elementEnd('fieldset');
|
||||
$action->elementEnd('form');
|
||||
} else {
|
||||
$action->element('p', 'form_guide',
|
||||
_m('To use a Gravatar first enter in an email address.'));
|
||||
}
|
||||
}
|
||||
|
||||
function onStartAvatarSaveForm($action) {
|
||||
if ($action->arg('add')) {
|
||||
$result = $this->gravatar_save();
|
||||
|
||||
if($result['success']===true) {
|
||||
common_broadcast_profile(common_current_user()->getProfile());
|
||||
}
|
||||
|
||||
$action->showForm($result['message'], $result['success']);
|
||||
|
||||
return false;
|
||||
} else if ($action->arg('remove')) {
|
||||
$result = $this->gravatar_remove();
|
||||
|
||||
if($result['success']===true) {
|
||||
common_broadcast_profile(common_current_user()->getProfile());
|
||||
}
|
||||
|
||||
$action->showForm($result['message'], $result['success']);
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function hasGravatar($id) {
|
||||
$avatar = new Avatar();
|
||||
$avatar->profile_id = $id;
|
||||
if ($avatar->find()) {
|
||||
while ($avatar->fetch()) {
|
||||
if($avatar->filename == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function gravatar_save()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
if(empty($cur->email)) {
|
||||
return array('message' => _m('You do not have a email set in your profile.'),
|
||||
'success' => false);
|
||||
}
|
||||
//Get rid of previous Avatar
|
||||
$this->gravatar_remove();
|
||||
|
||||
foreach (array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE) as $size) {
|
||||
$gravatar = new Avatar();
|
||||
$gravatar->profile_id = $cur->id;
|
||||
$gravatar->width = $size;
|
||||
$gravatar->height = $size;
|
||||
$gravatar->original = false; //No file, so no original
|
||||
$gravatar->mediatype = 'img';//XXX: Unsure what to put here
|
||||
//$gravatar->filename = null;//No filename. Remote
|
||||
$gravatar->url = $this->gravatar_url($cur->email, $size);
|
||||
$gravatar->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
|
||||
if (!$gravatar->insert()) {
|
||||
return array('message' => _m('Failed to save Gravatar to the DB.'),
|
||||
'success' => false);
|
||||
}
|
||||
}
|
||||
return array('message' => _m('Gravatar added.'),
|
||||
'success' => true);
|
||||
}
|
||||
|
||||
function gravatar_remove()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$avatar = $profile->getOriginalAvatar();
|
||||
if($avatar) $avatar->delete();
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
if($avatar) $avatar->delete();
|
||||
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
||||
if($avatar) $avatar->delete();
|
||||
$avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
|
||||
if($avatar) $avatar->delete();
|
||||
|
||||
return array('message' => _m('Gravatar removed.'),
|
||||
'success' => true);
|
||||
}
|
||||
|
||||
function gravatar_url($email, $size) {
|
||||
$url = "http://www.gravatar.com/avatar.php?gravatar_id=".
|
||||
md5(strtolower($email)).
|
||||
"&default=".urlencode(Avatar::defaultImage($size)).
|
||||
"&size=".$size;
|
||||
return $url;
|
||||
}
|
||||
}
|
13
plugins/Gravatar/README
Normal file
13
plugins/Gravatar/README
Normal file
@ -0,0 +1,13 @@
|
||||
GravatarPlugin 0.1
|
||||
|
||||
About
|
||||
This will allow users to use their Gravatar Avatar with your StatusNet install.
|
||||
|
||||
Configuration
|
||||
add this to your config.php:
|
||||
addPlugin('Gravatar', array());
|
||||
|
||||
ToDo:
|
||||
Site default all on for gravatar by default
|
||||
Migration Script
|
||||
Localize
|
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 ""
|
11
plugins/Realtime/README
Normal file
11
plugins/Realtime/README
Normal file
@ -0,0 +1,11 @@
|
||||
== TODO ==
|
||||
* i18n
|
||||
* Change in context URL to conversation (try not to construct the URL in JS)
|
||||
* Update mark behaviour (on notice send)
|
||||
* Pause, Send a notice ~ should not update counter
|
||||
* Pause ~ retain up to 50-100 most recent notices
|
||||
* Add geo data
|
||||
* Make it work for Conversation page (perhaps a little tricky)
|
||||
* IE is updating the counter in document title all the time (Not sure if this is still an issue)
|
||||
* Reconsider the timestamp approach
|
||||
|
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);
|
||||
}
|
@ -670,8 +670,7 @@ display:block;
|
||||
text-align:left;
|
||||
width:100%;
|
||||
}
|
||||
.entity_actions a,
|
||||
.entity_remote_subscribe {
|
||||
.entity_actions a {
|
||||
text-decoration:none;
|
||||
font-weight:bold;
|
||||
display:block;
|
||||
@ -686,7 +685,8 @@ border-radius:4px;
|
||||
.entity_actions a,
|
||||
.entity_actions input,
|
||||
.entity_actions p {
|
||||
border:0;
|
||||
border-width:2px;
|
||||
border-style:solid;
|
||||
padding-left:23px;
|
||||
}
|
||||
|
||||
@ -695,14 +695,6 @@ padding-left:23px;
|
||||
padding:2px 4px 1px 26px;
|
||||
}
|
||||
|
||||
.entity_remote_subscribe {
|
||||
padding:4px;
|
||||
border-width:2px;
|
||||
border-style:solid;
|
||||
border-radius:4px;
|
||||
-moz-border-radius:4px;
|
||||
-webkit-border-radius:4px;
|
||||
}
|
||||
.entity_actions .accept {
|
||||
margin-bottom:18px;
|
||||
}
|
||||
@ -1002,13 +994,13 @@ float:left;
|
||||
}
|
||||
.notice-options .notice_delete,
|
||||
.notice-options .notice_reply,
|
||||
.notice-options .form_forward,
|
||||
.notice-options .form_repeat,
|
||||
.notice-options .form_favor,
|
||||
.notice-options .form_disfavor {
|
||||
float:left;
|
||||
margin-left:20%;
|
||||
}
|
||||
.notice-options .form_forward,
|
||||
.notice-options .form_repeat,
|
||||
.notice-options .form_favor,
|
||||
.notice-options .form_disfavor {
|
||||
margin-left:0;
|
||||
@ -1034,12 +1026,12 @@ border-radius:0;
|
||||
-moz-border-radius:0;
|
||||
-webkit-border-radius:0;
|
||||
}
|
||||
.notice-options .form_forward legend,
|
||||
.notice-options .form_repeat legend,
|
||||
.notice-options .form_favor legend,
|
||||
.notice-options .form_disfavor legend {
|
||||
display:none;
|
||||
}
|
||||
.notice-options .form_forward fieldset,
|
||||
.notice-options .form_repeat fieldset,
|
||||
.notice-options .form_favor fieldset,
|
||||
.notice-options .form_disfavor fieldset {
|
||||
border:0;
|
||||
|
@ -30,8 +30,7 @@ border-radius:4px;
|
||||
input, textarea, select, option {
|
||||
font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||
}
|
||||
input, textarea, select,
|
||||
.entity_remote_subscribe {
|
||||
input, textarea, select {
|
||||
border-color:#AAAAAA;
|
||||
}
|
||||
|
||||
@ -56,15 +55,12 @@ background:none;
|
||||
}
|
||||
|
||||
.form_notice.warning #notice_text-count,
|
||||
.form_settings .form_note,
|
||||
.entity_remote_subscribe,
|
||||
.entity_actions .form_notice input.submit {
|
||||
.form_settings .form_note {
|
||||
background-color:#9BB43E;
|
||||
}
|
||||
input.submit,
|
||||
.form_notice.warning #notice_text-count,
|
||||
.form_settings .form_note,
|
||||
.entity_remote_subscribe,
|
||||
.entity_actions a,
|
||||
.entity_actions input,
|
||||
.entity_moderation p,
|
||||
@ -82,16 +78,18 @@ background-color:transparent;
|
||||
input:focus, textarea:focus, select:focus,
|
||||
.form_notice.warning #notice_data-text,
|
||||
.form_notice.warning #notice_text-count,
|
||||
.form_settings .form_note,
|
||||
.entity_remote_subscribe {
|
||||
.form_settings .form_note {
|
||||
border-color:#9BB43E;
|
||||
}
|
||||
input.submit,
|
||||
.entity_remote_subscribe,
|
||||
.entity_actions .form_notice input.submit {
|
||||
input.submit {
|
||||
color:#FFFFFF;
|
||||
}
|
||||
input.submit {
|
||||
.entity_actions input.submit {
|
||||
border-color:transparent;
|
||||
text-shadow:none;
|
||||
}
|
||||
input.submit,
|
||||
.form_notice input.submit {
|
||||
background:#AAAAAA url(../../base/images/illustrations/illu_pattern-01.png) 0 0 repeat-x;
|
||||
text-shadow:0 1px 0 #FFFFFF;
|
||||
color:#000000;
|
||||
@ -109,9 +107,6 @@ box-shadow:3px 3px 3px rgba(194, 194, 194, 0.1);
|
||||
-webkit-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.1);
|
||||
text-shadow:none;
|
||||
}
|
||||
.entity_actions input.submit {
|
||||
text-shadow:none;
|
||||
}
|
||||
|
||||
a,
|
||||
.form_settings input.form_action-primary,
|
||||
|
@ -30,8 +30,7 @@ border-radius:4px;
|
||||
input, textarea, select, option {
|
||||
font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||
}
|
||||
input, textarea, select,
|
||||
.entity_remote_subscribe {
|
||||
input, textarea, select {
|
||||
border-color:#AAAAAA;
|
||||
}
|
||||
|
||||
@ -56,15 +55,12 @@ background:none;
|
||||
}
|
||||
|
||||
.form_notice.warning #notice_text-count,
|
||||
.form_settings .form_note,
|
||||
.entity_remote_subscribe,
|
||||
.entity_actions .form_notice input.submit {
|
||||
.form_settings .form_note {
|
||||
background-color:#9BB43E;
|
||||
}
|
||||
input.submit,
|
||||
.form_notice.warning #notice_text-count,
|
||||
.form_settings .form_note,
|
||||
.entity_remote_subscribe,
|
||||
.entity_actions a,
|
||||
.entity_actions input,
|
||||
.entity_moderation p,
|
||||
@ -82,16 +78,18 @@ background-color:transparent;
|
||||
input:focus, textarea:focus, select:focus,
|
||||
.form_notice.warning #notice_data-text,
|
||||
.form_notice.warning #notice_text-count,
|
||||
.form_settings .form_note,
|
||||
.entity_remote_subscribe {
|
||||
.form_settings .form_note {
|
||||
border-color:#9BB43E;
|
||||
}
|
||||
input.submit,
|
||||
.entity_remote_subscribe,
|
||||
.entity_actions .form_notice input.submit {
|
||||
input.submit {
|
||||
color:#FFFFFF;
|
||||
}
|
||||
input.submit {
|
||||
.entity_actions input.submit {
|
||||
border-color:transparent;
|
||||
text-shadow:none;
|
||||
}
|
||||
input.submit,
|
||||
.form_notice input.submit {
|
||||
background:#AAAAAA url(../../base/images/illustrations/illu_pattern-01.png) 0 0 repeat-x;
|
||||
text-shadow:0 1px 0 #FFFFFF;
|
||||
color:#000000;
|
||||
@ -109,9 +107,6 @@ box-shadow:3px 3px 3px rgba(194, 194, 194, 0.1);
|
||||
-webkit-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.1);
|
||||
text-shadow:none;
|
||||
}
|
||||
.entity_actions input.submit {
|
||||
text-shadow:none;
|
||||
}
|
||||
|
||||
a,
|
||||
.form_settings input.form_action-primary,
|
||||
|
Loading…
Reference in New Issue
Block a user