forked from GNUsocial/gnu-social
Merge branch '0.8.x' into stats
Conflicts: README
This commit is contained in:
commit
76aa85fe5e
3
.gitignore
vendored
3
.gitignore
vendored
@ -13,3 +13,6 @@ dataobject.ini
|
|||||||
*.rej
|
*.rej
|
||||||
.#*
|
.#*
|
||||||
*.swp
|
*.swp
|
||||||
|
.buildpath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
14
EVENTS.txt
14
EVENTS.txt
@ -100,6 +100,20 @@ StartPublicGroupNav: Showing the public group nav menu
|
|||||||
EndPublicGroupNav: At the end of the public group nav menu
|
EndPublicGroupNav: At the end of the public group nav menu
|
||||||
- $action: the current action
|
- $action: the current action
|
||||||
|
|
||||||
|
StartSubGroupNav: Showing the subscriptions group nav menu
|
||||||
|
- $action: the current action
|
||||||
|
|
||||||
|
EndSubGroupNav: At the end of the subscriptions group nav menu
|
||||||
|
- $action: the current action
|
||||||
|
|
||||||
RouterInitialized: After the router instance has been initialized
|
RouterInitialized: After the router instance has been initialized
|
||||||
- $m: the Net_URL_Mapper that has just been set up
|
- $m: the Net_URL_Mapper that has just been set up
|
||||||
|
|
||||||
|
StartLogout: Before logging out
|
||||||
|
- $action: the logout action
|
||||||
|
|
||||||
|
EndLogout: After logging out
|
||||||
|
- $action: the logout action
|
||||||
|
|
||||||
|
ArgsInitialized: After the argument array has been initialized
|
||||||
|
- $args: associative array of arguments, can be modified
|
||||||
|
3
README
3
README
@ -1133,6 +1133,9 @@ welcome: nickname of a user account that sends welcome messages to new
|
|||||||
busy servers it may be a good idea to keep that one just for
|
busy servers it may be a good idea to keep that one just for
|
||||||
'urgent' messages. Default is null; no message.
|
'urgent' messages. Default is null; no message.
|
||||||
|
|
||||||
|
If either of these special user accounts are specified, the users should
|
||||||
|
be created before the configuration is updated.
|
||||||
|
|
||||||
snapshot
|
snapshot
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class AccesstokenAction extends Action
|
|||||||
try {
|
try {
|
||||||
common_debug('getting request from env variables', __FILE__);
|
common_debug('getting request from env variables', __FILE__);
|
||||||
common_remove_magic_from_request();
|
common_remove_magic_from_request();
|
||||||
$req = OAuthRequest::from_request('POST', common_locale_url('accesstoken'));
|
$req = OAuthRequest::from_request('POST', common_local_url('accesstoken'));
|
||||||
common_debug('getting a server', __FILE__);
|
common_debug('getting a server', __FILE__);
|
||||||
$server = omb_oauth_server();
|
$server = omb_oauth_server();
|
||||||
common_debug('fetching the access token', __FILE__);
|
common_debug('fetching the access token', __FILE__);
|
||||||
|
@ -93,7 +93,7 @@ class AllAction extends ProfileAction
|
|||||||
if (common_logged_in()) {
|
if (common_logged_in()) {
|
||||||
$current_user = common_current_user();
|
$current_user = common_current_user();
|
||||||
if ($this->user->id === $current_user->id) {
|
if ($this->user->id === $current_user->id) {
|
||||||
$message .= _('Try subscribing to more people, [join a group](%%action.groups) or post something yourself.');
|
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
|
||||||
} else {
|
} else {
|
||||||
$message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
|
$message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,7 @@ class ApiAction extends Action
|
|||||||
'statuses/friends_timeline',
|
'statuses/friends_timeline',
|
||||||
'statuses/friends',
|
'statuses/friends',
|
||||||
'statuses/replies',
|
'statuses/replies',
|
||||||
|
'statuses/mentions',
|
||||||
'statuses/followers',
|
'statuses/followers',
|
||||||
'favorites/favorites');
|
'favorites/favorites');
|
||||||
|
|
||||||
|
209
actions/attachment.php
Normal file
209
actions/attachment.php
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Show notice attachments
|
||||||
|
*
|
||||||
|
* 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 Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2008-2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||||
|
//require_once INSTALLDIR.'/lib/feedlist.php';
|
||||||
|
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show notice attachments
|
||||||
|
*
|
||||||
|
* @category Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AttachmentAction extends Action
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Attachment object to show
|
||||||
|
*/
|
||||||
|
|
||||||
|
var $attachment = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load attributes based on database arguments
|
||||||
|
*
|
||||||
|
* Loads all the DB stuff
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST array
|
||||||
|
*
|
||||||
|
* @return success flag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
$id = $this->arg('attachment');
|
||||||
|
|
||||||
|
$this->attachment = File::staticGet($id);
|
||||||
|
|
||||||
|
if (!$this->attachment) {
|
||||||
|
$this->clientError(_('No such attachment.'), 404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this action read-only?
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the page
|
||||||
|
*
|
||||||
|
* @return string title of the page
|
||||||
|
*/
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
$a = new Attachment($this->attachment);
|
||||||
|
return $a->title();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last-modified date for page
|
||||||
|
*
|
||||||
|
* When was the content of this page last modified? Based on notice,
|
||||||
|
* profile, avatar.
|
||||||
|
*
|
||||||
|
* @return int last-modified date as unix timestamp
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
function lastModified()
|
||||||
|
{
|
||||||
|
return max(strtotime($this->notice->created),
|
||||||
|
strtotime($this->profile->modified),
|
||||||
|
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity tag for this page
|
||||||
|
*
|
||||||
|
* Shows the ETag for the page, based on the notice ID and timestamps
|
||||||
|
* for the notice, profile, and avatar. It's weak, since we change
|
||||||
|
* the date text "one hour ago", etc.
|
||||||
|
*
|
||||||
|
* @return string etag
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
function etag()
|
||||||
|
{
|
||||||
|
$avtime = ($this->avatar) ?
|
||||||
|
strtotime($this->avatar->modified) : 0;
|
||||||
|
|
||||||
|
return 'W/"' . implode(':', array($this->arg('action'),
|
||||||
|
common_language(),
|
||||||
|
$this->notice->id,
|
||||||
|
strtotime($this->notice->created),
|
||||||
|
strtotime($this->profile->modified),
|
||||||
|
$avtime)) . '"';
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle input
|
||||||
|
*
|
||||||
|
* Only handles get, so just show the page.
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST data (unused)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't show local navigation
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showLocalNavBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the content area of the page
|
||||||
|
*
|
||||||
|
* Shows a single notice list item.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$this->elementStart('ul', array('class' => 'attachments'));
|
||||||
|
$ali = new Attachment($this->attachment, $this);
|
||||||
|
$cnt = $ali->show();
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't show page notice
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showPageNoticeBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show aside: this attachments appears in what notices
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function showSections() {
|
||||||
|
$ns = new AttachmentNoticeSection($this);
|
||||||
|
$ns->show();
|
||||||
|
$atcs = new AttachmentTagCloudSection($this);
|
||||||
|
$atcs->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
141
actions/attachment_ajax.php
Normal file
141
actions/attachment_ajax.php
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Show notice attachments
|
||||||
|
*
|
||||||
|
* 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 Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2008-2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/actions/attachment.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show notice attachments
|
||||||
|
*
|
||||||
|
* @category Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Attachment_ajaxAction extends AttachmentAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Load attributes based on database arguments
|
||||||
|
*
|
||||||
|
* Loads all the DB stuff
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST array
|
||||||
|
*
|
||||||
|
* @return success flag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
if (!$this->attachment) {
|
||||||
|
$this->clientError(_('No such attachment.'), 404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show page, a template method.
|
||||||
|
*
|
||||||
|
* @return nothing
|
||||||
|
*/
|
||||||
|
function showPage()
|
||||||
|
{
|
||||||
|
if (Event::handle('StartShowBody', array($this))) {
|
||||||
|
$this->showCore();
|
||||||
|
Event::handle('EndShowBody', array($this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show core.
|
||||||
|
*
|
||||||
|
* Shows local navigation, content block and aside.
|
||||||
|
*
|
||||||
|
* @return nothing
|
||||||
|
*/
|
||||||
|
function showCore()
|
||||||
|
{
|
||||||
|
$this->elementStart('div', array('id' => 'core'));
|
||||||
|
if (Event::handle('StartShowContentBlock', array($this))) {
|
||||||
|
$this->showContentBlock();
|
||||||
|
Event::handle('EndShowContentBlock', array($this));
|
||||||
|
}
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last-modified date for page
|
||||||
|
*
|
||||||
|
* When was the content of this page last modified? Based on notice,
|
||||||
|
* profile, avatar.
|
||||||
|
*
|
||||||
|
* @return int last-modified date as unix timestamp
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
function lastModified()
|
||||||
|
{
|
||||||
|
return max(strtotime($this->notice->created),
|
||||||
|
strtotime($this->profile->modified),
|
||||||
|
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity tag for this page
|
||||||
|
*
|
||||||
|
* Shows the ETag for the page, based on the notice ID and timestamps
|
||||||
|
* for the notice, profile, and avatar. It's weak, since we change
|
||||||
|
* the date text "one hour ago", etc.
|
||||||
|
*
|
||||||
|
* @return string etag
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
function etag()
|
||||||
|
{
|
||||||
|
$avtime = ($this->avatar) ?
|
||||||
|
strtotime($this->avatar->modified) : 0;
|
||||||
|
|
||||||
|
return 'W/"' . implode(':', array($this->arg('action'),
|
||||||
|
common_language(),
|
||||||
|
$this->notice->id,
|
||||||
|
strtotime($this->notice->created),
|
||||||
|
strtotime($this->profile->modified),
|
||||||
|
$avtime)) . '"';
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
292
actions/attachments.php
Normal file
292
actions/attachments.php
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Show notice attachments
|
||||||
|
*
|
||||||
|
* 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 Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2008-2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||||
|
//require_once INSTALLDIR.'/lib/feedlist.php';
|
||||||
|
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show notice attachments
|
||||||
|
*
|
||||||
|
* @category Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AttachmentsAction extends Action
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Notice object to show
|
||||||
|
*/
|
||||||
|
|
||||||
|
var $notice = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profile of the notice object
|
||||||
|
*/
|
||||||
|
|
||||||
|
var $profile = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Avatar of the profile of the notice object
|
||||||
|
*/
|
||||||
|
|
||||||
|
var $avatar = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this action read-only?
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last-modified date for page
|
||||||
|
*
|
||||||
|
* When was the content of this page last modified? Based on notice,
|
||||||
|
* profile, avatar.
|
||||||
|
*
|
||||||
|
* @return int last-modified date as unix timestamp
|
||||||
|
*/
|
||||||
|
|
||||||
|
function lastModified()
|
||||||
|
{
|
||||||
|
return max(strtotime($this->notice->created),
|
||||||
|
strtotime($this->profile->modified),
|
||||||
|
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity tag for this page
|
||||||
|
*
|
||||||
|
* Shows the ETag for the page, based on the notice ID and timestamps
|
||||||
|
* for the notice, profile, and avatar. It's weak, since we change
|
||||||
|
* the date text "one hour ago", etc.
|
||||||
|
*
|
||||||
|
* @return string etag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function etag()
|
||||||
|
{
|
||||||
|
$avtime = ($this->avatar) ?
|
||||||
|
strtotime($this->avatar->modified) : 0;
|
||||||
|
|
||||||
|
return 'W/"' . implode(':', array($this->arg('action'),
|
||||||
|
common_language(),
|
||||||
|
$this->notice->id,
|
||||||
|
strtotime($this->notice->created),
|
||||||
|
strtotime($this->profile->modified),
|
||||||
|
$avtime)) . '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the page
|
||||||
|
*
|
||||||
|
* @return string title of the page
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return sprintf(_('%1$s\'s status on %2$s'),
|
||||||
|
$this->profile->nickname,
|
||||||
|
common_exact_date($this->notice->created));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load attributes based on database arguments
|
||||||
|
*
|
||||||
|
* Loads all the DB stuff
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST array
|
||||||
|
*
|
||||||
|
* @return success flag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
$id = $this->arg('notice');
|
||||||
|
|
||||||
|
$this->notice = Notice::staticGet($id);
|
||||||
|
|
||||||
|
if (!$this->notice) {
|
||||||
|
$this->clientError(_('No such notice.'), 404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
// STOP if there are no attachments
|
||||||
|
// maybe even redirect if there's a single one
|
||||||
|
// RYM FIXME TODO
|
||||||
|
$this->clientError(_('No such attachment.'), 404);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$this->profile = $this->notice->getProfile();
|
||||||
|
|
||||||
|
if (!$this->profile) {
|
||||||
|
$this->serverError(_('Notice has no profile'), 500);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle input
|
||||||
|
*
|
||||||
|
* Only handles get, so just show the page.
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST data (unused)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
if ($this->notice->is_local == 0) {
|
||||||
|
if (!empty($this->notice->url)) {
|
||||||
|
common_redirect($this->notice->url, 301);
|
||||||
|
} else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) {
|
||||||
|
common_redirect($this->notice->uri, 301);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$f2p = new File_to_post;
|
||||||
|
$f2p->post_id = $this->notice->id;
|
||||||
|
$file = new File;
|
||||||
|
$file->joinAdd($f2p);
|
||||||
|
$file->selectAdd();
|
||||||
|
$file->selectAdd('file.id as id');
|
||||||
|
$count = $file->find(true);
|
||||||
|
if (!$count) return;
|
||||||
|
if (1 === $count) {
|
||||||
|
common_redirect(common_local_url('attachment', array('attachment' => $file->id)), 301);
|
||||||
|
} else {
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't show local navigation
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showLocalNavBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the content area of the page
|
||||||
|
*
|
||||||
|
* Shows a single notice list item.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$al = new AttachmentList($this->notice, $this);
|
||||||
|
$cnt = $al->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't show page notice
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showPageNoticeBlock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't show aside
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showAside() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra <head> content
|
||||||
|
*
|
||||||
|
* We show the microid(s) for the author, if any.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function extraHead()
|
||||||
|
{
|
||||||
|
$user = User::staticGet($this->profile->id);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->emailmicroid && $user->email && $this->notice->uri) {
|
||||||
|
$id = new Microid('mailto:'. $user->email,
|
||||||
|
$this->notice->uri);
|
||||||
|
$this->element('meta', array('name' => 'microid',
|
||||||
|
'content' => $id->toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->jabbermicroid && $user->jabber && $this->notice->uri) {
|
||||||
|
$id = new Microid('xmpp:', $user->jabber,
|
||||||
|
$this->notice->uri);
|
||||||
|
$this->element('meta', array('name' => 'microid',
|
||||||
|
'content' => $id->toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
115
actions/attachments_ajax.php
Normal file
115
actions/attachments_ajax.php
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Show notice attachments
|
||||||
|
*
|
||||||
|
* 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 Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2008-2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||||
|
//require_once INSTALLDIR.'/lib/feedlist.php';
|
||||||
|
require_once INSTALLDIR.'/actions/attachments.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show notice attachments
|
||||||
|
*
|
||||||
|
* @category Personal
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Attachments_ajaxAction extends AttachmentsAction
|
||||||
|
{
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the content area of the page
|
||||||
|
*
|
||||||
|
* Shows a single notice list item.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContentBlock()
|
||||||
|
{
|
||||||
|
$al = new AttachmentList($this->notice, $this);
|
||||||
|
$cnt = $al->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra <head> content
|
||||||
|
*
|
||||||
|
* We show the microid(s) for the author, if any.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function extraHead()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show page, a template method.
|
||||||
|
*
|
||||||
|
* @return nothing
|
||||||
|
*/
|
||||||
|
function showPage()
|
||||||
|
{
|
||||||
|
if (Event::handle('StartShowBody', array($this))) {
|
||||||
|
$this->showCore();
|
||||||
|
Event::handle('EndShowBody', array($this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show core.
|
||||||
|
*
|
||||||
|
* Shows local navigation, content block and aside.
|
||||||
|
*
|
||||||
|
* @return nothing
|
||||||
|
*/
|
||||||
|
function showCore()
|
||||||
|
{
|
||||||
|
$this->elementStart('div', array('id' => 'core'));
|
||||||
|
if (Event::handle('StartShowContentBlock', array($this))) {
|
||||||
|
$this->showContentBlock();
|
||||||
|
Event::handle('EndShowContentBlock', array($this));
|
||||||
|
}
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@
|
|||||||
* @link http://laconi.ca/
|
* @link http://laconi.ca/
|
||||||
*
|
*
|
||||||
* Laconica - a distributed open-source microblogging tool
|
* Laconica - a distributed open-source microblogging tool
|
||||||
* Copyright (C) 2008, Controlez-Vous, Inc.
|
* Copyright (C) 2009, Control Yourself, Inc.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -31,7 +31,7 @@ if (!defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/noticelist.php');
|
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversation tree in the browser
|
* Conversation tree in the browser
|
||||||
@ -42,6 +42,7 @@ require_once(INSTALLDIR.'/lib/noticelist.php');
|
|||||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
* @link http://laconi.ca/
|
* @link http://laconi.ca/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ConversationAction extends Action
|
class ConversationAction extends Action
|
||||||
{
|
{
|
||||||
var $id = null;
|
var $id = null;
|
||||||
@ -69,17 +70,40 @@ class ConversationAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the action
|
||||||
|
*
|
||||||
|
* @param array $args Web and URL arguments
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the page title
|
||||||
|
*
|
||||||
|
* @return string page title
|
||||||
|
*/
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
return _("Conversation");
|
return _("Conversation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show content.
|
||||||
|
*
|
||||||
|
* Display a hierarchical unordered list in the content area.
|
||||||
|
* Uses ConversationTree to do most of the heavy lifting.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
// FIXME this needs to be a tree, not a list
|
// FIXME this needs to be a tree, not a list
|
||||||
@ -95,9 +119,9 @@ class ConversationAction extends Action
|
|||||||
'notice:conversation:'.$this->id,
|
'notice:conversation:'.$this->id,
|
||||||
$offset, $limit);
|
$offset, $limit);
|
||||||
|
|
||||||
$nl = new NoticeList($notices, $this);
|
$ct = new ConversationTree($notices, $this);
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $ct->show();
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$this->page, 'conversation', array('id' => $this->id));
|
$this->page, 'conversation', array('id' => $this->id));
|
||||||
@ -105,3 +129,170 @@ class ConversationAction extends Action
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation tree
|
||||||
|
*
|
||||||
|
* The widget class for displaying a hierarchical list of notices.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ConversationTree extends NoticeList
|
||||||
|
{
|
||||||
|
var $tree = null;
|
||||||
|
var $table = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the tree of notices
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$cnt = 0;
|
||||||
|
|
||||||
|
$this->tree = array();
|
||||||
|
$this->table = array();
|
||||||
|
|
||||||
|
while ($this->notice->fetch()) {
|
||||||
|
|
||||||
|
$cnt++;
|
||||||
|
|
||||||
|
$id = $this->notice->id;
|
||||||
|
$notice = clone($this->notice);
|
||||||
|
|
||||||
|
$this->table[$id] = $notice;
|
||||||
|
|
||||||
|
if (is_null($notice->reply_to)) {
|
||||||
|
$this->tree['root'] = array($notice->id);
|
||||||
|
} else if (array_key_exists($notice->reply_to, $this->tree)) {
|
||||||
|
$this->tree[$notice->reply_to][] = $notice->id;
|
||||||
|
} else {
|
||||||
|
$this->tree[$notice->reply_to] = array($notice->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||||
|
$this->out->element('h2', null, _('Notices'));
|
||||||
|
$this->out->elementStart('ul', array('class' => 'notices'));
|
||||||
|
|
||||||
|
if (array_key_exists('root', $this->tree)) {
|
||||||
|
$rootid = $this->tree['root'][0];
|
||||||
|
$this->showNoticePlus($rootid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
|
return $cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a notice plus its list of children.
|
||||||
|
*
|
||||||
|
* @param integer $id ID of the notice to show
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showNoticePlus($id)
|
||||||
|
{
|
||||||
|
$notice = $this->table[$id];
|
||||||
|
|
||||||
|
// We take responsibility for doing the li
|
||||||
|
|
||||||
|
$this->out->elementStart('li', array('class' => 'hentry notice',
|
||||||
|
'id' => 'notice-' . $this->notice->id));
|
||||||
|
|
||||||
|
$item = $this->newListItem($notice);
|
||||||
|
$item->show();
|
||||||
|
|
||||||
|
if (array_key_exists($id, $this->tree)) {
|
||||||
|
$children = $this->tree[$id];
|
||||||
|
|
||||||
|
$this->out->elementStart('ul', array('class' => 'notices'));
|
||||||
|
|
||||||
|
foreach ($children as $child) {
|
||||||
|
$this->showNoticePlus($child);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override parent class to return our preferred item.
|
||||||
|
*
|
||||||
|
* @param Notice $notice Notice to display
|
||||||
|
*
|
||||||
|
* @return NoticeListItem a list item to show
|
||||||
|
*/
|
||||||
|
|
||||||
|
function newListItem($notice)
|
||||||
|
{
|
||||||
|
return new ConversationTreeItem($notice, $this->out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation tree list item
|
||||||
|
*
|
||||||
|
* Special class of NoticeListItem for use inside conversation trees.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ConversationTreeItem extends NoticeListItem
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* start a single notice.
|
||||||
|
*
|
||||||
|
* The default creates the <li>; we skip, since the ConversationTree
|
||||||
|
* takes care of that.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showStart()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finish the notice
|
||||||
|
*
|
||||||
|
* The default closes the <li>; we skip, since the ConversationTree
|
||||||
|
* takes care of that.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showEnd()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show link to notice conversation page
|
||||||
|
*
|
||||||
|
* Since we're only used on the conversation page, we skip this
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContext()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
@ -112,8 +112,8 @@ class DeletenoticeAction extends DeleteAction
|
|||||||
$this->hidden('token', common_session_token());
|
$this->hidden('token', common_session_token());
|
||||||
$this->hidden('notice', $this->trimmed('notice'));
|
$this->hidden('notice', $this->trimmed('notice'));
|
||||||
$this->element('p', null, _('Are you sure you want to delete this notice?'));
|
$this->element('p', null, _('Are you sure you want to delete this notice?'));
|
||||||
$this->submit('form_action-yes', _('Yes'), 'submit form_action-primary', 'yes');
|
$this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not delete this notice"));
|
||||||
$this->submit('form_action-no', _('No'), 'submit form_action-secondary', 'no');
|
$this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Delete this notice'));
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
}
|
}
|
||||||
|
@ -76,14 +76,22 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
'action' =>
|
'action' =>
|
||||||
common_local_url('designsettings')));
|
common_local_url('designsettings')));
|
||||||
$this->elementStart('fieldset');
|
$this->elementStart('fieldset');
|
||||||
// $this->element('legend', null, _('Design settings'));
|
|
||||||
$this->hidden('token', common_session_token());
|
$this->hidden('token', common_session_token());
|
||||||
|
|
||||||
$this->elementStart('fieldset', array('id' => 'settings_design_background-image'));
|
$this->elementStart('fieldset', array('id' => 'settings_design_background-image'));
|
||||||
$this->element('legend', null, _('Change background image'));
|
$this->element('legend', null, _('Change background image'));
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->element('p', null, _('Upload background image'));
|
$this->element('label', array('for' => 'design_ background-image_file'),
|
||||||
|
_('Upload file'));
|
||||||
|
$this->element('input', array('name' => 'design_background-image_file',
|
||||||
|
'type' => 'file',
|
||||||
|
'id' => 'design_background-image_file'));
|
||||||
|
$this->element('p', 'form_guide', _('You can upload your personal background image. The maximum file size is 2Mb.'));
|
||||||
|
$this->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||||
|
'type' => 'hidden',
|
||||||
|
'id' => 'MAX_FILE_SIZE',
|
||||||
|
'value' => ImageFile::maxFileSizeInt()));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
@ -91,28 +99,59 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
$this->elementStart('fieldset', array('id' => 'settings_design_color'));
|
$this->elementStart('fieldset', array('id' => 'settings_design_color'));
|
||||||
$this->element('legend', null, _('Change colours'));
|
$this->element('legend', null, _('Change colours'));
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
|
|
||||||
|
//This is a JSON object in the DB field. Here for testing. Remove later.
|
||||||
|
$userSwatch = '{"body":{"background-color":"#F0F2F5"},
|
||||||
|
"#content":{"background-color":"#FFFFFF"},
|
||||||
|
"#aside_primary":{"background-color":"#CEE1E9"},
|
||||||
|
"html body":{"color":"#000000"},
|
||||||
|
"a":{"color":"#002E6E"}}';
|
||||||
|
|
||||||
|
//Default theme swatch -- Where should this be stored?
|
||||||
|
$defaultSwatch = array('body' => array('background-color' => '#F0F2F5'),
|
||||||
|
'#content' => array('background-color' => '#FFFFFF'),
|
||||||
|
'#aside_primary' => array('background-color' => '#CEE1E9'),
|
||||||
|
'html body' => array('color' => '#000000'),
|
||||||
|
'a' => array('color' => '#002E6E'));
|
||||||
|
|
||||||
|
$userSwatch = ($userSwatch) ? json_decode($userSwatch, true) : $defaultSwatch;
|
||||||
|
|
||||||
|
$s = 0;
|
||||||
|
$labelSwatch = array('Background',
|
||||||
|
'Content',
|
||||||
|
'Sidebar',
|
||||||
|
'Text',
|
||||||
|
'Links');
|
||||||
|
foreach($userSwatch as $propertyvalue => $value) {
|
||||||
|
$foo = array_values($value);
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->input('color-1', _('Background color'), '#F0F2F5', null);
|
$this->element('label', array('for' => 'swatch-'.$s), _($labelSwatch[$s]));
|
||||||
$this->elementEnd('li');
|
$this->element('input', array('name' => 'swatch-'.$s, //prefer swatch[$s] ?
|
||||||
$this->elementStart('li');
|
'type' => 'text',
|
||||||
$this->input('color-2', _('Content background color'), '#FFFFFF', null);
|
'id' => 'swatch-'.$s,
|
||||||
$this->elementEnd('li');
|
'class' => 'swatch',
|
||||||
$this->elementStart('li');
|
'maxlength' => '7',
|
||||||
$this->input('color-3', _('Sidebar background color'), '#CEE1E9', null);
|
'size' => '7',
|
||||||
$this->elementEnd('li');
|
'value' => $foo[0]));
|
||||||
$this->elementStart('li');
|
|
||||||
$this->input('color-4', _('Text color'), '#000000', null);
|
|
||||||
$this->elementEnd('li');
|
|
||||||
$this->elementStart('li');
|
|
||||||
$this->input('color-5', _('Link color'), '#002E6E', null);
|
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
$s++;
|
||||||
|
}
|
||||||
|
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
$this->element('div', array('id' => 'color-picker'));
|
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
|
|
||||||
|
$this->element('input', array('id' => 'settings_design_reset',
|
||||||
|
'type' => 'reset',
|
||||||
|
'value' => 'Reset',
|
||||||
|
'class' => 'submit form_action-primary',
|
||||||
|
'title' => _('Reset back to default')));
|
||||||
|
$this->submit('save', _('Save'), 'submit form_action-secondary', 'save', _('Save design'));
|
||||||
|
|
||||||
$this->submit('save', _('Save'));
|
/*TODO: Check submitted form values:
|
||||||
|
json_encode(form values)
|
||||||
|
if submitted Swatch == DefaultSwatch, don't store in DB.
|
||||||
|
else store in BD
|
||||||
|
*/
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
|
|
||||||
@ -187,7 +226,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the jCrop stylesheet
|
* Add the Farbtastic stylesheet
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
@ -205,7 +244,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the jCrop scripts
|
* Add the Farbtastic scripts
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
@ -214,7 +253,6 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
|
|
||||||
// if ($this->mode == 'crop') {
|
|
||||||
$farbtasticPack = common_path('js/farbtastic/farbtastic.js');
|
$farbtasticPack = common_path('js/farbtastic/farbtastic.js');
|
||||||
$farbtasticGo = common_path('js/farbtastic/farbtastic.go.js');
|
$farbtasticGo = common_path('js/farbtastic/farbtastic.go.js');
|
||||||
|
|
||||||
@ -222,6 +260,5 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
'src' => $farbtasticPack));
|
'src' => $farbtasticPack));
|
||||||
$this->element('script', array('type' => 'text/javascript',
|
$this->element('script', array('type' => 'text/javascript',
|
||||||
'src' => $farbtasticGo));
|
'src' => $farbtasticGo));
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ class FavoritesrssAction extends Rss10Action
|
|||||||
$c = array('url' => common_local_url('favoritesrss',
|
$c = array('url' => common_local_url('favoritesrss',
|
||||||
array('nickname' =>
|
array('nickname' =>
|
||||||
$user->nickname)),
|
$user->nickname)),
|
||||||
'title' => sprintf(_("%s favorite notices"), $user->nickname),
|
'title' => sprintf(_("%s's favorite notices"), $user->nickname),
|
||||||
'link' => common_local_url('showfavorites',
|
'link' => common_local_url('showfavorites',
|
||||||
array('nickname' =>
|
array('nickname' =>
|
||||||
$user->nickname)),
|
$user->nickname)),
|
||||||
|
@ -191,11 +191,28 @@ class FinishopenidloginAction extends Action
|
|||||||
{
|
{
|
||||||
# FIXME: save invite code before redirect, and check here
|
# FIXME: save invite code before redirect, and check here
|
||||||
|
|
||||||
if (common_config('site', 'closed') || common_config('site', 'inviteonly')) {
|
if (common_config('site', 'closed')) {
|
||||||
$this->clientError(_('Registration not allowed.'));
|
$this->clientError(_('Registration not allowed.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$invite = null;
|
||||||
|
|
||||||
|
if (common_config('site', 'inviteonly')) {
|
||||||
|
$code = $_SESSION['invitecode'];
|
||||||
|
if (empty($code)) {
|
||||||
|
$this->clientError(_('Registration not allowed.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invite = Invitation::staticGet($code);
|
||||||
|
|
||||||
|
if (empty($invite)) {
|
||||||
|
$this->clientError(_('Not a valid invitation code.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$nickname = $this->trimmed('newname');
|
$nickname = $this->trimmed('newname');
|
||||||
|
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if (!Validate::string($nickname, array('min_length' => 1,
|
||||||
@ -257,10 +274,16 @@ class FinishopenidloginAction extends Action
|
|||||||
# XXX: add language
|
# XXX: add language
|
||||||
# XXX: add timezone
|
# XXX: add timezone
|
||||||
|
|
||||||
$user = User::register(array('nickname' => $nickname,
|
$args = array('nickname' => $nickname,
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'fullname' => $fullname,
|
'fullname' => $fullname,
|
||||||
'location' => $location));
|
'location' => $location);
|
||||||
|
|
||||||
|
if (!empty($invite)) {
|
||||||
|
$args['code'] = $invite->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::register($args);
|
||||||
|
|
||||||
$result = oid_link_user($user->id, $canonical, $display);
|
$result = oid_link_user($user->id, $canonical, $display);
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ if (!defined('LACONICA')) {
|
|||||||
|
|
||||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
require_once INSTALLDIR.'/lib/rssaction.php';
|
||||||
|
|
||||||
define('MEMBERS_PER_SECTION', 81);
|
define('MEMBERS_PER_SECTION', 27);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group RSS feed
|
* Group RSS feed
|
||||||
|
@ -70,10 +70,20 @@ class LogoutAction extends Action
|
|||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
$this->clientError(_('Not logged in.'));
|
$this->clientError(_('Not logged in.'));
|
||||||
} else {
|
} else {
|
||||||
common_set_user(null);
|
if (Event::handle('StartLogout', array($this))) {
|
||||||
common_real_login(false); // not logged in
|
$this->logout();
|
||||||
common_forgetme(); // don't log back in!
|
}
|
||||||
|
Event::handle('EndLogout', array($this));
|
||||||
|
|
||||||
common_redirect(common_local_url('public'), 303);
|
common_redirect(common_local_url('public'), 303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function logout()
|
||||||
|
{
|
||||||
|
common_set_user(null);
|
||||||
|
common_real_login(false); // not logged in
|
||||||
|
common_forgetme(); // don't log back in!
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -172,15 +172,54 @@ class NewmessageAction extends Action
|
|||||||
|
|
||||||
$this->notify($user, $this->other, $message);
|
$this->notify($user, $this->other, $message);
|
||||||
|
|
||||||
$url = common_local_url('outbox', array('nickname' => $user->nickname));
|
if ($this->boolean('ajax')) {
|
||||||
|
$this->startHTML('text/xml;charset=utf-8');
|
||||||
|
$this->elementStart('head');
|
||||||
|
$this->element('title', null, _('Message sent'));
|
||||||
|
$this->elementEnd('head');
|
||||||
|
$this->elementStart('body');
|
||||||
|
$this->element('p', array('id' => 'command_result'),
|
||||||
|
sprintf(_('Direct message to %s sent'),
|
||||||
|
$this->other->nickname));
|
||||||
|
$this->elementEnd('body');
|
||||||
|
$this->elementEnd('html');
|
||||||
|
} else {
|
||||||
|
$url = common_local_url('outbox',
|
||||||
|
array('nickname' => $user->nickname));
|
||||||
common_redirect($url, 303);
|
common_redirect($url, 303);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an Ajax-y error message
|
||||||
|
*
|
||||||
|
* Goes back to the browser, where it's shown in a popup.
|
||||||
|
*
|
||||||
|
* @param string $msg Message to show
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function ajaxErrorMsg($msg)
|
||||||
|
{
|
||||||
|
$this->startHTML('text/xml;charset=utf-8', true);
|
||||||
|
$this->elementStart('head');
|
||||||
|
$this->element('title', null, _('Ajax Error'));
|
||||||
|
$this->elementEnd('head');
|
||||||
|
$this->elementStart('body');
|
||||||
|
$this->element('p', array('id' => 'error'), $msg);
|
||||||
|
$this->elementEnd('body');
|
||||||
|
$this->elementEnd('html');
|
||||||
|
}
|
||||||
|
|
||||||
function showForm($msg = null)
|
function showForm($msg = null)
|
||||||
{
|
{
|
||||||
$this->msg = $msg;
|
if ($msg && $this->boolean('ajax')) {
|
||||||
|
$this->ajaxErrorMsg($msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->msg = $msg;
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,8 @@ class NewnoticeAction extends Action
|
|||||||
$replyto = 'false';
|
$replyto = 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
$notice = Notice::saveNew($user->id, $content, 'web', 1,
|
// $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
||||||
|
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
||||||
($replyto == 'false') ? null : $replyto);
|
($replyto == 'false') ? null : $replyto);
|
||||||
|
|
||||||
if (is_string($notice)) {
|
if (is_string($notice)) {
|
||||||
@ -166,6 +167,8 @@ class NewnoticeAction extends Action
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->saveUrls($notice);
|
||||||
|
|
||||||
common_broadcast_notice($notice);
|
common_broadcast_notice($notice);
|
||||||
|
|
||||||
if ($this->boolean('ajax')) {
|
if ($this->boolean('ajax')) {
|
||||||
@ -191,6 +194,24 @@ class NewnoticeAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** save all urls in the notice to the db
|
||||||
|
*
|
||||||
|
* follow redirects and save all available file information
|
||||||
|
* (mimetype, date, size, oembed, etc.)
|
||||||
|
*
|
||||||
|
* @param class $notice Notice to pull URLs from
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function saveUrls($notice) {
|
||||||
|
common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveUrl($data) {
|
||||||
|
list($url, $notice_id) = $data;
|
||||||
|
$zzz = File::processNew($url, $notice_id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show an Ajax-y error message
|
* Show an Ajax-y error message
|
||||||
*
|
*
|
||||||
|
@ -91,9 +91,9 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
$this->element('legend', null, _('Profile information'));
|
$this->element('legend', null, _('Profile information'));
|
||||||
$this->hidden('token', common_session_token());
|
$this->hidden('token', common_session_token());
|
||||||
|
|
||||||
# too much common patterns here... abstractable?
|
// too much common patterns here... abstractable?
|
||||||
|
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
|
if (Event::handle('StartProfileFormData', array($this))) {
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->input('nickname', _('Nickname'),
|
$this->input('nickname', _('Nickname'),
|
||||||
($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname,
|
($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname,
|
||||||
@ -118,6 +118,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
($this->arg('location')) ? $this->arg('location') : $profile->location,
|
($this->arg('location')) ? $this->arg('location') : $profile->location,
|
||||||
_('Where you are, like "City, State (or Region), Country"'));
|
_('Where you are, like "City, State (or Region), Country"'));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
Event::handle('EndProfileFormData', array($this));
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->input('tags', _('Tags'),
|
$this->input('tags', _('Tags'),
|
||||||
($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
|
($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
|
||||||
@ -127,7 +128,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
$language = common_language();
|
$language = common_language();
|
||||||
$this->dropdown('language', _('Language'),
|
$this->dropdown('language', _('Language'),
|
||||||
get_nice_language_list(), _('Preferred language'),
|
get_nice_language_list(), _('Preferred language'),
|
||||||
true, $language);
|
false, $language);
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$timezone = common_timezone();
|
$timezone = common_timezone();
|
||||||
$timezones = array();
|
$timezones = array();
|
||||||
@ -146,12 +147,12 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
($this->arg('autosubscribe')) ?
|
($this->arg('autosubscribe')) ?
|
||||||
$this->boolean('autosubscribe') : $user->autosubscribe);
|
$this->boolean('autosubscribe') : $user->autosubscribe);
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
}
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
$this->submit('save', _('Save'));
|
$this->submit('save', _('Save'));
|
||||||
|
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -165,8 +166,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
|
|
||||||
function handlePost()
|
function handlePost()
|
||||||
{
|
{
|
||||||
# CSRF protection
|
// CSRF protection
|
||||||
|
|
||||||
$token = $this->trimmed('token');
|
$token = $this->trimmed('token');
|
||||||
if (!$token || $token != common_session_token()) {
|
if (!$token || $token != common_session_token()) {
|
||||||
$this->showForm(_('There was a problem with your session token. '.
|
$this->showForm(_('There was a problem with your session token. '.
|
||||||
@ -174,6 +174,8 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Event::handle('StartProfileSaveForm', array($this))) {
|
||||||
|
|
||||||
$nickname = $this->trimmed('nickname');
|
$nickname = $this->trimmed('nickname');
|
||||||
$fullname = $this->trimmed('fullname');
|
$fullname = $this->trimmed('fullname');
|
||||||
$homepage = $this->trimmed('homepage');
|
$homepage = $this->trimmed('homepage');
|
||||||
@ -184,8 +186,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
$timezone = $this->trimmed('timezone');
|
$timezone = $this->trimmed('timezone');
|
||||||
$tagstring = $this->trimmed('tags');
|
$tagstring = $this->trimmed('tags');
|
||||||
|
|
||||||
# Some validation
|
// Some validation
|
||||||
|
|
||||||
if (!Validate::string($nickname, array('min_length' => 1,
|
if (!Validate::string($nickname, array('min_length' => 1,
|
||||||
'max_length' => 64,
|
'max_length' => 64,
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||||
@ -259,13 +260,12 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
$this->serverError(_('Couldn\'t update user.'));
|
$this->serverError(_('Couldn\'t update user.'));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
# Re-initialize language environment if it changed
|
// Re-initialize language environment if it changed
|
||||||
common_init_language();
|
common_init_language();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# XXX: XOR
|
// XXX: XOR
|
||||||
|
|
||||||
if ($user->autosubscribe ^ $autosubscribe) {
|
if ($user->autosubscribe ^ $autosubscribe) {
|
||||||
|
|
||||||
$original = clone($user);
|
$original = clone($user);
|
||||||
@ -303,8 +303,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set the user tags
|
// Set the user tags
|
||||||
|
|
||||||
$result = $user->setSelfTags($tags);
|
$result = $user->setSelfTags($tags);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
@ -313,10 +312,12 @@ class ProfilesettingsAction extends AccountSettingsAction
|
|||||||
}
|
}
|
||||||
|
|
||||||
$user->query('COMMIT');
|
$user->query('COMMIT');
|
||||||
|
Event::handle('EndProfileSaveForm', array($this));
|
||||||
common_broadcast_profile($profile);
|
common_broadcast_profile($profile);
|
||||||
|
|
||||||
$this->showForm(_('Settings saved.'), true);
|
$this->showForm(_('Settings saved.'), true);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function nicknameExists($nickname)
|
function nicknameExists($nickname)
|
||||||
|
@ -55,6 +55,45 @@ class RegisterAction extends Action
|
|||||||
|
|
||||||
var $registered = false;
|
var $registered = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare page to run
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param $args
|
||||||
|
* @return string title
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
$this->code = $this->trimmed('code');
|
||||||
|
|
||||||
|
if (empty($this->code)) {
|
||||||
|
common_ensure_session();
|
||||||
|
if (array_key_exists('invitecode', $_SESSION)) {
|
||||||
|
$this->code = $_SESSION['invitecode'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (common_config('site', 'inviteonly') && empty($this->code)) {
|
||||||
|
$this->clientError(_('Sorry, only invited people can register.'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->code)) {
|
||||||
|
$this->invite = Invitation::staticGet('code', $this->code);
|
||||||
|
if (empty($this->invite)) {
|
||||||
|
$this->clientError(_('Sorry, invalid invitation code.'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Store this in case we need it
|
||||||
|
common_ensure_session();
|
||||||
|
$_SESSION['invitecode'] = $this->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title of the page
|
* Title of the page
|
||||||
*
|
*
|
||||||
@ -108,6 +147,7 @@ class RegisterAction extends Action
|
|||||||
|
|
||||||
function tryRegister()
|
function tryRegister()
|
||||||
{
|
{
|
||||||
|
if (Event::handle('StartRegistrationTry', array($this))) {
|
||||||
$token = $this->trimmed('token');
|
$token = $this->trimmed('token');
|
||||||
if (!$token || $token != common_session_token()) {
|
if (!$token || $token != common_session_token()) {
|
||||||
$this->showForm(_('There was a problem with your session token. '.
|
$this->showForm(_('There was a problem with your session token. '.
|
||||||
@ -123,27 +163,22 @@ class RegisterAction extends Action
|
|||||||
$location = $this->trimmed('location');
|
$location = $this->trimmed('location');
|
||||||
|
|
||||||
// We don't trim these... whitespace is OK in a password!
|
// We don't trim these... whitespace is OK in a password!
|
||||||
|
|
||||||
$password = $this->arg('password');
|
$password = $this->arg('password');
|
||||||
$confirm = $this->arg('confirm');
|
$confirm = $this->arg('confirm');
|
||||||
|
|
||||||
// invitation code, if any
|
// invitation code, if any
|
||||||
|
|
||||||
$code = $this->trimmed('code');
|
$code = $this->trimmed('code');
|
||||||
|
|
||||||
$invite = null;
|
|
||||||
|
|
||||||
if ($code) {
|
if ($code) {
|
||||||
$invite = Invitation::staticGet($code);
|
$invite = Invitation::staticGet($code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (common_config('site', 'inviteonly') && !($code && !empty($invite))) {
|
if (common_config('site', 'inviteonly') && !($code && $invite)) {
|
||||||
$this->clientError(_('Sorry, only invited people can register.'));
|
$this->clientError(_('Sorry, only invited people can register.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input scrubbing
|
// Input scrubbing
|
||||||
|
|
||||||
$nickname = common_canonical_nickname($nickname);
|
$nickname = common_canonical_nickname($nickname);
|
||||||
$email = common_canonical_email($email);
|
$email = common_canonical_email($email);
|
||||||
|
|
||||||
@ -206,6 +241,9 @@ class RegisterAction extends Action
|
|||||||
common_debug('Adding rememberme cookie for ' . $nickname);
|
common_debug('Adding rememberme cookie for ' . $nickname);
|
||||||
common_rememberme($user);
|
common_rememberme($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Event::handle('EndRegistrationTry', array($this));
|
||||||
|
|
||||||
// Re-init language env in case it changed (not yet, but soon)
|
// Re-init language env in case it changed (not yet, but soon)
|
||||||
common_init_language();
|
common_init_language();
|
||||||
$this->showSuccess();
|
$this->showSuccess();
|
||||||
@ -213,6 +251,7 @@ class RegisterAction extends Action
|
|||||||
$this->showForm(_('Invalid username or password.'));
|
$this->showForm(_('Invalid username or password.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the given nickname already exist?
|
* Does the given nickname already exist?
|
||||||
@ -252,8 +291,10 @@ class RegisterAction extends Action
|
|||||||
|
|
||||||
// overrrided to add entry-title class
|
// overrrided to add entry-title class
|
||||||
function showPageTitle() {
|
function showPageTitle() {
|
||||||
|
if (Event::handle('StartShowPageTitle', array($this))) {
|
||||||
$this->element('h1', array('class' => 'entry-title'), $this->title());
|
$this->element('h1', array('class' => 'entry-title'), $this->title());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// overrided to add hentry, and content-inner class
|
// overrided to add hentry, and content-inner class
|
||||||
function showContentBlock()
|
function showContentBlock()
|
||||||
@ -362,11 +403,12 @@ class RegisterAction extends Action
|
|||||||
$this->element('legend', null, 'Account settings');
|
$this->element('legend', null, 'Account settings');
|
||||||
$this->hidden('token', common_session_token());
|
$this->hidden('token', common_session_token());
|
||||||
|
|
||||||
if ($code) {
|
if ($this->code) {
|
||||||
$this->hidden('code', $code);
|
$this->hidden('code', $this->code);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
|
if (Event::handle('StartRegistrationFormData', array($this))) {
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->input('nickname', _('Nickname'), $this->trimmed('nickname'),
|
$this->input('nickname', _('Nickname'), $this->trimmed('nickname'),
|
||||||
_('1-64 lowercase letters or numbers, '.
|
_('1-64 lowercase letters or numbers, '.
|
||||||
@ -381,8 +423,8 @@ class RegisterAction extends Action
|
|||||||
_('Same as password above. Required.'));
|
_('Same as password above. Required.'));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
if (!empty($invite) && $invite->address_type == 'email') {
|
if ($this->invite && $this->invite->address_type == 'email') {
|
||||||
$this->input('email', _('Email'), $invite->address,
|
$this->input('email', _('Email'), $this->invite->address,
|
||||||
_('Used only for updates, announcements, '.
|
_('Used only for updates, announcements, '.
|
||||||
'and password recovery'));
|
'and password recovery'));
|
||||||
} else {
|
} else {
|
||||||
@ -414,6 +456,7 @@ class RegisterAction extends Action
|
|||||||
_('Where you are, like "City, '.
|
_('Where you are, like "City, '.
|
||||||
'State (or Region), Country"'));
|
'State (or Region), Country"'));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
Event::handle('EndRegistrationFormData', array($this));
|
||||||
$this->elementStart('li', array('id' => 'settings_rememberme'));
|
$this->elementStart('li', array('id' => 'settings_rememberme'));
|
||||||
$this->checkbox('rememberme', _('Remember me'),
|
$this->checkbox('rememberme', _('Remember me'),
|
||||||
$this->boolean('rememberme'),
|
$this->boolean('rememberme'),
|
||||||
@ -438,6 +481,7 @@ class RegisterAction extends Action
|
|||||||
'email address, IM address, and phone number.'));
|
'email address, IM address, and phone number.'));
|
||||||
$this->elementEnd('label');
|
$this->elementEnd('label');
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
}
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
$this->submit('submit', _('Register'));
|
$this->submit('submit', _('Register'));
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
@ -519,3 +563,4 @@ class RegisterAction extends Action
|
|||||||
$nav->show();
|
$nav->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +74,9 @@ class ShowfavoritesAction extends Action
|
|||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return sprintf(_("%s favorite notices"), $this->user->nickname);
|
return sprintf(_("%s's favorite notices"), $this->user->nickname);
|
||||||
} else {
|
} else {
|
||||||
return sprintf(_("%s favorite notices, page %d"),
|
return sprintf(_("%s's favorite notices, page %d"),
|
||||||
$this->user->nickname,
|
$this->user->nickname,
|
||||||
$this->page);
|
$this->page);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ if (!defined('LACONICA')) {
|
|||||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||||
|
|
||||||
define('MEMBERS_PER_SECTION', 81);
|
define('MEMBERS_PER_SECTION', 27);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group main page
|
* Group main page
|
||||||
@ -361,7 +361,7 @@ class ShowgroupAction extends Action
|
|||||||
$this->element('p', null, _('(None)'));
|
$this->element('p', null, _('(None)'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cnt == MEMBERS_PER_SECTION) {
|
if ($cnt > MEMBERS_PER_SECTION) {
|
||||||
$this->element('a', array('href' => common_local_url('groupmembers',
|
$this->element('a', array('href' => common_local_url('groupmembers',
|
||||||
array('nickname' => $this->group->nickname))),
|
array('nickname' => $this->group->nickname))),
|
||||||
_('All members'));
|
_('All members'));
|
||||||
|
@ -68,6 +68,9 @@ class ShowstreamAction extends ProfileAction
|
|||||||
} else {
|
} else {
|
||||||
$base = $this->user->nickname;
|
$base = $this->user->nickname;
|
||||||
}
|
}
|
||||||
|
if (!empty($this->tag)) {
|
||||||
|
$base .= sprintf(_(' tagged %s'), $this->tag);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
return $base;
|
return $base;
|
||||||
@ -110,6 +113,15 @@ class ShowstreamAction extends ProfileAction
|
|||||||
|
|
||||||
function getFeeds()
|
function getFeeds()
|
||||||
{
|
{
|
||||||
|
if (!empty($this->tag)) {
|
||||||
|
return array(new Feed(Feed::RSS1,
|
||||||
|
common_local_url('userrss',
|
||||||
|
array('nickname' => $this->user->nickname,
|
||||||
|
'tag' => $this->tag)),
|
||||||
|
sprintf(_('Notice feed for %s tagged %s (RSS 1.0)'),
|
||||||
|
$this->user->nickname, $this->tag)));
|
||||||
|
}
|
||||||
|
|
||||||
return array(new Feed(Feed::RSS1,
|
return array(new Feed(Feed::RSS1,
|
||||||
common_local_url('userrss',
|
common_local_url('userrss',
|
||||||
array('nickname' => $this->user->nickname)),
|
array('nickname' => $this->user->nickname)),
|
||||||
@ -363,7 +375,9 @@ class ShowstreamAction extends ProfileAction
|
|||||||
|
|
||||||
function showNotices()
|
function showNotices()
|
||||||
{
|
{
|
||||||
$notice = $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
$notice = empty($this->tag)
|
||||||
|
? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1)
|
||||||
|
: $this->user->getTaggedNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null, $this->tag);
|
||||||
|
|
||||||
$pnl = new ProfileNoticeList($notice, $this);
|
$pnl = new ProfileNoticeList($notice, $this);
|
||||||
$cnt = $pnl->show();
|
$cnt = $pnl->show();
|
||||||
|
@ -118,6 +118,16 @@ class SubscribersAction extends GalleryAction
|
|||||||
$this->raw(common_markup_to_html($message));
|
$this->raw(common_markup_to_html($message));
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSections()
|
||||||
|
{
|
||||||
|
parent::showSections();
|
||||||
|
$cloud = new SubscribersPeopleTagCloudSection($this);
|
||||||
|
$cloud->show();
|
||||||
|
|
||||||
|
$cloud2 = new SubscribersPeopleSelfTagCloudSection($this);
|
||||||
|
$cloud2->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubscribersList extends ProfileList
|
class SubscribersList extends ProfileList
|
||||||
|
@ -125,6 +125,16 @@ class SubscriptionsAction extends GalleryAction
|
|||||||
$this->raw(common_markup_to_html($message));
|
$this->raw(common_markup_to_html($message));
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSections()
|
||||||
|
{
|
||||||
|
parent::showSections();
|
||||||
|
$cloud = new SubscriptionsPeopleTagCloudSection($this);
|
||||||
|
$cloud->show();
|
||||||
|
|
||||||
|
$cloud2 = new SubscriptionsPeopleSelfTagCloudSection($this);
|
||||||
|
$cloud2->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubscriptionsList extends ProfileList
|
class SubscriptionsList extends ProfileList
|
||||||
|
@ -49,9 +49,10 @@ class TagAction extends Action
|
|||||||
{
|
{
|
||||||
$pop = new PopularNoticeSection($this);
|
$pop = new PopularNoticeSection($this);
|
||||||
$pop->show();
|
$pop->show();
|
||||||
|
$freqatt = new FrequentAttachmentSection($this);
|
||||||
|
$freqatt->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
if ($this->page == 1) {
|
if ($this->page == 1) {
|
||||||
|
@ -133,11 +133,7 @@ class TwitapifriendshipsAction extends TwitterapiAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user_a->isSubscribed($user_b)) {
|
$result = $user_a->isSubscribed($user_b);
|
||||||
$result = 'true';
|
|
||||||
} else {
|
|
||||||
$result = 'false';
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($apidata['content-type']) {
|
switch ($apidata['content-type']) {
|
||||||
case 'xml':
|
case 'xml':
|
||||||
|
@ -144,10 +144,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
break;
|
break;
|
||||||
case 'atom':
|
case 'atom':
|
||||||
if (isset($apidata['api_arg'])) {
|
if (isset($apidata['api_arg'])) {
|
||||||
$selfuri = $selfuri = common_root_url() .
|
$selfuri = common_root_url() .
|
||||||
'api/statuses/friends_timeline/' . $apidata['api_arg'] . '.atom';
|
'api/statuses/friends_timeline/' . $apidata['api_arg'] . '.atom';
|
||||||
} else {
|
} else {
|
||||||
$selfuri = $selfuri = common_root_url() .
|
$selfuri = common_root_url() .
|
||||||
'api/statuses/friends_timeline.atom';
|
'api/statuses/friends_timeline.atom';
|
||||||
}
|
}
|
||||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri);
|
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri);
|
||||||
@ -231,10 +231,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
break;
|
break;
|
||||||
case 'atom':
|
case 'atom':
|
||||||
if (isset($apidata['api_arg'])) {
|
if (isset($apidata['api_arg'])) {
|
||||||
$selfuri = $selfuri = common_root_url() .
|
$selfuri = common_root_url() .
|
||||||
'api/statuses/user_timeline/' . $apidata['api_arg'] . '.atom';
|
'api/statuses/user_timeline/' . $apidata['api_arg'] . '.atom';
|
||||||
} else {
|
} else {
|
||||||
$selfuri = $selfuri = common_root_url() .
|
$selfuri = common_root_url() .
|
||||||
'api/statuses/user_timeline.atom';
|
'api/statuses/user_timeline.atom';
|
||||||
}
|
}
|
||||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink, $selfuri);
|
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink, $selfuri);
|
||||||
@ -344,7 +344,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$this->show($args, $apidata);
|
$this->show($args, $apidata);
|
||||||
}
|
}
|
||||||
|
|
||||||
function replies($args, $apidata)
|
function mentions($args, $apidata)
|
||||||
{
|
{
|
||||||
|
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
@ -360,11 +360,13 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$profile = $user->getProfile();
|
$profile = $user->getProfile();
|
||||||
|
|
||||||
$sitename = common_config('site', 'name');
|
$sitename = common_config('site', 'name');
|
||||||
$title = sprintf(_('%1$s / Updates replying to %2$s'), $sitename, $user->nickname);
|
$title = sprintf(_('%1$s / Updates mentioning %2$s'),
|
||||||
|
$sitename, $user->nickname);
|
||||||
$taguribase = common_config('integration', 'taguri');
|
$taguribase = common_config('integration', 'taguri');
|
||||||
$id = "tag:$taguribase:Replies:".$user->id;
|
$id = "tag:$taguribase:Mentions:".$user->id;
|
||||||
$link = common_local_url('replies', array('nickname' => $user->nickname));
|
$link = common_local_url('replies', array('nickname' => $user->nickname));
|
||||||
$subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'), $sitename, $user->nickname, $profile->getBestName());
|
$subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'),
|
||||||
|
$sitename, $user->nickname, $profile->getBestName());
|
||||||
|
|
||||||
if (!$page) {
|
if (!$page) {
|
||||||
$page = 1;
|
$page = 1;
|
||||||
@ -385,7 +387,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
|
|
||||||
$since = strtotime($this->arg('since'));
|
$since = strtotime($this->arg('since'));
|
||||||
|
|
||||||
$notice = $user->getReplies((($page-1)*20), $count, $since_id, $before_id, $since);
|
$notice = $user->getReplies((($page-1)*20),
|
||||||
|
$count, $since_id, $before_id, $since);
|
||||||
$notices = array();
|
$notices = array();
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
while ($notice->fetch()) {
|
||||||
@ -400,14 +403,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
$this->show_rss_timeline($notices, $title, $link, $subtitle);
|
$this->show_rss_timeline($notices, $title, $link, $subtitle);
|
||||||
break;
|
break;
|
||||||
case 'atom':
|
case 'atom':
|
||||||
if (isset($apidata['api_arg'])) {
|
$selfuri = common_root_url() .
|
||||||
$selfuri = $selfuri = common_root_url() .
|
ltrim($_SERVER['QUERY_STRING'], 'p=');
|
||||||
'api/statuses/replies/' . $apidata['api_arg'] . '.atom';
|
$this->show_atom_timeline($notices, $title, $id, $link, $subtitle,
|
||||||
} else {
|
null, $selfuri);
|
||||||
$selfuri = $selfuri = common_root_url() .
|
|
||||||
'api/statuses/replies.atom';
|
|
||||||
}
|
|
||||||
$this->show_atom_timeline($notices, $title, $id, $link, $subtitle, null, $selfuri);
|
|
||||||
break;
|
break;
|
||||||
case 'json':
|
case 'json':
|
||||||
$this->show_json_timeline($notices);
|
$this->show_json_timeline($notices);
|
||||||
@ -418,6 +417,11 @@ class TwitapistatusesAction extends TwitterapiAction
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function replies($args, $apidata)
|
||||||
|
{
|
||||||
|
call_user_func(array($this, 'mentions'), $args, $apidata);
|
||||||
|
}
|
||||||
|
|
||||||
function show($args, $apidata)
|
function show($args, $apidata)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
|
@ -83,7 +83,7 @@ class TwitapiusersAction extends TwitterapiAction
|
|||||||
$twitter_user['profile_link_color'] = '';
|
$twitter_user['profile_link_color'] = '';
|
||||||
$twitter_user['profile_sidebar_fill_color'] = '';
|
$twitter_user['profile_sidebar_fill_color'] = '';
|
||||||
$twitter_user['profile_sidebar_border_color'] = '';
|
$twitter_user['profile_sidebar_border_color'] = '';
|
||||||
$twitter_user['profile_background_tile'] = 'false';
|
$twitter_user['profile_background_tile'] = false;
|
||||||
|
|
||||||
$faves = DB_DataObject::factory('fave');
|
$faves = DB_DataObject::factory('fave');
|
||||||
$faves->user_id = $user->id;
|
$faves->user_id = $user->id;
|
||||||
@ -103,22 +103,14 @@ class TwitapiusersAction extends TwitterapiAction
|
|||||||
|
|
||||||
if (isset($apidata['user'])) {
|
if (isset($apidata['user'])) {
|
||||||
|
|
||||||
if ($apidata['user']->isSubscribed($profile)) {
|
$twitter_user['following'] = $apidata['user']->isSubscribed($profile);
|
||||||
$twitter_user['following'] = 'true';
|
|
||||||
} else {
|
|
||||||
$twitter_user['following'] = 'false';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notifications on?
|
// Notifications on?
|
||||||
$sub = Subscription::pkeyGet(array('subscriber' =>
|
$sub = Subscription::pkeyGet(array('subscriber' =>
|
||||||
$apidata['user']->id, 'subscribed' => $profile->id));
|
$apidata['user']->id, 'subscribed' => $profile->id));
|
||||||
|
|
||||||
if ($sub) {
|
if ($sub) {
|
||||||
if ($sub->jabber || $sub->sms) {
|
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
|
||||||
$twitter_user['notifications'] = 'true';
|
|
||||||
} else {
|
|
||||||
$twitter_user['notifications'] = 'false';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->checkbox('noticesync',
|
$this->checkbox('noticesend',
|
||||||
_('Automatically send my notices to Twitter.'),
|
_('Automatically send my notices to Twitter.'),
|
||||||
($flink) ?
|
($flink) ?
|
||||||
($flink->noticesync & FOREIGN_NOTICE_SEND) :
|
($flink->noticesync & FOREIGN_NOTICE_SEND) :
|
||||||
@ -158,6 +158,22 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
($flink->friendsync & FOREIGN_FRIEND_RECV) :
|
($flink->friendsync & FOREIGN_FRIEND_RECV) :
|
||||||
false);
|
false);
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
|
||||||
|
if (common_config('twitterbridge','enabled')) {
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->checkbox('noticerecv',
|
||||||
|
_('Import my Friends Timeline.'),
|
||||||
|
($flink) ?
|
||||||
|
($flink->noticesync & FOREIGN_NOTICE_RECV) :
|
||||||
|
false);
|
||||||
|
$this->elementEnd('li');
|
||||||
|
} else {
|
||||||
|
// preserve setting even if bidrection bridge toggled off
|
||||||
|
if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
|
||||||
|
$this->hidden('noticerecv', true, 'noticerecv');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
if ($flink) {
|
if ($flink) {
|
||||||
@ -320,7 +336,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
{
|
{
|
||||||
$screen_name = $this->trimmed('twitter_username');
|
$screen_name = $this->trimmed('twitter_username');
|
||||||
$password = $this->trimmed('twitter_password');
|
$password = $this->trimmed('twitter_password');
|
||||||
$noticesync = $this->boolean('noticesync');
|
$noticesend = $this->boolean('noticesend');
|
||||||
|
$noticerecv = $this->boolean('noticerecv');
|
||||||
$replysync = $this->boolean('replysync');
|
$replysync = $this->boolean('replysync');
|
||||||
$friendsync = $this->boolean('friendsync');
|
$friendsync = $this->boolean('friendsync');
|
||||||
|
|
||||||
@ -363,7 +380,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
$flink->credentials = $password;
|
$flink->credentials = $password;
|
||||||
$flink->created = common_sql_now();
|
$flink->created = common_sql_now();
|
||||||
|
|
||||||
$flink->set_flags($noticesync, $replysync, $friendsync);
|
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
|
||||||
|
|
||||||
$flink_id = $flink->insert();
|
$flink_id = $flink->insert();
|
||||||
|
|
||||||
@ -375,6 +392,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
if ($friendsync) {
|
if ($friendsync) {
|
||||||
save_twitter_friends($user, $twit_user->id, $screen_name, $password);
|
save_twitter_friends($user, $twit_user->id, $screen_name, $password);
|
||||||
|
$flink->last_friendsync = common_sql_now();
|
||||||
|
$flink->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->showForm(_('Twitter settings saved.'), true);
|
$this->showForm(_('Twitter settings saved.'), true);
|
||||||
@ -419,7 +438,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
function savePreferences()
|
function savePreferences()
|
||||||
{
|
{
|
||||||
$noticesync = $this->boolean('noticesync');
|
$noticesend = $this->boolean('noticesend');
|
||||||
|
$noticerecv = $this->boolean('noticerecv');
|
||||||
$friendsync = $this->boolean('friendsync');
|
$friendsync = $this->boolean('friendsync');
|
||||||
$replysync = $this->boolean('replysync');
|
$replysync = $this->boolean('replysync');
|
||||||
|
|
||||||
@ -448,7 +468,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
|||||||
|
|
||||||
$original = clone($flink);
|
$original = clone($flink);
|
||||||
|
|
||||||
$flink->set_flags($noticesync, $replysync, $friendsync);
|
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
|
||||||
|
|
||||||
$result = $flink->update($original);
|
$result = $flink->update($original);
|
||||||
|
|
||||||
|
@ -25,14 +25,15 @@ require_once(INSTALLDIR.'/lib/rssaction.php');
|
|||||||
|
|
||||||
class UserrssAction extends Rss10Action
|
class UserrssAction extends Rss10Action
|
||||||
{
|
{
|
||||||
|
|
||||||
var $user = null;
|
var $user = null;
|
||||||
|
var $tag = null;
|
||||||
|
|
||||||
function prepare($args)
|
function prepare($args)
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$nickname = $this->trimmed('nickname');
|
$nickname = $this->trimmed('nickname');
|
||||||
$this->user = User::staticGet('nickname', $nickname);
|
$this->user = User::staticGet('nickname', $nickname);
|
||||||
|
$this->tag = $this->trimmed('tag');
|
||||||
|
|
||||||
if (!$this->user) {
|
if (!$this->user) {
|
||||||
$this->clientError(_('No such user.'));
|
$this->clientError(_('No such user.'));
|
||||||
@ -42,6 +43,25 @@ class UserrssAction extends Rss10Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getTaggedNotices($tag = null, $limit=0)
|
||||||
|
{
|
||||||
|
$user = $this->user;
|
||||||
|
|
||||||
|
if (is_null($user)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = $user->getTaggedNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit, 0, 0, null, $tag);
|
||||||
|
|
||||||
|
$notices = array();
|
||||||
|
while ($notice->fetch()) {
|
||||||
|
$notices[] = clone($notice);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $notices;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function getNotices($limit=0)
|
function getNotices($limit=0)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -36,4 +36,53 @@ class Fave extends Memcached_DataObject
|
|||||||
{
|
{
|
||||||
return Memcached_DataObject::pkeyGet('Fave', $kv);
|
return Memcached_DataObject::pkeyGet('Fave', $kv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE)
|
||||||
|
{
|
||||||
|
$ids = Notice::stream(array('Fave', '_streamDirect'),
|
||||||
|
array($user_id),
|
||||||
|
'fave:ids_by_user:'.$user_id,
|
||||||
|
$offset, $limit);
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since)
|
||||||
|
{
|
||||||
|
$fav = new Fave();
|
||||||
|
|
||||||
|
$fav->user_id = $user_id;
|
||||||
|
|
||||||
|
$fav->selectAdd();
|
||||||
|
$fav->selectAdd('notice_id');
|
||||||
|
|
||||||
|
if ($since_id != 0) {
|
||||||
|
$fav->whereAdd('notice_id > ' . $since_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($before_id != 0) {
|
||||||
|
$fav->whereAdd('notice_id < ' . $before_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($since)) {
|
||||||
|
$fav->whereAdd('modified > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: we sort by fave time, not by notice time!
|
||||||
|
|
||||||
|
$fav->orderBy('modified DESC');
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$fav->limit($offset, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
|
||||||
|
if ($fav->find()) {
|
||||||
|
while ($fav->fetch()) {
|
||||||
|
$ids[] = $fav->notice_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
123
classes/File.php
Normal file
123
classes/File.php
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
require_once INSTALLDIR.'/classes/File_redirection.php';
|
||||||
|
require_once INSTALLDIR.'/classes/File_oembed.php';
|
||||||
|
require_once INSTALLDIR.'/classes/File_thumbnail.php';
|
||||||
|
require_once INSTALLDIR.'/classes/File_to_post.php';
|
||||||
|
//require_once INSTALLDIR.'/classes/File_redirection.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table Definition for file
|
||||||
|
*/
|
||||||
|
|
||||||
|
class File extends Memcached_DataObject
|
||||||
|
{
|
||||||
|
###START_AUTOCODE
|
||||||
|
/* the code below is auto generated do not remove the above tag */
|
||||||
|
|
||||||
|
public $__table = 'file'; // table name
|
||||||
|
public $id; // int(11) not_null primary_key group_by
|
||||||
|
public $url; // varchar(255) unique_key
|
||||||
|
public $mimetype; // varchar(50)
|
||||||
|
public $size; // int(11) group_by
|
||||||
|
public $title; // varchar(255)
|
||||||
|
public $date; // int(11) group_by
|
||||||
|
public $protected; // int(1) group_by
|
||||||
|
|
||||||
|
/* Static get */
|
||||||
|
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File',$k,$v); }
|
||||||
|
|
||||||
|
/* the code above is auto generated do not remove the tag below */
|
||||||
|
###END_AUTOCODE
|
||||||
|
|
||||||
|
function isProtected($url) {
|
||||||
|
return 'http://www.facebook.com/login.php' === $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAttachments($post_id) {
|
||||||
|
$query = "select file.* from file join file_to_post on (file_id = file.id) join notice on (post_id = notice.id) where post_id = " . $this->escape($post_id);
|
||||||
|
$this->query($query);
|
||||||
|
$att = array();
|
||||||
|
while ($this->fetch()) {
|
||||||
|
$att[] = clone($this);
|
||||||
|
}
|
||||||
|
$this->free();
|
||||||
|
return $att;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveNew($redir_data, $given_url) {
|
||||||
|
$x = new File;
|
||||||
|
$x->url = $given_url;
|
||||||
|
if (!empty($redir_data['protected'])) $x->protected = $redir_data['protected'];
|
||||||
|
if (!empty($redir_data['title'])) $x->title = $redir_data['title'];
|
||||||
|
if (!empty($redir_data['type'])) $x->mimetype = $redir_data['type'];
|
||||||
|
if (!empty($redir_data['size'])) $x->size = intval($redir_data['size']);
|
||||||
|
if (isset($redir_data['time']) && $redir_data['time'] > 0) $x->date = intval($redir_data['time']);
|
||||||
|
$file_id = $x->insert();
|
||||||
|
|
||||||
|
if (isset($redir_data['type'])
|
||||||
|
&& ('text/html' === substr($redir_data['type'], 0, 9))
|
||||||
|
&& ($oembed_data = File_oembed::_getOembed($given_url))
|
||||||
|
&& isset($oembed_data['json'])) {
|
||||||
|
|
||||||
|
File_oembed::saveNew($oembed_data['json'], $file_id);
|
||||||
|
}
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processNew($given_url, $notice_id) {
|
||||||
|
if (empty($given_url)) return -1; // error, no url to process
|
||||||
|
$given_url = File_redirection::_canonUrl($given_url);
|
||||||
|
if (empty($given_url)) return -1; // error, no url to process
|
||||||
|
$file = File::staticGet('url', $given_url);
|
||||||
|
if (empty($file->id)) {
|
||||||
|
$file_redir = File_redirection::staticGet('url', $given_url);
|
||||||
|
if (empty($file_redir->id)) {
|
||||||
|
$redir_data = File_redirection::where($given_url);
|
||||||
|
$redir_url = $redir_data['url'];
|
||||||
|
if ($redir_url === $given_url) {
|
||||||
|
$x = File::saveNew($redir_data, $given_url);
|
||||||
|
$file_id = $x->id;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$x = File::processNew($redir_url, $notice_id);
|
||||||
|
$file_id = $x->id;
|
||||||
|
File_redirection::saveNew($redir_data, $file_id, $given_url);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$file_id = $file_redir->file_id;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$file_id = $file->id;
|
||||||
|
$x = $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($x)) {
|
||||||
|
$x = File::staticGet($file_id);
|
||||||
|
if (empty($x)) die('Impossible!');
|
||||||
|
}
|
||||||
|
|
||||||
|
File_to_post::processNew($file_id, $notice_id);
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
}
|
87
classes/File_oembed.php
Normal file
87
classes/File_oembed.php
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table Definition for file_oembed
|
||||||
|
*/
|
||||||
|
|
||||||
|
class File_oembed extends Memcached_DataObject
|
||||||
|
{
|
||||||
|
###START_AUTOCODE
|
||||||
|
/* the code below is auto generated do not remove the above tag */
|
||||||
|
|
||||||
|
public $__table = 'file_oembed'; // table name
|
||||||
|
public $id; // int(11) not_null primary_key group_by
|
||||||
|
public $file_id; // int(11) unique_key group_by
|
||||||
|
public $version; // varchar(20)
|
||||||
|
public $type; // varchar(20)
|
||||||
|
public $provider; // varchar(50)
|
||||||
|
public $provider_url; // varchar(255)
|
||||||
|
public $width; // int(11) group_by
|
||||||
|
public $height; // int(11) group_by
|
||||||
|
public $html; // blob(65535) blob
|
||||||
|
public $title; // varchar(255)
|
||||||
|
public $author_name; // varchar(50)
|
||||||
|
public $author_url; // varchar(255)
|
||||||
|
public $url; // varchar(255)
|
||||||
|
|
||||||
|
/* Static get */
|
||||||
|
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_oembed',$k,$v); }
|
||||||
|
|
||||||
|
/* the code above is auto generated do not remove the tag below */
|
||||||
|
###END_AUTOCODE
|
||||||
|
|
||||||
|
|
||||||
|
function _getOembed($url, $maxwidth = 500, $maxheight = 400, $format = 'json') {
|
||||||
|
$cmd = 'http://oohembed.com/oohembed/?url=' . urlencode($url);
|
||||||
|
if (is_int($maxwidth)) $cmd .= "&maxwidth=$maxwidth";
|
||||||
|
if (is_int($maxheight)) $cmd .= "&maxheight=$maxheight";
|
||||||
|
if (is_string($format)) $cmd .= "&format=$format";
|
||||||
|
$oe = @file_get_contents($cmd);
|
||||||
|
if (false === $oe) return false;
|
||||||
|
return array($format => (('json' === $format) ? json_decode($oe, true) : $oe));
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveNew($data, $file_id) {
|
||||||
|
$file_oembed = new File_oembed;
|
||||||
|
$file_oembed->file_id = $file_id;
|
||||||
|
$file_oembed->version = $data['version'];
|
||||||
|
$file_oembed->type = $data['type'];
|
||||||
|
if (!empty($data['provider_name'])) $file_oembed->provider = $data['provider_name'];
|
||||||
|
if (!isset($file_oembed->provider) && !empty($data['provide'])) $file_oembed->provider = $data['provider'];
|
||||||
|
if (!empty($data['provide_url'])) $file_oembed->provider_url = $data['provider_url'];
|
||||||
|
if (!empty($data['width'])) $file_oembed->width = intval($data['width']);
|
||||||
|
if (!empty($data['height'])) $file_oembed->height = intval($data['height']);
|
||||||
|
if (!empty($data['html'])) $file_oembed->html = $data['html'];
|
||||||
|
if (!empty($data['title'])) $file_oembed->title = $data['title'];
|
||||||
|
if (!empty($data['author_name'])) $file_oembed->author_name = $data['author_name'];
|
||||||
|
if (!empty($data['author_url'])) $file_oembed->author_url = $data['author_url'];
|
||||||
|
if (!empty($data['url'])) $file_oembed->url = $data['url'];
|
||||||
|
$file_oembed->insert();
|
||||||
|
if (!empty($data['thumbnail_url'])) {
|
||||||
|
File_thumbnail::saveNew($data, $file_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
274
classes/File_redirection.php
Normal file
274
classes/File_redirection.php
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
require_once INSTALLDIR.'/classes/File.php';
|
||||||
|
require_once INSTALLDIR.'/classes/File_oembed.php';
|
||||||
|
|
||||||
|
define('USER_AGENT', 'Laconica user agent / file probe');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table Definition for file_redirection
|
||||||
|
*/
|
||||||
|
|
||||||
|
class File_redirection extends Memcached_DataObject
|
||||||
|
{
|
||||||
|
###START_AUTOCODE
|
||||||
|
/* the code below is auto generated do not remove the above tag */
|
||||||
|
|
||||||
|
public $__table = 'file_redirection'; // table name
|
||||||
|
public $id; // int(11) not_null primary_key group_by
|
||||||
|
public $url; // varchar(255) unique_key
|
||||||
|
public $file_id; // int(11) group_by
|
||||||
|
public $redirections; // int(11) group_by
|
||||||
|
public $httpcode; // int(11) group_by
|
||||||
|
|
||||||
|
/* Static get */
|
||||||
|
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_redirection',$k,$v); }
|
||||||
|
|
||||||
|
/* the code above is auto generated do not remove the tag below */
|
||||||
|
###END_AUTOCODE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function _commonCurl($url, $redirs) {
|
||||||
|
$curlh = curl_init();
|
||||||
|
curl_setopt($curlh, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($curlh, CURLOPT_AUTOREFERER, true); // # setup referer header when folowing redirects
|
||||||
|
curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 10); // # seconds to wait
|
||||||
|
curl_setopt($curlh, CURLOPT_MAXREDIRS, $redirs); // # max number of http redirections to follow
|
||||||
|
curl_setopt($curlh, CURLOPT_USERAGENT, USER_AGENT);
|
||||||
|
curl_setopt($curlh, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
|
||||||
|
curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($curlh, CURLOPT_FILETIME, true);
|
||||||
|
curl_setopt($curlh, CURLOPT_HEADER, true); // Include header in output
|
||||||
|
return $curlh;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _redirectWhere_imp($short_url, $redirs = 10, $protected = false) {
|
||||||
|
if ($redirs < 0) return false;
|
||||||
|
|
||||||
|
// let's see if we know this...
|
||||||
|
$a = File::staticGet('url', $short_url);
|
||||||
|
if (empty($a->id)) {
|
||||||
|
$b = File_redirection::staticGet('url', $short_url);
|
||||||
|
if (empty($b->id)) {
|
||||||
|
// we'll have to figure it out
|
||||||
|
} else {
|
||||||
|
// this is a redirect to $b->file_id
|
||||||
|
$a = File::staticGet($b->file_id);
|
||||||
|
$url = $a->url;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// this is a direct link to $a->url
|
||||||
|
$url = $a->url;
|
||||||
|
}
|
||||||
|
if (isset($url)) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$curlh = File_redirection::_commonCurl($short_url, $redirs);
|
||||||
|
// Don't include body in output
|
||||||
|
curl_setopt($curlh, CURLOPT_NOBODY, true);
|
||||||
|
curl_exec($curlh);
|
||||||
|
$info = curl_getinfo($curlh);
|
||||||
|
curl_close($curlh);
|
||||||
|
|
||||||
|
if (405 == $info['http_code']) {
|
||||||
|
$curlh = File_redirection::_commonCurl($short_url, $redirs);
|
||||||
|
curl_exec($curlh);
|
||||||
|
$info = curl_getinfo($curlh);
|
||||||
|
curl_close($curlh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($info['redirect_count']) && File::isProtected($info['url'])) {
|
||||||
|
return File_redirection::_redirectWhere_imp($short_url, $info['redirect_count'] - 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = array('code' => $info['http_code']
|
||||||
|
, 'redirects' => $info['redirect_count']
|
||||||
|
, 'url' => $info['url']);
|
||||||
|
|
||||||
|
if (!empty($info['content_type'])) $ret['type'] = $info['content_type'];
|
||||||
|
if ($protected) $ret['protected'] = true;
|
||||||
|
if (!empty($info['download_content_length'])) $ret['size'] = $info['download_content_length'];
|
||||||
|
if (isset($info['filetime']) && ($info['filetime'] > 0)) $ret['time'] = $info['filetime'];
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function where($in_url) {
|
||||||
|
$ret = File_redirection::_redirectWhere_imp($in_url);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeShort($long_url) {
|
||||||
|
$long_url = File_redirection::_canonUrl($long_url);
|
||||||
|
// do we already know this long_url and have a short redirection for it?
|
||||||
|
$file = new File;
|
||||||
|
$file_redir = new File_redirection;
|
||||||
|
$file->url = $long_url;
|
||||||
|
$file->joinAdd($file_redir);
|
||||||
|
$file->selectAdd('length(file_redirection.url) as len');
|
||||||
|
$file->limit(1);
|
||||||
|
$file->orderBy('len');
|
||||||
|
$file->find(true);
|
||||||
|
if (!empty($file->id)) {
|
||||||
|
return $file->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if yet unknown, we must find a short url according to user settings
|
||||||
|
$short_url = File_redirection::_userMakeShort($long_url, common_current_user());
|
||||||
|
return $short_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _userMakeShort($long_url, $user) {
|
||||||
|
if (empty($user)) {
|
||||||
|
// common current user does not find a user when called from the XMPP daemon
|
||||||
|
// therefore we'll set one here fix, so that XMPP given URLs may be shortened
|
||||||
|
$user->urlshorteningservice = 'ur1.ca';
|
||||||
|
}
|
||||||
|
$curlh = curl_init();
|
||||||
|
curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 20); // # seconds to wait
|
||||||
|
curl_setopt($curlh, CURLOPT_USERAGENT, 'Laconica');
|
||||||
|
curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
|
||||||
|
switch($user->urlshorteningservice) {
|
||||||
|
case 'ur1.ca':
|
||||||
|
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||||
|
$short_url_service = new LilUrl;
|
||||||
|
$short_url = $short_url_service->shorten($long_url);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2tu.us':
|
||||||
|
$short_url_service = new TightUrl;
|
||||||
|
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||||
|
$short_url = $short_url_service->shorten($long_url);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ptiturl.com':
|
||||||
|
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||||
|
$short_url_service = new PtitUrl;
|
||||||
|
$short_url = $short_url_service->shorten($long_url);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'bit.ly':
|
||||||
|
curl_setopt($curlh, CURLOPT_URL, 'http://bit.ly/api?method=shorten&long_url='.urlencode($long_url));
|
||||||
|
$short_url = current(json_decode(curl_exec($curlh))->results)->hashUrl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'is.gd':
|
||||||
|
curl_setopt($curlh, CURLOPT_URL, 'http://is.gd/api.php?longurl='.urlencode($long_url));
|
||||||
|
$short_url = curl_exec($curlh);
|
||||||
|
break;
|
||||||
|
case 'snipr.com':
|
||||||
|
curl_setopt($curlh, CURLOPT_URL, 'http://snipr.com/site/snip?r=simple&link='.urlencode($long_url));
|
||||||
|
$short_url = curl_exec($curlh);
|
||||||
|
break;
|
||||||
|
case 'metamark.net':
|
||||||
|
curl_setopt($curlh, CURLOPT_URL, 'http://metamark.net/api/rest/simple?long_url='.urlencode($long_url));
|
||||||
|
$short_url = curl_exec($curlh);
|
||||||
|
break;
|
||||||
|
case 'tinyurl.com':
|
||||||
|
curl_setopt($curlh, CURLOPT_URL, 'http://tinyurl.com/api-create.php?url='.urlencode($long_url));
|
||||||
|
$short_url = curl_exec($curlh);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$short_url = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_close($curlh);
|
||||||
|
|
||||||
|
if ($short_url) {
|
||||||
|
$short_url = (string)$short_url;
|
||||||
|
// store it
|
||||||
|
$file = File::staticGet('url', $long_url);
|
||||||
|
if (empty($file)) {
|
||||||
|
$redir_data = File_redirection::where($long_url);
|
||||||
|
$file = File::saveNew($redir_data, $long_url);
|
||||||
|
$file_id = $file->id;
|
||||||
|
if (!empty($redir_data['oembed']['json'])) {
|
||||||
|
File_oembed::saveNew($redir_data['oembed']['json'], $file_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$file_id = $file->id;
|
||||||
|
}
|
||||||
|
$file_redir = File_redirection::staticGet('url', $short_url);
|
||||||
|
if (empty($file_redir)) {
|
||||||
|
$file_redir = new File_redirection;
|
||||||
|
$file_redir->url = $short_url;
|
||||||
|
$file_redir->file_id = $file_id;
|
||||||
|
$file_redir->insert();
|
||||||
|
}
|
||||||
|
return $short_url;
|
||||||
|
}
|
||||||
|
return $long_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _canonUrl($in_url, $default_scheme = 'http://') {
|
||||||
|
if (empty($in_url)) return false;
|
||||||
|
$out_url = $in_url;
|
||||||
|
$p = parse_url($out_url);
|
||||||
|
if (empty($p['host']) || empty($p['scheme'])) {
|
||||||
|
list($scheme) = explode(':', $in_url, 2);
|
||||||
|
switch ($scheme) {
|
||||||
|
case 'fax':
|
||||||
|
case 'tel':
|
||||||
|
$out_url = str_replace('.-()', '', $out_url);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'mailto':
|
||||||
|
case 'aim':
|
||||||
|
case 'jabber':
|
||||||
|
case 'xmpp':
|
||||||
|
// don't touch anything
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$out_url = $default_scheme . ltrim($out_url, '/');
|
||||||
|
$p = parse_url($out_url);
|
||||||
|
if (empty($p['scheme'])) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (('ftp' == $p['scheme']) || ('http' == $p['scheme']) || ('https' == $p['scheme'])) {
|
||||||
|
if (empty($p['host'])) return false;
|
||||||
|
if (empty($p['path'])) {
|
||||||
|
$out_url .= '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveNew($data, $file_id, $url) {
|
||||||
|
$file_redir = new File_redirection;
|
||||||
|
$file_redir->url = $url;
|
||||||
|
$file_redir->file_id = $file_id;
|
||||||
|
$file_redir->redirections = intval($data['redirects']);
|
||||||
|
$file_redir->httpcode = intval($data['code']);
|
||||||
|
$file_redir->insert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
55
classes/File_thumbnail.php
Normal file
55
classes/File_thumbnail.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table Definition for file_thumbnail
|
||||||
|
*/
|
||||||
|
|
||||||
|
class File_thumbnail extends Memcached_DataObject
|
||||||
|
{
|
||||||
|
###START_AUTOCODE
|
||||||
|
/* the code below is auto generated do not remove the above tag */
|
||||||
|
|
||||||
|
public $__table = 'file_thumbnail'; // table name
|
||||||
|
public $id; // int(11) not_null primary_key group_by
|
||||||
|
public $file_id; // int(11) unique_key group_by
|
||||||
|
public $url; // varchar(255) unique_key
|
||||||
|
public $width; // int(11) group_by
|
||||||
|
public $height; // int(11) group_by
|
||||||
|
|
||||||
|
/* Static get */
|
||||||
|
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_thumbnail',$k,$v); }
|
||||||
|
|
||||||
|
/* the code above is auto generated do not remove the tag below */
|
||||||
|
###END_AUTOCODE
|
||||||
|
|
||||||
|
function saveNew($data, $file_id) {
|
||||||
|
$tn = new File_thumbnail;
|
||||||
|
$tn->file_id = $file_id;
|
||||||
|
$tn->url = $data['thumbnail_url'];
|
||||||
|
$tn->width = intval($data['thumbnail_width']);
|
||||||
|
$tn->height = intval($data['thumbnail_height']);
|
||||||
|
$tn->insert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
60
classes/File_to_post.php
Normal file
60
classes/File_to_post.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table Definition for file_to_post
|
||||||
|
*/
|
||||||
|
|
||||||
|
class File_to_post extends Memcached_DataObject
|
||||||
|
{
|
||||||
|
###START_AUTOCODE
|
||||||
|
/* the code below is auto generated do not remove the above tag */
|
||||||
|
|
||||||
|
public $__table = 'file_to_post'; // table name
|
||||||
|
public $id; // int(11) not_null primary_key group_by
|
||||||
|
public $file_id; // int(11) multiple_key group_by
|
||||||
|
public $post_id; // int(11) group_by
|
||||||
|
|
||||||
|
/* Static get */
|
||||||
|
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('File_to_post',$k,$v); }
|
||||||
|
|
||||||
|
/* the code above is auto generated do not remove the tag below */
|
||||||
|
###END_AUTOCODE
|
||||||
|
|
||||||
|
function processNew($file_id, $notice_id) {
|
||||||
|
static $seen = array();
|
||||||
|
if (empty($seen[$notice_id]) || !in_array($file_id, $seen[$notice_id])) {
|
||||||
|
$f2p = new File_to_post;
|
||||||
|
$f2p->file_id = $file_id;
|
||||||
|
$f2p->post_id = $notice_id;
|
||||||
|
$f2p->insert();
|
||||||
|
if (empty($seen[$notice_id])) {
|
||||||
|
$seen[$notice_id] = array($file_id);
|
||||||
|
} else {
|
||||||
|
$seen[$notice_id][] = $file_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,8 @@ class Foreign_link extends Memcached_DataObject
|
|||||||
public $noticesync; // tinyint(1) not_null default_1
|
public $noticesync; // tinyint(1) not_null default_1
|
||||||
public $friendsync; // tinyint(1) not_null default_2
|
public $friendsync; // tinyint(1) not_null default_2
|
||||||
public $profilesync; // tinyint(1) not_null default_1
|
public $profilesync; // tinyint(1) not_null default_1
|
||||||
|
public $last_noticesync; // datetime()
|
||||||
|
public $last_friendsync; // datetime()
|
||||||
public $created; // datetime() not_null
|
public $created; // datetime() not_null
|
||||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||||
|
|
||||||
@ -57,14 +59,20 @@ class Foreign_link extends Memcached_DataObject
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_flags($noticesync, $replysync, $friendsync)
|
function set_flags($noticesend, $noticerecv, $replysync, $friendsync)
|
||||||
{
|
{
|
||||||
if ($noticesync) {
|
if ($noticesend) {
|
||||||
$this->noticesync |= FOREIGN_NOTICE_SEND;
|
$this->noticesync |= FOREIGN_NOTICE_SEND;
|
||||||
} else {
|
} else {
|
||||||
$this->noticesync &= ~FOREIGN_NOTICE_SEND;
|
$this->noticesync &= ~FOREIGN_NOTICE_SEND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($noticerecv) {
|
||||||
|
$this->noticesync |= FOREIGN_NOTICE_RECV;
|
||||||
|
} else {
|
||||||
|
$this->noticesync &= ~FOREIGN_NOTICE_RECV;
|
||||||
|
}
|
||||||
|
|
||||||
if ($replysync) {
|
if ($replysync) {
|
||||||
$this->noticesync |= FOREIGN_NOTICE_SEND_REPLY;
|
$this->noticesync |= FOREIGN_NOTICE_SEND_REPLY;
|
||||||
} else {
|
} else {
|
||||||
|
0
classes/Group_inbox.php
Executable file → Normal file
0
classes/Group_inbox.php
Executable file → Normal file
0
classes/Group_member.php
Executable file → Normal file
0
classes/Group_member.php
Executable file → Normal file
@ -124,8 +124,6 @@ class Notice extends Memcached_DataObject
|
|||||||
|
|
||||||
$profile = Profile::staticGet($profile_id);
|
$profile = Profile::staticGet($profile_id);
|
||||||
|
|
||||||
$final = common_shorten_links($content);
|
|
||||||
|
|
||||||
if (!$profile) {
|
if (!$profile) {
|
||||||
common_log(LOG_ERR, 'Problem saving notice. Unknown user.');
|
common_log(LOG_ERR, 'Problem saving notice. Unknown user.');
|
||||||
return _('Problem saving notice. Unknown user.');
|
return _('Problem saving notice. Unknown user.');
|
||||||
@ -136,7 +134,7 @@ class Notice extends Memcached_DataObject
|
|||||||
return _('Too many notices too fast; take a breather and post again in a few minutes.');
|
return _('Too many notices too fast; take a breather and post again in a few minutes.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $final)) {
|
if (common_config('site', 'dupelimit') > 0 && !Notice::checkDupes($profile_id, $content)) {
|
||||||
common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.');
|
common_log(LOG_WARNING, 'Dupe posting by profile #' . $profile_id . '; throttled.');
|
||||||
return _('Too many duplicate messages too quickly; take a breather and post again in a few minutes.');
|
return _('Too many duplicate messages too quickly; take a breather and post again in a few minutes.');
|
||||||
}
|
}
|
||||||
@ -167,8 +165,8 @@ class Notice extends Memcached_DataObject
|
|||||||
|
|
||||||
$notice->reply_to = $reply_to;
|
$notice->reply_to = $reply_to;
|
||||||
$notice->created = common_sql_now();
|
$notice->created = common_sql_now();
|
||||||
$notice->content = $final;
|
$notice->content = $content;
|
||||||
$notice->rendered = common_render_content($final, $notice);
|
$notice->rendered = common_render_content($content, $notice);
|
||||||
$notice->source = $source;
|
$notice->source = $source;
|
||||||
$notice->uri = $uri;
|
$notice->uri = $uri;
|
||||||
|
|
||||||
@ -206,7 +204,12 @@ class Notice extends Memcached_DataObject
|
|||||||
$notice->saveTags();
|
$notice->saveTags();
|
||||||
$notice->saveGroups();
|
$notice->saveGroups();
|
||||||
|
|
||||||
|
if (common_config('queue', 'enabled')) {
|
||||||
|
$notice->addToAuthorInbox();
|
||||||
|
} else {
|
||||||
$notice->addToInboxes();
|
$notice->addToInboxes();
|
||||||
|
}
|
||||||
|
|
||||||
$notice->query('COMMIT');
|
$notice->query('COMMIT');
|
||||||
|
|
||||||
Event::handle('EndNoticeSave', array($notice));
|
Event::handle('EndNoticeSave', array($notice));
|
||||||
@ -216,8 +219,12 @@ class Notice extends Memcached_DataObject
|
|||||||
# XXX: someone clever could prepend instead of clearing the cache
|
# XXX: someone clever could prepend instead of clearing the cache
|
||||||
|
|
||||||
if (common_config('memcached', 'enabled')) {
|
if (common_config('memcached', 'enabled')) {
|
||||||
|
if (common_config('queue', 'enabled')) {
|
||||||
|
$notice->blowAuthorCaches();
|
||||||
|
} else {
|
||||||
$notice->blowCaches();
|
$notice->blowCaches();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $notice;
|
return $notice;
|
||||||
}
|
}
|
||||||
@ -270,6 +277,16 @@ class Notice extends Memcached_DataObject
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasAttachments() {
|
||||||
|
$post = clone $this;
|
||||||
|
$query = "select count(file_id) as n_attachments from file join file_to_post on (file_id = file.id) join notice on (post_id = notice.id) where post_id = " . $post->escape($post->id);
|
||||||
|
$post->query($query);
|
||||||
|
$post->fetch();
|
||||||
|
$n_attachments = intval($post->n_attachments);
|
||||||
|
$post->free();
|
||||||
|
return $n_attachments;
|
||||||
|
}
|
||||||
|
|
||||||
function blowCaches($blowLast=false)
|
function blowCaches($blowLast=false)
|
||||||
{
|
{
|
||||||
$this->blowSubsCache($blowLast);
|
$this->blowSubsCache($blowLast);
|
||||||
@ -280,6 +297,17 @@ class Notice extends Memcached_DataObject
|
|||||||
$this->blowGroupCache($blowLast);
|
$this->blowGroupCache($blowLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function blowAuthorCaches($blowLast=false)
|
||||||
|
{
|
||||||
|
// Clear the user's cache
|
||||||
|
$cache = common_memcache();
|
||||||
|
if (!empty($cache)) {
|
||||||
|
$cache->delete(common_cache_key('notice_inbox:by_user:'.$this->profile_id));
|
||||||
|
}
|
||||||
|
$this->blowNoticeCache($blowLast);
|
||||||
|
$this->blowPublicCache($blowLast);
|
||||||
|
}
|
||||||
|
|
||||||
function blowGroupCache($blowLast=false)
|
function blowGroupCache($blowLast=false)
|
||||||
{
|
{
|
||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
@ -288,17 +316,17 @@ class Notice extends Memcached_DataObject
|
|||||||
$group_inbox->notice_id = $this->id;
|
$group_inbox->notice_id = $this->id;
|
||||||
if ($group_inbox->find()) {
|
if ($group_inbox->find()) {
|
||||||
while ($group_inbox->fetch()) {
|
while ($group_inbox->fetch()) {
|
||||||
$cache->delete(common_cache_key('group:notices:'.$group_inbox->group_id));
|
$cache->delete(common_cache_key('user_group:notice_ids:' . $group_inbox->group_id));
|
||||||
if ($blowLast) {
|
if ($blowLast) {
|
||||||
$cache->delete(common_cache_key('group:notices:'.$group_inbox->group_id.';last'));
|
$cache->delete(common_cache_key('user_group:notice_ids:' . $group_inbox->group_id.';last'));
|
||||||
}
|
}
|
||||||
$member = new Group_member();
|
$member = new Group_member();
|
||||||
$member->group_id = $group_inbox->group_id;
|
$member->group_id = $group_inbox->group_id;
|
||||||
if ($member->find()) {
|
if ($member->find()) {
|
||||||
while ($member->fetch()) {
|
while ($member->fetch()) {
|
||||||
$cache->delete(common_cache_key('user:notices_with_friends:' . $member->profile_id));
|
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id));
|
||||||
if ($blowLast) {
|
if ($blowLast) {
|
||||||
$cache->delete(common_cache_key('user:notices_with_friends:' . $member->profile_id . ';last'));
|
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id . ';last'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,10 +345,7 @@ class Notice extends Memcached_DataObject
|
|||||||
$tag->notice_id = $this->id;
|
$tag->notice_id = $this->id;
|
||||||
if ($tag->find()) {
|
if ($tag->find()) {
|
||||||
while ($tag->fetch()) {
|
while ($tag->fetch()) {
|
||||||
$cache->delete(common_cache_key('notice_tag:notice_stream:' . $tag->tag));
|
$tag->blowCache($blowLast);
|
||||||
if ($blowLast) {
|
|
||||||
$cache->delete(common_cache_key('notice_tag:notice_stream:' . $tag->tag . ';last'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$tag->free();
|
$tag->free();
|
||||||
@ -341,9 +366,9 @@ class Notice extends Memcached_DataObject
|
|||||||
'WHERE subscription.subscribed = ' . $this->profile_id);
|
'WHERE subscription.subscribed = ' . $this->profile_id);
|
||||||
|
|
||||||
while ($user->fetch()) {
|
while ($user->fetch()) {
|
||||||
$cache->delete(common_cache_key('user:notices_with_friends:' . $user->id));
|
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id));
|
||||||
if ($blowLast) {
|
if ($blowLast) {
|
||||||
$cache->delete(common_cache_key('user:notices_with_friends:' . $user->id . ';last'));
|
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id.';last'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$user->free();
|
$user->free();
|
||||||
@ -355,10 +380,10 @@ class Notice extends Memcached_DataObject
|
|||||||
{
|
{
|
||||||
if ($this->is_local) {
|
if ($this->is_local) {
|
||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
if ($cache) {
|
if (!empty($cache)) {
|
||||||
$cache->delete(common_cache_key('profile:notices:'.$this->profile_id));
|
$cache->delete(common_cache_key('profile:notice_ids:'.$this->profile_id));
|
||||||
if ($blowLast) {
|
if ($blowLast) {
|
||||||
$cache->delete(common_cache_key('profile:notices:'.$this->profile_id.';last'));
|
$cache->delete(common_cache_key('profile:notice_ids:'.$this->profile_id.';last'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,9 +397,9 @@ class Notice extends Memcached_DataObject
|
|||||||
$reply->notice_id = $this->id;
|
$reply->notice_id = $this->id;
|
||||||
if ($reply->find()) {
|
if ($reply->find()) {
|
||||||
while ($reply->fetch()) {
|
while ($reply->fetch()) {
|
||||||
$cache->delete(common_cache_key('user:replies:'.$reply->profile_id));
|
$cache->delete(common_cache_key('reply:stream:'.$reply->profile_id));
|
||||||
if ($blowLast) {
|
if ($blowLast) {
|
||||||
$cache->delete(common_cache_key('user:replies:'.$reply->profile_id.';last'));
|
$cache->delete(common_cache_key('reply:stream:'.$reply->profile_id.';last'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,9 +429,9 @@ class Notice extends Memcached_DataObject
|
|||||||
$fave->notice_id = $this->id;
|
$fave->notice_id = $this->id;
|
||||||
if ($fave->find()) {
|
if ($fave->find()) {
|
||||||
while ($fave->fetch()) {
|
while ($fave->fetch()) {
|
||||||
$cache->delete(common_cache_key('user:faves:'.$fave->user_id));
|
$cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id));
|
||||||
if ($blowLast) {
|
if ($blowLast) {
|
||||||
$cache->delete(common_cache_key('user:faves:'.$fave->user_id.';last'));
|
$cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id.';last'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -602,27 +627,80 @@ class Notice extends Memcached_DataObject
|
|||||||
return $wrapper;
|
return $wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStreamByIds($ids)
|
||||||
|
{
|
||||||
|
$cache = common_memcache();
|
||||||
|
|
||||||
|
if (!empty($cache)) {
|
||||||
|
$notices = array();
|
||||||
|
foreach ($ids as $id) {
|
||||||
|
$notices[] = Notice::staticGet('id', $id);
|
||||||
|
}
|
||||||
|
return new ArrayWrapper($notices);
|
||||||
|
} else {
|
||||||
|
$notice = new Notice();
|
||||||
|
$notice->whereAdd('id in (' . implode(', ', $ids) . ')');
|
||||||
|
$notice->orderBy('id DESC');
|
||||||
|
|
||||||
|
$notice->find();
|
||||||
|
return $notice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function publicStream($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null)
|
function publicStream($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null)
|
||||||
{
|
{
|
||||||
|
$ids = Notice::stream(array('Notice', '_publicStreamDirect'),
|
||||||
|
array(),
|
||||||
|
'public',
|
||||||
|
$offset, $limit, $since_id, $before_id, $since);
|
||||||
|
|
||||||
$parts = array();
|
return Notice::getStreamByIds($ids);
|
||||||
|
}
|
||||||
|
|
||||||
$qry = 'SELECT * FROM notice ';
|
function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null)
|
||||||
|
{
|
||||||
|
$notice = new Notice();
|
||||||
|
|
||||||
|
$notice->selectAdd(); // clears it
|
||||||
|
$notice->selectAdd('id');
|
||||||
|
|
||||||
|
$notice->orderBy('id DESC');
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$notice->limit($offset, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
if (common_config('public', 'localonly')) {
|
if (common_config('public', 'localonly')) {
|
||||||
$parts[] = 'is_local = 1';
|
$notice->whereAdd('is_local = 1');
|
||||||
} else {
|
} else {
|
||||||
# -1 == blacklisted
|
# -1 == blacklisted
|
||||||
$parts[] = 'is_local != -1';
|
$notice->whereAdd('is_local != -1');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($parts) {
|
if ($since_id != 0) {
|
||||||
$qry .= ' WHERE ' . implode(' AND ', $parts);
|
$notice->whereAdd('id > ' . $since_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Notice::getStream($qry,
|
if ($before_id != 0) {
|
||||||
'public',
|
$notice->whereAdd('id < ' . $before_id);
|
||||||
$offset, $limit, $since_id, $before_id, null, $since);
|
}
|
||||||
|
|
||||||
|
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 addToInboxes()
|
function addToInboxes()
|
||||||
@ -648,6 +726,33 @@ class Notice extends Memcached_DataObject
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addToAuthorInbox()
|
||||||
|
{
|
||||||
|
$enabled = common_config('inboxes', 'enabled');
|
||||||
|
|
||||||
|
if ($enabled === true || $enabled === 'transitional') {
|
||||||
|
$user = User::staticGet('id', $this->profile_id);
|
||||||
|
if (empty($user)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$inbox = new Notice_inbox();
|
||||||
|
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
||||||
|
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created) ' .
|
||||||
|
"SELECT $UT.id, " . $this->id . ", '" . $this->created . "' " .
|
||||||
|
"FROM $UT " .
|
||||||
|
"WHERE $UT.id = " . $this->profile_id . ' ' .
|
||||||
|
'AND NOT EXISTS (SELECT user_id, notice_id ' .
|
||||||
|
'FROM notice_inbox ' .
|
||||||
|
"WHERE user_id = " . $this->profile_id . ' '.
|
||||||
|
'AND notice_id = ' . $this->id . ' )';
|
||||||
|
if ($enabled === 'transitional') {
|
||||||
|
$qry .= " AND $UT.inboxed = 1";
|
||||||
|
}
|
||||||
|
$inbox->query($qry);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function saveGroups()
|
function saveGroups()
|
||||||
{
|
{
|
||||||
$enabled = common_config('inboxes', 'enabled');
|
$enabled = common_config('inboxes', 'enabled');
|
||||||
@ -700,6 +805,13 @@ class Notice extends Memcached_DataObject
|
|||||||
|
|
||||||
// FIXME: do this in an offline daemon
|
// FIXME: do this in an offline daemon
|
||||||
|
|
||||||
|
$this->addToGroupInboxes($group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToGroupInboxes($group)
|
||||||
|
{
|
||||||
$inbox = new Notice_inbox();
|
$inbox = new Notice_inbox();
|
||||||
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
||||||
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' .
|
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' .
|
||||||
@ -715,8 +827,6 @@ class Notice extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
$result = $inbox->query($qry);
|
$result = $inbox->query($qry);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveReplies()
|
function saveReplies()
|
||||||
{
|
{
|
||||||
@ -913,4 +1023,59 @@ class Notice extends Memcached_DataObject
|
|||||||
array('notice' => $this->id));
|
array('notice' => $this->id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $before_id=0, $since=null, $tag=null)
|
||||||
|
{
|
||||||
|
$cache = common_memcache();
|
||||||
|
|
||||||
|
if (empty($cache) ||
|
||||||
|
$since_id != 0 || $before_id != 0 || !is_null($since) ||
|
||||||
|
($offset + $limit) > NOTICE_CACHE_WINDOW) {
|
||||||
|
return call_user_func_array($fn, array_merge($args, array($offset, $limit, $since_id,
|
||||||
|
$before_id, $since, $tag)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$idkey = common_cache_key($cachekey);
|
||||||
|
|
||||||
|
$idstr = $cache->get($idkey);
|
||||||
|
|
||||||
|
if (!empty($idstr)) {
|
||||||
|
// Cache hit! Woohoo!
|
||||||
|
$window = explode(',', $idstr);
|
||||||
|
$ids = array_slice($window, $offset, $limit);
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
$laststr = $cache->get($idkey.';last');
|
||||||
|
|
||||||
|
if (!empty($laststr)) {
|
||||||
|
$window = explode(',', $laststr);
|
||||||
|
$last_id = $window[0];
|
||||||
|
$new_ids = call_user_func_array($fn, array_merge($args, array(0, NOTICE_CACHE_WINDOW,
|
||||||
|
$last_id, 0, null, $tag)));
|
||||||
|
|
||||||
|
$new_window = array_merge($new_ids, $window);
|
||||||
|
|
||||||
|
$new_windowstr = implode(',', $new_window);
|
||||||
|
|
||||||
|
$result = $cache->set($idkey, $new_windowstr);
|
||||||
|
$result = $cache->set($idkey . ';last', $new_windowstr);
|
||||||
|
|
||||||
|
$ids = array_slice($new_window, $offset, $limit);
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
$window = call_user_func_array($fn, array_merge($args, array(0, NOTICE_CACHE_WINDOW,
|
||||||
|
0, 0, null, $tag)));
|
||||||
|
|
||||||
|
$windowstr = implode(',', $window);
|
||||||
|
|
||||||
|
$result = $cache->set($idkey, $windowstr);
|
||||||
|
$result = $cache->set($idkey . ';last', $windowstr);
|
||||||
|
|
||||||
|
$ids = array_slice($window, $offset, $limit);
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
/*
|
||||||
* Laconica - a distributed open-source microblogging tool
|
* Laconica - a distributed open-source microblogging tool
|
||||||
* Copyright (C) 2008, Controlez-Vous, Inc.
|
* Copyright (C) 2008, 2009, Control Yourself, Inc.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -21,6 +21,10 @@ if (!defined('LACONICA')) { exit(1); }
|
|||||||
|
|
||||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
// We keep 5 pages of inbox notices in memcache, +1 for pagination check
|
||||||
|
|
||||||
|
define('INBOX_CACHE_WINDOW', 101);
|
||||||
|
|
||||||
class Notice_inbox extends Memcached_DataObject
|
class Notice_inbox extends Memcached_DataObject
|
||||||
{
|
{
|
||||||
###START_AUTOCODE
|
###START_AUTOCODE
|
||||||
@ -38,4 +42,47 @@ class Notice_inbox extends Memcached_DataObject
|
|||||||
|
|
||||||
/* the code above is auto generated do not remove the tag below */
|
/* the code above is auto generated do not remove the tag below */
|
||||||
###END_AUTOCODE
|
###END_AUTOCODE
|
||||||
|
|
||||||
|
function stream($user_id, $offset, $limit, $since_id, $before_id, $since)
|
||||||
|
{
|
||||||
|
return Notice::stream(array('Notice_inbox', '_streamDirect'),
|
||||||
|
array($user_id),
|
||||||
|
'notice_inbox:by_user:'.$user_id,
|
||||||
|
$offset, $limit, $since_id, $before_id, $since);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since)
|
||||||
|
{
|
||||||
|
$inbox = new Notice_inbox();
|
||||||
|
|
||||||
|
$inbox->user_id = $user_id;
|
||||||
|
|
||||||
|
if ($since_id != 0) {
|
||||||
|
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($before_id != 0) {
|
||||||
|
$inbox->whereAdd('notice_id < ' . $before_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($since)) {
|
||||||
|
$inbox->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
$inbox->orderBy('notice_id DESC');
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$inbox->limit($offset, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
|
||||||
|
if ($inbox->find()) {
|
||||||
|
while ($inbox->fetch()) {
|
||||||
|
$ids[] = $inbox->notice_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,21 +37,62 @@ class Notice_tag extends Memcached_DataObject
|
|||||||
###END_AUTOCODE
|
###END_AUTOCODE
|
||||||
|
|
||||||
static function getStream($tag, $offset=0, $limit=20) {
|
static function getStream($tag, $offset=0, $limit=20) {
|
||||||
$qry =
|
|
||||||
'SELECT notice.* ' .
|
|
||||||
'FROM notice JOIN notice_tag ON notice.id = notice_tag.notice_id ' .
|
|
||||||
"WHERE notice_tag.tag = '%s' ";
|
|
||||||
|
|
||||||
return Notice::getStream(sprintf($qry, $tag),
|
$ids = Notice::stream(array('Notice_tag', '_streamDirect'),
|
||||||
'notice_tag:notice_stream:' . common_keyize($tag),
|
array($tag),
|
||||||
|
'notice_tag:notice_ids:' . common_keyize($tag),
|
||||||
$offset, $limit);
|
$offset, $limit);
|
||||||
|
|
||||||
|
return Notice::getStreamByIds($ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
function blowCache()
|
function _streamDirect($tag, $offset, $limit, $since_id, $before_id, $since)
|
||||||
|
{
|
||||||
|
$nt = new Notice_tag();
|
||||||
|
|
||||||
|
$nt->tag = $tag;
|
||||||
|
|
||||||
|
$nt->selectAdd();
|
||||||
|
$nt->selectAdd('notice_id');
|
||||||
|
|
||||||
|
if ($since_id != 0) {
|
||||||
|
$nt->whereAdd('notice_id > ' . $since_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($before_id != 0) {
|
||||||
|
$nt->whereAdd('notice_id < ' . $before_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($since)) {
|
||||||
|
$nt->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
$nt->orderBy('notice_id DESC');
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$nt->limit($offset, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
|
||||||
|
if ($nt->find()) {
|
||||||
|
while ($nt->fetch()) {
|
||||||
|
$ids[] = $nt->notice_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
function blowCache($blowLast=false)
|
||||||
{
|
{
|
||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
if ($cache) {
|
if ($cache) {
|
||||||
$cache->delete(common_cache_key('notice_tag:notice_stream:' . $this->tag));
|
$idkey = common_cache_key('notice_tag:notice_ids:' . common_keyize($this->tag));
|
||||||
|
$cache->delete($idkey);
|
||||||
|
if ($blowLast) {
|
||||||
|
$cache->delete($idkey.';last');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,16 +153,101 @@ class Profile extends Memcached_DataObject
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0)
|
function getTaggedNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null, $tag=null)
|
||||||
{
|
{
|
||||||
$qry =
|
// XXX: I'm not sure this is going to be any faster. It probably isn't.
|
||||||
'SELECT * ' .
|
$ids = Notice::stream(array($this, '_streamTaggedDirect'),
|
||||||
'FROM notice ' .
|
array(),
|
||||||
'WHERE profile_id = %d ';
|
'profile:notice_ids:' . $this->id,
|
||||||
|
$offset, $limit, $since_id, $before_id, $since, $tag);
|
||||||
|
common_debug(print_r($ids, true));
|
||||||
|
return Notice::getStreamByIds($ids);
|
||||||
|
}
|
||||||
|
|
||||||
return Notice::getStream(sprintf($qry, $this->id),
|
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
'profile:notices:'.$this->id,
|
{
|
||||||
$offset, $limit, $since_id, $before_id);
|
// XXX: I'm not sure this is going to be any faster. It probably isn't.
|
||||||
|
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||||
|
array(),
|
||||||
|
'profile:notice_ids:' . $this->id,
|
||||||
|
$offset, $limit, $since_id, $before_id, $since);
|
||||||
|
|
||||||
|
return Notice::getStreamByIds($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _streamTaggedDirect($offset, $limit, $since_id, $before_id, $since=null, $tag=null)
|
||||||
|
{
|
||||||
|
common_debug('_streamTaggedDirect()');
|
||||||
|
$notice = new Notice();
|
||||||
|
$notice->profile_id = $this->id;
|
||||||
|
$query = "select id from notice join notice_tag on id=notice_id where tag='" . $notice->escape($tag) . "' and profile_id=" . $notice->escape($notice->profile_id);
|
||||||
|
if ($since_id != 0) {
|
||||||
|
$query .= " and id > $since_id";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($before_id != 0) {
|
||||||
|
$query .= " and id < $before_id";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($since)) {
|
||||||
|
$query .= " and created > '" . date('Y-m-d H:i:s', $since) . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= ' order by id DESC';
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$query .= " limit $offset, $limit";
|
||||||
|
}
|
||||||
|
$notice->query($query);
|
||||||
|
$ids = array();
|
||||||
|
|
||||||
|
while ($notice->fetch()) {
|
||||||
|
common_debug(print_r($notice, true));
|
||||||
|
$ids[] = $notice->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function _streamDirect($offset, $limit, $since_id, $before_id, $since = null)
|
||||||
|
{
|
||||||
|
$notice = new Notice();
|
||||||
|
|
||||||
|
$notice->profile_id = $this->id;
|
||||||
|
|
||||||
|
$notice->selectAdd();
|
||||||
|
$notice->selectAdd('id');
|
||||||
|
|
||||||
|
if ($since_id != 0) {
|
||||||
|
$notice->whereAdd('id > ' . $since_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($before_id != 0) {
|
||||||
|
$notice->whereAdd('id < ' . $before_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($since)) {
|
||||||
|
$notice->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice->orderBy('id DESC');
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$notice->limit($offset, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
|
||||||
|
if ($notice->find()) {
|
||||||
|
while ($notice->fetch()) {
|
||||||
|
$ids[] = $notice->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMember($group)
|
function isMember($group)
|
||||||
|
0
classes/Related_group.php
Executable file → Normal file
0
classes/Related_group.php
Executable file → Normal file
@ -21,4 +21,47 @@ class Reply extends Memcached_DataObject
|
|||||||
|
|
||||||
/* the code above is auto generated do not remove the tag below */
|
/* the code above is auto generated do not remove the tag below */
|
||||||
###END_AUTOCODE
|
###END_AUTOCODE
|
||||||
|
|
||||||
|
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
|
{
|
||||||
|
$ids = Notice::stream(array('Reply', '_streamDirect'),
|
||||||
|
array($user_id),
|
||||||
|
'reply:stream:' . $user_id,
|
||||||
|
$offset, $limit, $since_id, $before_id, $since);
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _streamDirect($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
|
{
|
||||||
|
$reply = new Reply();
|
||||||
|
$reply->profile_id = $user_id;
|
||||||
|
|
||||||
|
if ($since_id != 0) {
|
||||||
|
$reply->whereAdd('notice_id > ' . $since_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($before_id != 0) {
|
||||||
|
$reply->whereAdd('notice_id < ' . $before_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($since)) {
|
||||||
|
$reply->whereAdd('modified > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
$reply->orderBy('notice_id DESC');
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$reply->limit($offset, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
|
||||||
|
if ($reply->find()) {
|
||||||
|
while ($reply->fetch()) {
|
||||||
|
$ids[] = $reply->notice_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
0
classes/Status_network.php
Executable file → Normal file
0
classes/Status_network.php
Executable file → Normal file
@ -349,30 +349,31 @@ class User extends Memcached_DataObject
|
|||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
|
|
||||||
// XXX: Kind of a hack.
|
// XXX: Kind of a hack.
|
||||||
|
|
||||||
if ($cache) {
|
if ($cache) {
|
||||||
// This is the stream of favorite notices, in rev chron
|
// This is the stream of favorite notices, in rev chron
|
||||||
// order. This forces it into cache.
|
// order. This forces it into cache.
|
||||||
$faves = $this->favoriteNotices(0, NOTICE_CACHE_WINDOW);
|
|
||||||
$cnt = 0;
|
$ids = Fave::stream($this->id, 0, NOTICE_CACHE_WINDOW);
|
||||||
while ($faves->fetch()) {
|
|
||||||
if ($faves->id < $notice->id) {
|
// If it's in the list, then it's a fave
|
||||||
// If we passed it, it's not a fave
|
|
||||||
return false;
|
if (in_array($notice->id, $ids)) {
|
||||||
} else if ($faves->id == $notice->id) {
|
|
||||||
// If it matches a cached notice, then it's a fave
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$cnt++;
|
|
||||||
}
|
|
||||||
// If we're not past the end of the cache window,
|
// If we're not past the end of the cache window,
|
||||||
// then the cache has all available faves, so this one
|
// then the cache has all available faves, so this one
|
||||||
// is not a fave.
|
// is not a fave.
|
||||||
if ($cnt < NOTICE_CACHE_WINDOW) {
|
|
||||||
|
if (count($ids) < NOTICE_CACHE_WINDOW) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, cache doesn't have all faves;
|
// Otherwise, cache doesn't have all faves;
|
||||||
// fall through to the default
|
// fall through to the default
|
||||||
}
|
}
|
||||||
|
|
||||||
$fave = Fave::pkeyGet(array('user_id' => $this->id,
|
$fave = Fave::pkeyGet(array('user_id' => $this->id,
|
||||||
'notice_id' => $notice->id));
|
'notice_id' => $notice->id));
|
||||||
return ((is_null($fave)) ? false : true);
|
return ((is_null($fave)) ? false : true);
|
||||||
@ -401,13 +402,18 @@ class User extends Memcached_DataObject
|
|||||||
|
|
||||||
function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
{
|
{
|
||||||
$qry =
|
$ids = Reply::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
|
||||||
'SELECT notice.* ' .
|
common_debug("Ids = " . implode(',', $ids));
|
||||||
'FROM notice JOIN reply ON notice.id = reply.notice_id ' .
|
return Notice::getStreamByIds($ids);
|
||||||
'WHERE reply.profile_id = %d ';
|
}
|
||||||
return Notice::getStream(sprintf($qry, $this->id),
|
|
||||||
'user:replies:'.$this->id,
|
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) {
|
||||||
$offset, $limit, $since_id, $before_id, null, $since);
|
$profile = $this->getProfile();
|
||||||
|
if (!$profile) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return $profile->getTaggedNotices($tag, $offset, $limit, $since_id, $before_id, $since);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
@ -416,19 +422,14 @@ class User extends Memcached_DataObject
|
|||||||
if (!$profile) {
|
if (!$profile) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return $profile->getNotices($offset, $limit, $since_id, $before_id);
|
return $profile->getNotices($offset, $limit, $since_id, $before_id, $since);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE)
|
function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE)
|
||||||
{
|
{
|
||||||
$qry =
|
$ids = Fave::stream($this->id, $offset, $limit);
|
||||||
'SELECT notice.* ' .
|
return Notice::getStreamByIds($ids);
|
||||||
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
|
|
||||||
'WHERE fave.user_id = %d ';
|
|
||||||
return Notice::getStream(sprintf($qry, $this->id),
|
|
||||||
'user:faves:'.$this->id,
|
|
||||||
$offset, $limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
@ -444,21 +445,17 @@ class User extends Memcached_DataObject
|
|||||||
'SELECT notice.* ' .
|
'SELECT notice.* ' .
|
||||||
'FROM notice JOIN subscription ON notice.profile_id = subscription.subscribed ' .
|
'FROM notice JOIN subscription ON notice.profile_id = subscription.subscribed ' .
|
||||||
'WHERE subscription.subscriber = %d ';
|
'WHERE subscription.subscriber = %d ';
|
||||||
$order = null;
|
|
||||||
} else if ($enabled === true ||
|
|
||||||
($enabled == 'transitional' && $this->inboxed == 1)) {
|
|
||||||
|
|
||||||
$qry =
|
|
||||||
'SELECT notice.* ' .
|
|
||||||
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
|
|
||||||
'WHERE notice_inbox.user_id = %d ';
|
|
||||||
// NOTE: we override ORDER
|
|
||||||
$order = null;
|
|
||||||
}
|
|
||||||
return Notice::getStream(sprintf($qry, $this->id),
|
return Notice::getStream(sprintf($qry, $this->id),
|
||||||
'user:notices_with_friends:' . $this->id,
|
'user:notices_with_friends:' . $this->id,
|
||||||
$offset, $limit, $since_id, $before_id,
|
$offset, $limit, $since_id, $before_id,
|
||||||
$order, $since);
|
$order, $since);
|
||||||
|
} else if ($enabled === true ||
|
||||||
|
($enabled == 'transitional' && $this->inboxed == 1)) {
|
||||||
|
|
||||||
|
$ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
|
||||||
|
|
||||||
|
return Notice::getStreamByIds($ids);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function blowFavesCache()
|
function blowFavesCache()
|
||||||
@ -467,8 +464,8 @@ class User extends Memcached_DataObject
|
|||||||
if ($cache) {
|
if ($cache) {
|
||||||
// Faves don't happen chronologically, so we need to blow
|
// Faves don't happen chronologically, so we need to blow
|
||||||
// ;last cache, too
|
// ;last cache, too
|
||||||
$cache->delete(common_cache_key('user:faves:'.$this->id));
|
$cache->delete(common_cache_key('fave:ids_by_user:'.$this->id));
|
||||||
$cache->delete(common_cache_key('user:faves:'.$this->id).';last');
|
$cache->delete(common_cache_key('fave:ids_by_user:'.$this->id.';last'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
classes/User_group.php
Executable file → Normal file
49
classes/User_group.php
Executable file → Normal file
@ -50,13 +50,50 @@ class User_group extends Memcached_DataObject
|
|||||||
|
|
||||||
function getNotices($offset, $limit)
|
function getNotices($offset, $limit)
|
||||||
{
|
{
|
||||||
$qry =
|
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||||
'SELECT notice.* ' .
|
array(),
|
||||||
'FROM notice JOIN group_inbox ON notice.id = group_inbox.notice_id ' .
|
'user_group:notice_ids:' . $this->id,
|
||||||
'WHERE group_inbox.group_id = %d ';
|
|
||||||
return Notice::getStream(sprintf($qry, $this->id),
|
|
||||||
'group:notices:'.$this->id,
|
|
||||||
$offset, $limit);
|
$offset, $limit);
|
||||||
|
|
||||||
|
return Notice::getStreamByIds($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _streamDirect($offset, $limit, $since_id, $before_id, $since)
|
||||||
|
{
|
||||||
|
$inbox = new Group_inbox();
|
||||||
|
|
||||||
|
$inbox->group_id = $this->id;
|
||||||
|
|
||||||
|
$inbox->selectAdd();
|
||||||
|
$inbox->selectAdd('notice_id');
|
||||||
|
|
||||||
|
if ($since_id != 0) {
|
||||||
|
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($before_id != 0) {
|
||||||
|
$inbox->whereAdd('notice_id < ' . $before_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($since)) {
|
||||||
|
$inbox->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
$inbox->orderBy('notice_id DESC');
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$inbox->limit($offset, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
|
||||||
|
if ($inbox->find()) {
|
||||||
|
while ($inbox->fetch()) {
|
||||||
|
$ids[] = $inbox->notice_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
function allowedNickname($nickname)
|
function allowedNickname($nickname)
|
||||||
|
61
classes/laconica.ini
Executable file → Normal file
61
classes/laconica.ini
Executable file → Normal file
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
[avatar]
|
[avatar]
|
||||||
profile_id = 129
|
profile_id = 129
|
||||||
original = 17
|
original = 17
|
||||||
@ -47,6 +46,64 @@ modified = 384
|
|||||||
notice_id = K
|
notice_id = K
|
||||||
user_id = K
|
user_id = K
|
||||||
|
|
||||||
|
[file]
|
||||||
|
id = 129
|
||||||
|
url = 2
|
||||||
|
mimetype = 2
|
||||||
|
size = 1
|
||||||
|
title = 2
|
||||||
|
date = 1
|
||||||
|
protected = 1
|
||||||
|
|
||||||
|
[file__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[file_oembed]
|
||||||
|
id = 129
|
||||||
|
file_id = 1
|
||||||
|
version = 2
|
||||||
|
type = 2
|
||||||
|
provider = 2
|
||||||
|
provider_url = 2
|
||||||
|
width = 1
|
||||||
|
height = 1
|
||||||
|
html = 34
|
||||||
|
title = 2
|
||||||
|
author_name = 2
|
||||||
|
author_url = 2
|
||||||
|
url = 2
|
||||||
|
|
||||||
|
[file_oembed__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[file_redirection]
|
||||||
|
id = 129
|
||||||
|
url = 2
|
||||||
|
file_id = 1
|
||||||
|
redirections = 1
|
||||||
|
httpcode = 1
|
||||||
|
|
||||||
|
[file_redirection__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[file_thumbnail]
|
||||||
|
id = 129
|
||||||
|
file_id = 1
|
||||||
|
url = 2
|
||||||
|
width = 1
|
||||||
|
height = 1
|
||||||
|
|
||||||
|
[file_thumbnail__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[file_to_post]
|
||||||
|
id = 129
|
||||||
|
file_id = 1
|
||||||
|
post_id = 1
|
||||||
|
|
||||||
|
[file_to_post__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
[foreign_link]
|
[foreign_link]
|
||||||
user_id = 129
|
user_id = 129
|
||||||
foreign_id = 129
|
foreign_id = 129
|
||||||
@ -55,6 +112,8 @@ credentials = 2
|
|||||||
noticesync = 145
|
noticesync = 145
|
||||||
friendsync = 145
|
friendsync = 145
|
||||||
profilesync = 145
|
profilesync = 145
|
||||||
|
last_noticesync = 14
|
||||||
|
last_friendsync = 14
|
||||||
created = 142
|
created = 142
|
||||||
modified = 384
|
modified = 384
|
||||||
|
|
||||||
|
@ -41,3 +41,17 @@ subscribed = profile:id
|
|||||||
[fave]
|
[fave]
|
||||||
notice_id = notice:id
|
notice_id = notice:id
|
||||||
user_id = user:id
|
user_id = user:id
|
||||||
|
|
||||||
|
[file_oembed]
|
||||||
|
file_id = file:id
|
||||||
|
|
||||||
|
[file_redirection]
|
||||||
|
file_id = file:id
|
||||||
|
|
||||||
|
[file_thumbnail]
|
||||||
|
file_id = file:id
|
||||||
|
|
||||||
|
[file_to_post]
|
||||||
|
file_id = file:id
|
||||||
|
post_id = notice:id
|
||||||
|
|
||||||
|
@ -2,4 +2,5 @@ insert into foreign_service
|
|||||||
(id, name, description, created)
|
(id, name, description, created)
|
||||||
values
|
values
|
||||||
('1','Twitter', 'Twitter Micro-blogging service', now()),
|
('1','Twitter', 'Twitter Micro-blogging service', now()),
|
||||||
('2','Facebook', 'Facebook', now());
|
('2','Facebook', 'Facebook', now()),
|
||||||
|
('3','FacebookConnect', 'Facebook Connect', now());
|
||||||
|
@ -119,6 +119,7 @@ create table notice (
|
|||||||
index notice_profile_id_idx (profile_id),
|
index notice_profile_id_idx (profile_id),
|
||||||
index notice_conversation_idx (conversation),
|
index notice_conversation_idx (conversation),
|
||||||
index notice_created_idx (created),
|
index notice_created_idx (created),
|
||||||
|
index notice_replyto_idx (reply_to),
|
||||||
FULLTEXT(content)
|
FULLTEXT(content)
|
||||||
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
|
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
@ -290,6 +291,8 @@ create table foreign_link (
|
|||||||
noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
|
noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
|
||||||
friendsync tinyint not null default 2 comment 'friend synchronization, bit 1 = sync outgoing, bit 2 = sync incoming',
|
friendsync tinyint not null default 2 comment 'friend synchronization, bit 1 = sync outgoing, bit 2 = sync incoming',
|
||||||
profilesync tinyint not null default 1 comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming',
|
profilesync tinyint not null default 1 comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming',
|
||||||
|
last_noticesync datetime default null comment 'last time notices were imported',
|
||||||
|
last_friendsync datetime default null comment 'last time friends were imported',
|
||||||
created datetime not null comment 'date this record was created',
|
created datetime not null comment 'date this record was created',
|
||||||
modified timestamp comment 'date this record was modified',
|
modified timestamp comment 'date this record was modified',
|
||||||
|
|
||||||
@ -422,3 +425,60 @@ create table group_inbox (
|
|||||||
|
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
|
create table file (
|
||||||
|
id integer primary key auto_increment,
|
||||||
|
url varchar(255), mimetype varchar(50),
|
||||||
|
size integer,
|
||||||
|
title varchar(255),
|
||||||
|
date integer(11),
|
||||||
|
protected integer(1),
|
||||||
|
|
||||||
|
unique(url)
|
||||||
|
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
create table file_oembed (
|
||||||
|
id integer primary key auto_increment,
|
||||||
|
file_id integer,
|
||||||
|
version varchar(20),
|
||||||
|
type varchar(20),
|
||||||
|
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),
|
||||||
|
|
||||||
|
unique(file_id)
|
||||||
|
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
create table file_redirection (
|
||||||
|
id integer primary key auto_increment,
|
||||||
|
url varchar(255),
|
||||||
|
file_id integer,
|
||||||
|
redirections integer,
|
||||||
|
httpcode integer,
|
||||||
|
|
||||||
|
unique(url)
|
||||||
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
|
create table file_thumbnail (
|
||||||
|
id integer primary key auto_increment,
|
||||||
|
file_id integer,
|
||||||
|
url varchar(255),
|
||||||
|
width integer,
|
||||||
|
height integer,
|
||||||
|
|
||||||
|
unique(file_id),
|
||||||
|
unique(url)
|
||||||
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
|
create table file_to_post (
|
||||||
|
id integer primary key auto_increment,
|
||||||
|
file_id integer,
|
||||||
|
post_id integer,
|
||||||
|
|
||||||
|
unique(file_id, post_id)
|
||||||
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
@ -291,6 +291,8 @@ create table foreign_link (
|
|||||||
noticesync int not null default 1 /* comment 'notice synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies' */,
|
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' */,
|
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' */,
|
||||||
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
|
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
|
||||||
modified timestamp /* comment 'date this record was modified' */,
|
modified timestamp /* comment 'date this record was modified' */,
|
||||||
|
|
||||||
@ -425,6 +427,64 @@ create table group_inbox (
|
|||||||
);
|
);
|
||||||
create index group_inbox_created_idx on group_inbox using btree(created);
|
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(11),
|
||||||
|
protected integer(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
create sequence file_oembed_seq;
|
||||||
|
create table file_oembed (
|
||||||
|
id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
|
||||||
|
file_id bigint unique,
|
||||||
|
version varchar(20),
|
||||||
|
type varchar(20),
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
|
||||||
|
create sequence file_redirection_seq;
|
||||||
|
create table file_redirection (
|
||||||
|
id bigint default nextval('file_redirection_seq') primary key /* comment 'unique identifier' */,
|
||||||
|
url varchar(255) unique,
|
||||||
|
file_id bigint,
|
||||||
|
redirections integer,
|
||||||
|
httpcode integer
|
||||||
|
);
|
||||||
|
|
||||||
|
create sequence file_thumbnail_seq;
|
||||||
|
create table file_thumbnail (
|
||||||
|
id bigint default nextval('file_thumbnail_seq') primary key /* comment 'unique identifier' */,
|
||||||
|
file_id bigint unique,
|
||||||
|
url varchar(255) unique,
|
||||||
|
width integer,
|
||||||
|
height integer
|
||||||
|
);
|
||||||
|
|
||||||
|
create sequence file_to_post_seq;
|
||||||
|
create table file_to_post (
|
||||||
|
id bigint default nextval('file_to_post_seq') primary key /* comment 'unique identifier' */,
|
||||||
|
file_id bigint,
|
||||||
|
post_id bigint,
|
||||||
|
|
||||||
|
unique(file_id, post_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/* Textsearch stuff */
|
/* Textsearch stuff */
|
||||||
|
|
||||||
create index textsearch_idx on profile using gist(textsearch);
|
create index textsearch_idx on profile using gist(textsearch);
|
||||||
|
@ -8,6 +8,7 @@ VALUES
|
|||||||
('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()),
|
('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()),
|
||||||
('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()),
|
('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()),
|
||||||
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
|
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
|
||||||
|
('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
|
||||||
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
|
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
|
||||||
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
||||||
('identicatools','Laconica Tools','http://bitbucketlabs.net/laconica-tools/', now()),
|
('identicatools','Laconica Tools','http://bitbucketlabs.net/laconica-tools/', now()),
|
||||||
@ -23,6 +24,7 @@ VALUES
|
|||||||
('peoplebrowsr', 'PeopleBrowsr', 'http://www.peoplebrowsr.com/', now()),
|
('peoplebrowsr', 'PeopleBrowsr', 'http://www.peoplebrowsr.com/', now()),
|
||||||
('Pikchur','Pikchur','http://www.pikchur.com/', now()),
|
('Pikchur','Pikchur','http://www.pikchur.com/', now()),
|
||||||
('Ping.fm','Ping.fm','http://ping.fm/', now()),
|
('Ping.fm','Ping.fm','http://ping.fm/', now()),
|
||||||
|
('pingvine','PingVine','http://pingvine.com/', now()),
|
||||||
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
||||||
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
||||||
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
||||||
@ -42,6 +44,7 @@ VALUES
|
|||||||
('twidge','Twidge','http://software.complete.org/twidge', now()),
|
('twidge','Twidge','http://software.complete.org/twidge', now()),
|
||||||
('twidroid','twidroid','http://www.twidroid.com/', now()),
|
('twidroid','twidroid','http://www.twidroid.com/', now()),
|
||||||
('twittelator','Twittelator','http://www.stone.com/iPhone/Twittelator/', now()),
|
('twittelator','Twittelator','http://www.stone.com/iPhone/Twittelator/', now()),
|
||||||
|
('twitter','Twitter','http://twitter.com/', now()),
|
||||||
('twitterfeed','twitterfeed','http://twitterfeed.com/', now()),
|
('twitterfeed','twitterfeed','http://twitterfeed.com/', now()),
|
||||||
('twitterphoto','TwitterPhoto','http://richfish.org/twitterphoto/', now()),
|
('twitterphoto','TwitterPhoto','http://richfish.org/twitterphoto/', now()),
|
||||||
('twitterpm','Net::Twitter','http://search.cpan.org/dist/Net-Twitter/', now()),
|
('twitterpm','Net::Twitter','http://search.cpan.org/dist/Net-Twitter/', now()),
|
||||||
|
@ -2358,6 +2358,8 @@ class DB_DataObject extends DB_DataObject_Overload
|
|||||||
$_DB_DATAOBJECT['QUERYENDTIME'] = $time = $t[0]+$t[1];
|
$_DB_DATAOBJECT['QUERYENDTIME'] = $time = $t[0]+$t[1];
|
||||||
|
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
if ($_DB_driver == 'DB') {
|
if ($_DB_driver == 'DB') {
|
||||||
$result = $DB->query($string);
|
$result = $DB->query($string);
|
||||||
} else {
|
} else {
|
||||||
@ -2375,7 +2377,18 @@ class DB_DataObject extends DB_DataObject_Overload
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// try to reconnect, at most 3 times
|
||||||
|
$again = false;
|
||||||
|
if (is_a($result, 'PEAR_Error')
|
||||||
|
AND $result->getCode() == DB_ERROR_NODBSELECTED
|
||||||
|
AND $cpt++<3) {
|
||||||
|
$DB->disconnect();
|
||||||
|
sleep(1);
|
||||||
|
$DB->connect($DB->dsn);
|
||||||
|
$again = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while ($again);
|
||||||
|
|
||||||
if (is_a($result,'PEAR_Error')) {
|
if (is_a($result,'PEAR_Error')) {
|
||||||
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
|
if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
// Copyright 2004-2008 Facebook. All Rights Reserved.
|
// Copyright 2004-2009 Facebook. All Rights Reserved.
|
||||||
//
|
//
|
||||||
// +---------------------------------------------------------------------------+
|
// +---------------------------------------------------------------------------+
|
||||||
// | Facebook Platform PHP5 client |
|
// | Facebook Platform PHP5 client |
|
||||||
@ -30,13 +30,12 @@
|
|||||||
// +---------------------------------------------------------------------------+
|
// +---------------------------------------------------------------------------+
|
||||||
// | For help with this library, contact developers-help@facebook.com |
|
// | For help with this library, contact developers-help@facebook.com |
|
||||||
// +---------------------------------------------------------------------------+
|
// +---------------------------------------------------------------------------+
|
||||||
//
|
|
||||||
include_once 'facebookapi_php5_restlib.php';
|
include_once 'facebookapi_php5_restlib.php';
|
||||||
|
|
||||||
define('FACEBOOK_API_VALIDATION_ERROR', 1);
|
define('FACEBOOK_API_VALIDATION_ERROR', 1);
|
||||||
class Facebook {
|
class Facebook {
|
||||||
public $api_client;
|
public $api_client;
|
||||||
|
|
||||||
public $api_key;
|
public $api_key;
|
||||||
public $secret;
|
public $secret;
|
||||||
public $generate_session_secret;
|
public $generate_session_secret;
|
||||||
@ -213,9 +212,40 @@ class Facebook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalidate the session currently being used, and clear any state associated with it
|
// Invalidate the session currently being used, and clear any state associated
|
||||||
|
// with it. Note that the user will still remain logged into Facebook.
|
||||||
public function expire_session() {
|
public function expire_session() {
|
||||||
if ($this->api_client->auth_expireSession()) {
|
if ($this->api_client->auth_expireSession()) {
|
||||||
|
$this->clear_cookie_state();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Logs the user out of all temporary application sessions as well as their
|
||||||
|
* Facebook session. Note this will only work if the user has a valid current
|
||||||
|
* session with the application.
|
||||||
|
*
|
||||||
|
* @param string $next URL to redirect to upon logging out
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function logout($next) {
|
||||||
|
$logout_url = $this->get_logout_url($next);
|
||||||
|
|
||||||
|
// Clear any stored state
|
||||||
|
$this->clear_cookie_state();
|
||||||
|
|
||||||
|
$this->redirect($logout_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears any persistent state stored about the user, including
|
||||||
|
* cookies and information related to the current session in the
|
||||||
|
* client.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function clear_cookie_state() {
|
||||||
if (!$this->in_fb_canvas() && isset($_COOKIE[$this->api_key . '_user'])) {
|
if (!$this->in_fb_canvas() && isset($_COOKIE[$this->api_key . '_user'])) {
|
||||||
$cookies = array('user', 'session_key', 'expires', 'ss');
|
$cookies = array('user', 'session_key', 'expires', 'ss');
|
||||||
foreach ($cookies as $name) {
|
foreach ($cookies as $name) {
|
||||||
@ -229,10 +259,6 @@ class Facebook {
|
|||||||
// now, clear the rest of the stored state
|
// now, clear the rest of the stored state
|
||||||
$this->user = 0;
|
$this->user = 0;
|
||||||
$this->api_client->session_key = 0;
|
$this->api_client->session_key = 0;
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function redirect($url) {
|
public function redirect($url) {
|
||||||
@ -249,7 +275,8 @@ class Facebook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function in_frame() {
|
public function in_frame() {
|
||||||
return isset($this->fb_params['in_canvas']) || isset($this->fb_params['in_iframe']);
|
return isset($this->fb_params['in_canvas'])
|
||||||
|
|| isset($this->fb_params['in_iframe']);
|
||||||
}
|
}
|
||||||
public function in_fb_canvas() {
|
public function in_fb_canvas() {
|
||||||
return isset($this->fb_params['in_canvas']);
|
return isset($this->fb_params['in_canvas']);
|
||||||
@ -296,14 +323,42 @@ class Facebook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function get_add_url($next=null) {
|
public function get_add_url($next=null) {
|
||||||
return self::get_facebook_url().'/add.php?api_key='.$this->api_key .
|
$page = self::get_facebook_url().'/add.php';
|
||||||
($next ? '&next=' . urlencode($next) : '');
|
$params = array('api_key' => $this->api_key);
|
||||||
|
|
||||||
|
if ($next) {
|
||||||
|
$params['next'] = $next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $page . '?' . http_build_query($params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_login_url($next, $canvas) {
|
public function get_login_url($next, $canvas) {
|
||||||
return self::get_facebook_url().'/login.php?v=1.0&api_key=' . $this->api_key .
|
$page = self::get_facebook_url().'/login.php';
|
||||||
($next ? '&next=' . urlencode($next) : '') .
|
$params = array('api_key' => $this->api_key,
|
||||||
($canvas ? '&canvas' : '');
|
'v' => '1.0');
|
||||||
|
|
||||||
|
if ($next) {
|
||||||
|
$params['next'] = $next;
|
||||||
|
}
|
||||||
|
if ($canvas) {
|
||||||
|
$params['canvas'] = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $page . '?' . http_build_query($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_logout_url($next) {
|
||||||
|
$page = self::get_facebook_url().'/logout.php';
|
||||||
|
$params = array('app_key' => $this->api_key,
|
||||||
|
'session_key' => $this->api_client->session_key);
|
||||||
|
|
||||||
|
if ($next) {
|
||||||
|
$params['connect_next'] = 1;
|
||||||
|
$params['next'] = $next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $page . '?' . http_build_query($params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function set_user($user, $session_key, $expires=null, $session_secret=null) {
|
public function set_user($user, $session_key, $expires=null, $session_secret=null) {
|
||||||
@ -410,7 +465,20 @@ class Facebook {
|
|||||||
return $fb_params;
|
return $fb_params;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* Validates the account that a user was trying to set up an
|
||||||
|
* independent account through Facebook Connect.
|
||||||
|
*
|
||||||
|
* @param user The user attempting to set up an independent account.
|
||||||
|
* @param hash The hash passed to the reclamation URL used.
|
||||||
|
* @return bool True if the user is the one that selected the
|
||||||
|
* reclamation link.
|
||||||
|
*/
|
||||||
|
public function verify_account_reclamation($user, $hash) {
|
||||||
|
return $hash == md5($user . $this->secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* Validates that a given set of parameters match their signature.
|
* Validates that a given set of parameters match their signature.
|
||||||
* Parameters all match a given input prefix, such as "fb_sig".
|
* Parameters all match a given input prefix, such as "fb_sig".
|
||||||
*
|
*
|
||||||
@ -422,6 +490,37 @@ class Facebook {
|
|||||||
return self::generate_sig($fb_params, $this->secret) == $expected_sig;
|
return self::generate_sig($fb_params, $this->secret) == $expected_sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the given signed public session data structure with
|
||||||
|
* public key of the app that
|
||||||
|
* the session proof belongs to.
|
||||||
|
*
|
||||||
|
* @param $signed_data the session info that is passed by another app
|
||||||
|
* @param string $public_key Optional public key of the app. If this
|
||||||
|
* is not passed, function will make an API call to get it.
|
||||||
|
* return true if the session proof passed verification.
|
||||||
|
*/
|
||||||
|
public function verify_signed_public_session_data($signed_data,
|
||||||
|
$public_key = null) {
|
||||||
|
|
||||||
|
// If public key is not already provided, we need to get it through API
|
||||||
|
if (!$public_key) {
|
||||||
|
$public_key = $this->api_client->auth_getAppPublicKey(
|
||||||
|
$signed_data['api_key']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create data to verify
|
||||||
|
$data_to_serialize = $signed_data;
|
||||||
|
unset($data_to_serialize['sig']);
|
||||||
|
$serialized_data = implode('_', $data_to_serialize);
|
||||||
|
|
||||||
|
// Decode signature
|
||||||
|
$signature = base64_decode($signed_data['sig']);
|
||||||
|
$result = openssl_verify($serialized_data, $signature, $public_key,
|
||||||
|
OPENSSL_ALGO_SHA1);
|
||||||
|
return $result == 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate a signature using the application secret key.
|
* Generate a signature using the application secret key.
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
// Copyright 2004-2008 Facebook. All Rights Reserved.
|
// Copyright 2004-2009 Facebook. All Rights Reserved.
|
||||||
//
|
//
|
||||||
// +---------------------------------------------------------------------------+
|
// +---------------------------------------------------------------------------+
|
||||||
// | Facebook Platform PHP5 client |
|
// | Facebook Platform PHP5 client |
|
||||||
|
1012
extlib/facebook/facebookapi_php5_restlib.php
Normal file → Executable file
1012
extlib/facebook/facebookapi_php5_restlib.php
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@ -63,6 +63,10 @@ function handleError($error)
|
|||||||
|
|
||||||
function main()
|
function main()
|
||||||
{
|
{
|
||||||
|
// quick check for fancy URL auto-detection support in installer.
|
||||||
|
if (isset($_SERVER['REDIRECT_URL']) && ('/check-fancy' === $_SERVER['REDIRECT_URL'])) {
|
||||||
|
die("Fancy URL support detection succeeded. We suggest you enable this to get fancy (pretty) URLs.");
|
||||||
|
}
|
||||||
global $user, $action, $config;
|
global $user, $action, $config;
|
||||||
|
|
||||||
Snapshot::check();
|
Snapshot::check();
|
||||||
@ -103,6 +107,8 @@ function main()
|
|||||||
|
|
||||||
$args = array_merge($args, $_REQUEST);
|
$args = array_merge($args, $_REQUEST);
|
||||||
|
|
||||||
|
Event::handle('ArgsInitialize', array(&$args));
|
||||||
|
|
||||||
$action = $args['action'];
|
$action = $args['action'];
|
||||||
|
|
||||||
if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) {
|
if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) {
|
||||||
|
171
install.php
171
install.php
@ -35,15 +35,17 @@ function main()
|
|||||||
|
|
||||||
function checkPrereqs()
|
function checkPrereqs()
|
||||||
{
|
{
|
||||||
|
$pass = true;
|
||||||
|
|
||||||
if (file_exists(INSTALLDIR.'/config.php')) {
|
if (file_exists(INSTALLDIR.'/config.php')) {
|
||||||
?><p class="error">Config file "config.php" already exists.</p>
|
?><p class="error">Config file "config.php" already exists.</p>
|
||||||
<?php
|
<?php
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
|
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
|
||||||
?><p class="error">Require PHP version 5 or greater.</p><?php
|
?><p class="error">Require PHP version 5 or greater.</p><?php
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$reqs = array('gd', 'mysql', 'curl',
|
$reqs = array('gd', 'mysql', 'curl',
|
||||||
@ -52,28 +54,26 @@ function checkPrereqs()
|
|||||||
|
|
||||||
foreach ($reqs as $req) {
|
foreach ($reqs as $req) {
|
||||||
if (!checkExtension($req)) {
|
if (!checkExtension($req)) {
|
||||||
?><p class="error">Cannot load required extension "<?php echo $req; ?>".</p><?php
|
?><p class="error">Cannot load required extension: <code><?php echo $req; ?></code></p><?php
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_writable(INSTALLDIR)) {
|
if (!is_writable(INSTALLDIR)) {
|
||||||
?><p class="error">Cannot write config file to "<?php echo INSTALLDIR; ?>".</p>
|
?><p class="error">Cannot write config file to: <code><?php echo INSTALLDIR; ?></code></p>
|
||||||
<p>On your server, try this command:</p>
|
<p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?></code>
|
||||||
<blockquote>chmod a+w <?php echo INSTALLDIR; ?></blockquote>
|
|
||||||
<?php
|
<?php
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_writable(INSTALLDIR.'/avatar/')) {
|
if (!is_writable(INSTALLDIR.'/avatar/')) {
|
||||||
?><p class="error">Cannot write avatar directory "<?php echo INSTALLDIR; ?>/avatar/".</p>
|
?><p class="error">Cannot write avatar directory: <code><?php echo INSTALLDIR; ?>/avatar/</code></p>
|
||||||
<p>On your server, try this command:</p>
|
<p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?>/avatar/</code></p>
|
||||||
<blockquote>chmod a+w <?php echo INSTALLDIR; ?>/avatar/</blockquote>
|
|
||||||
<?
|
<?
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return $pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkExtension($name)
|
function checkExtension($name)
|
||||||
@ -88,92 +88,121 @@ function checkExtension($name)
|
|||||||
|
|
||||||
function showForm()
|
function showForm()
|
||||||
{
|
{
|
||||||
?>
|
$config_path = htmlentities(trim(dirname($_SERVER['REQUEST_URI']), '/'));
|
||||||
|
echo<<<E_O_T
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<dl id="page_notice" class="system_notice">
|
||||||
|
<dt>Page notice</dt>
|
||||||
|
<dd>
|
||||||
|
<div class="instructions">
|
||||||
<p>Enter your database connection information below to initialize the database.</p>
|
<p>Enter your database connection information below to initialize the database.</p>
|
||||||
<form method='post' action='install.php'>
|
</div>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
<form method="post" action="install.php" class="form_settings" id="form_install">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<ul class='form_data'>
|
<legend>Connection settings</legend>
|
||||||
|
<ul class="form_data">
|
||||||
<li>
|
<li>
|
||||||
<label for='sitename'>Site name</label>
|
<label for="sitename">Site name</label>
|
||||||
<input type='text' id='sitename' name='sitename' />
|
<input type="text" id="sitename" name="sitename" />
|
||||||
<p>The name of your site</p>
|
<p class="form_guide">The name of your site</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<li>
|
<label for="fancy-enable">Fancy URLs</label>
|
||||||
<label for='host'>Hostname</label>
|
<input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
|
||||||
<input type='text' id='host' name='host' />
|
<input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
|
||||||
<p>Database hostname</p>
|
<p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for='host'>Database</label>
|
<label for="host">Hostname</label>
|
||||||
<input type='text' id='database' name='database' />
|
<input type="text" id="host" name="host" />
|
||||||
<p>Database name</p>
|
<p class="form_guide">Database hostname</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for='username'>Username</label>
|
<label for="host">Site path</label>
|
||||||
<input type='text' id='username' name='username' />
|
<input type="text" id="path" name="path" value="$config_path" />
|
||||||
<p>Database username</p>
|
<p class="form_guide">Site path, following the "/" after the domain name in the URL. Empty is fine. Field should be filled automatically.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for='password'>Password</label>
|
<label for="host">Database</label>
|
||||||
<input type='password' id='password' name='password' />
|
<input type="text" id="database" name="database" />
|
||||||
<p>Database password</p>
|
<p class="form_guide">Database name</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label for="username">Username</label>
|
||||||
|
<input type="text" id="username" name="username" />
|
||||||
|
<p class="form_guide">Database username</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
<input type="password" id="password" name="password" />
|
||||||
|
<p class="form_guide">Database password</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<input type='submit' name='submit' value='Submit'>
|
<input type="submit" name="submit" class="submit" value="Submit" />
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
<?
|
|
||||||
|
E_O_T;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateStatus($status, $error=false)
|
function updateStatus($status, $error=false)
|
||||||
{
|
{
|
||||||
?>
|
?>
|
||||||
<li>
|
<li <?php echo ($error) ? 'class="error"': ''; ?>><?print $status;?></li>
|
||||||
<?
|
|
||||||
print $status;
|
<?php
|
||||||
?>
|
|
||||||
</li>
|
|
||||||
<?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePost()
|
function handlePost()
|
||||||
{
|
{
|
||||||
?>
|
?>
|
||||||
<ul>
|
|
||||||
<?
|
<?php
|
||||||
$host = $_POST['host'];
|
$host = $_POST['host'];
|
||||||
$database = $_POST['database'];
|
$database = $_POST['database'];
|
||||||
$username = $_POST['username'];
|
$username = $_POST['username'];
|
||||||
$password = $_POST['password'];
|
$password = $_POST['password'];
|
||||||
$sitename = $_POST['sitename'];
|
$sitename = $_POST['sitename'];
|
||||||
|
$path = $_POST['path'];
|
||||||
|
$fancy = !empty($_POST['fancy']);
|
||||||
|
?>
|
||||||
|
<dl class="system_notice">
|
||||||
|
<dt>Page notice</dt>
|
||||||
|
<dd>
|
||||||
|
<ul>
|
||||||
|
<?php
|
||||||
|
$fail = false;
|
||||||
|
|
||||||
if (empty($host)) {
|
if (empty($host)) {
|
||||||
updateStatus("No hostname specified.", true);
|
updateStatus("No hostname specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($database)) {
|
if (empty($database)) {
|
||||||
updateStatus("No database specified.", true);
|
updateStatus("No database specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($username)) {
|
if (empty($username)) {
|
||||||
updateStatus("No username specified.", true);
|
updateStatus("No username specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($password)) {
|
if (empty($password)) {
|
||||||
updateStatus("No password specified.", true);
|
updateStatus("No password specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($sitename)) {
|
if (empty($sitename)) {
|
||||||
updateStatus("No sitename specified.", true);
|
updateStatus("No sitename specified.", true);
|
||||||
|
$fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($fail){
|
||||||
showForm();
|
showForm();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -214,24 +243,30 @@ function handlePost()
|
|||||||
}
|
}
|
||||||
updateStatus("Writing config file...");
|
updateStatus("Writing config file...");
|
||||||
$sqlUrl = "mysqli://$username:$password@$host/$database";
|
$sqlUrl = "mysqli://$username:$password@$host/$database";
|
||||||
$res = writeConf($sitename, $sqlUrl);
|
$res = writeConf($sitename, $sqlUrl, $fancy, $path);
|
||||||
if (!$res) {
|
if (!$res) {
|
||||||
updateStatus("Can't write config file.", true);
|
updateStatus("Can't write config file.", true);
|
||||||
showForm();
|
showForm();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateStatus("Done!");
|
updateStatus("Done!");
|
||||||
|
if ($path) $path .= '/';
|
||||||
|
updateStatus("You can visit your <a href='/$path'>new Laconica site</a>.");
|
||||||
?>
|
?>
|
||||||
</ul>
|
|
||||||
<?
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeConf($sitename, $sqlUrl)
|
function writeConf($sitename, $sqlUrl, $fancy, $path)
|
||||||
{
|
{
|
||||||
$res = file_put_contents(INSTALLDIR.'/config.php',
|
$res = file_put_contents(INSTALLDIR.'/config.php',
|
||||||
"<?php\n".
|
"<?php\n".
|
||||||
|
"if (!defined('LACONICA')) { exit(1); }\n\n".
|
||||||
"\$config['site']['name'] = \"$sitename\";\n\n".
|
"\$config['site']['name'] = \"$sitename\";\n\n".
|
||||||
"\$config['db']['database'] = \"$sqlUrl\";\n\n");
|
($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
|
||||||
|
"\$config['site']['path'] = \"$path\";\n\n".
|
||||||
|
"\$config['db']['database'] = \"$sqlUrl\";\n\n".
|
||||||
|
"?>");
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,15 +288,31 @@ function runDbScript($filename, $conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<html>
|
<?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
|
||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
|
||||||
<head>
|
<head>
|
||||||
<title>Install Laconica</title>
|
<title>Install Laconica</title>
|
||||||
<link rel="stylesheet" type="text/css" href="theme/base/css/display.css?version=0.7.1" media="screen, projection, tv"/>
|
<link rel="stylesheet" type="text/css" href="theme/base/css/display.css?version=0.8" media="screen, projection, tv"/>
|
||||||
<link rel="stylesheet" type="text/css" href="theme/base/css/modal.css?version=0.7.1" media="screen, projection, tv"/>
|
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
|
||||||
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.7.1" media="screen, projection, tv"/>
|
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
|
||||||
|
<!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
|
||||||
|
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/earthy/css/ie.css?version=0.8" /><![endif]-->
|
||||||
|
<script src='js/jquery.min.js'></script>
|
||||||
|
<script src='js/install.js'></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body id="install">
|
||||||
<div id="wrap">
|
<div id="wrap">
|
||||||
|
<div id="header">
|
||||||
|
<address id="site_contact" class="vcard">
|
||||||
|
<a class="url home bookmark" href=".">
|
||||||
|
<img class="logo photo" src="theme/default/logo.png" alt="Laconica"/>
|
||||||
|
<span class="fn org">Laconica</span>
|
||||||
|
</a>
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
<div id="core">
|
<div id="core">
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<h1>Install Laconica</h1>
|
<h1>Install Laconica</h1>
|
||||||
|
@ -1,10 +1,85 @@
|
|||||||
|
/** Init for Farbtastic library and page setup
|
||||||
|
*
|
||||||
|
* @package Laconica
|
||||||
|
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var f = $.farbtastic('#color-picker');
|
function UpdateColors(S) {
|
||||||
var colors = $('#settings_design_color input');
|
C = $(S).val();
|
||||||
|
switch (parseInt(S.id.slice(-1))) {
|
||||||
|
case 0: default:
|
||||||
|
$('body').css({'background-color':C});
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
$('#content').css({'background-color':C});
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$('#aside_primary').css({'background-color':C});
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$('body').css({'color':C});
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
$('a').css({'color':C});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
colors
|
function UpdateFarbtastic(e) {
|
||||||
.each(function () { f.linkTo(this); })
|
f.linked = e;
|
||||||
|
f.setColor(e.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateSwatch(e) {
|
||||||
|
$(e).css({"background-color": e.value,
|
||||||
|
"color": f.hsl[2] > 0.5 ? "#000": "#fff"});
|
||||||
|
}
|
||||||
|
|
||||||
|
function SynchColors(e) {
|
||||||
|
var S = f.linked;
|
||||||
|
var C = f.color;
|
||||||
|
|
||||||
|
if (S && S.value && S.value != C) {
|
||||||
|
S.value = C;
|
||||||
|
UpdateSwatch(S);
|
||||||
|
UpdateColors(S);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Init() {
|
||||||
|
$('#settings_design_color').append('<div id="color-picker"></div>');
|
||||||
|
$('#color-picker').hide();
|
||||||
|
|
||||||
|
f = $.farbtastic('#color-picker', SynchColors);
|
||||||
|
swatches = $('#settings_design_color .swatch');
|
||||||
|
|
||||||
|
swatches
|
||||||
|
.each(SynchColors)
|
||||||
|
.blur(function() {
|
||||||
|
$(this).val($(this).val().toUpperCase());
|
||||||
|
})
|
||||||
.focus(function() {
|
.focus(function() {
|
||||||
f.linkTo(this);
|
$('#color-picker').show();
|
||||||
|
UpdateFarbtastic(this);
|
||||||
|
})
|
||||||
|
.change(function() {
|
||||||
|
UpdateFarbtastic(this);
|
||||||
|
UpdateSwatch(this);
|
||||||
|
UpdateColors(this);
|
||||||
|
}).change();
|
||||||
|
}
|
||||||
|
|
||||||
|
var f, swatches;
|
||||||
|
Init();
|
||||||
|
$('#form_settings_design').bind('reset', function(){
|
||||||
|
setTimeout(function(){
|
||||||
|
swatches.each(function(){UpdateColors(this);});
|
||||||
|
$('#color-picker').remove();
|
||||||
|
swatches.unbind();
|
||||||
|
Init();
|
||||||
|
},10);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -128,7 +128,7 @@
|
|||||||
var a = document.createElement('A');
|
var a = document.createElement('A');
|
||||||
a.innerHTML = 'get this';
|
a.innerHTML = 'get this';
|
||||||
a.target = '_blank';
|
a.target = '_blank';
|
||||||
a.href = 'http://identica/doc/badge';
|
a.href = 'http://identi.ca/doc/badge';
|
||||||
$.s.f.appendChild(a);
|
$.s.f.appendChild(a);
|
||||||
$.s.appendChild($.s.f);
|
$.s.appendChild($.s.f);
|
||||||
$.f.getUser();
|
$.f.getUser();
|
||||||
|
18
js/install.js
Normal file
18
js/install.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
$(document).ready(function(){
|
||||||
|
$.ajax({url:'check-fancy',
|
||||||
|
type:'GET',
|
||||||
|
success:function(data, textStatus) {
|
||||||
|
$('#fancy-enable').attr('checked', true);
|
||||||
|
$('#fancy-disable').attr('checked', false);
|
||||||
|
$('#fancy-form_guide').text(data);
|
||||||
|
},
|
||||||
|
error:function(XMLHttpRequest, textStatus, errorThrown) {
|
||||||
|
$('#fancy-enable').attr('checked', false);
|
||||||
|
$('#fancy-disable').attr('checked', true);
|
||||||
|
$('#fancy-enable').attr('disabled', true);
|
||||||
|
$('#fancy-disable').attr('disabled', true);
|
||||||
|
$('#fancy-form_guide').text("Fancy URL support detection failed, disabling this option. Make sure you renamed htaccess.sample to .htaccess.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,3 +1,12 @@
|
|||||||
|
/** Init for Jcrop library and page setup
|
||||||
|
*
|
||||||
|
* @package Laconica
|
||||||
|
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
$(function(){
|
$(function(){
|
||||||
var x = ($('#avatar_crop_x').val()) ? $('#avatar_crop_x').val() : 0;
|
var x = ($('#avatar_crop_x').val()) ? $('#avatar_crop_x').val() : 0;
|
||||||
var y = ($('#avatar_crop_y').val()) ? $('#avatar_crop_y').val() : 0;
|
var y = ($('#avatar_crop_y').val()) ? $('#avatar_crop_y').val() : 0;
|
||||||
|
6
js/jquery.joverlay.min.js
vendored
Normal file
6
js/jquery.joverlay.min.js
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/* Copyright (c) 2009 Alvaro A. Lima Jr http://alvarojunior.com/jquery/joverlay.html
|
||||||
|
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
* Version: 0.6 (Abr 23, 2009)
|
||||||
|
* Requires: jQuery 1.3+
|
||||||
|
*/
|
||||||
|
(function($){var f=$.browser.msie&&$.browser.version==6.0;var g=null;$.fn.jOverlay=function(b){var b=$.extend({},$.fn.jOverlay.options,b);if(g!=null){clearTimeout(g)}var c=this.is('*')?this:'#jOverlayContent';var d=f?'absolute':'fixed';var e=b.imgLoading?"<img id='jOverlayLoading' src='"+b.imgLoading+"' style='position:"+d+"; z-index:"+(b.zIndex+9)+";'/>":'';$('body').prepend(e+"<div id='jOverlay' />"+"<div id='jOverlayContent' style='position:"+d+"; z-index:"+(b.zIndex+5)+"; display:none;'/>");$('#jOverlayLoading').load(function(){if(b.center){$.center(this)}});if(f){$("select").hide();$("#jOverlayContent select").show()}$('#jOverlay').css({backgroundColor:b.color,position:d,top:'0px',left:'0px',filter:'alpha(opacity='+(b.opacity*100)+')',opacity:b.opacity,zIndex:b.zIndex,width:!f?'100%':$(window).width()+'px',height:!f?'100%':$(document).height()+'px'}).show();if(this.is('*')){$('#jOverlayContent').html(this.addClass('jOverlayChildren').show()).show();if(b.center){$.center('#jOverlayContent')}if(!b.url&&$.isFunction(b.success)){b.success(this.html())}}if(b.url){$.ajax({type:b.method,data:b.data,url:b.url,success:function(a){$('#jOverlayLoading').fadeOut(600);$(c).html(a).show();if(b.center){$.center('#jOverlayContent')}if($.isFunction(b.success)){b.success(a)}}})}if(f){$(window).scroll(function(){if(b.center){$.center('#jOverlayContent')}});$(window).resize(function(){$('#jOverlay').css({width:$(window).width()+'px',height:$(document).height()+'px'});if(b.center){$.center('#jOverlayContent')}})}$(document).keydown(function(a){if(a.keyCode==27){$.closeOverlay()}});if(b.bgClickToClose){$('#jOverlay').click($.closeOverlay)}if(Number(b.timeout)>0){g=setTimeout($.closeOverlay,Number(b.timeout))}};$.center=function(a){var a=$(a);var b=a.height();var c=a.width();a.css({width:c+'px',marginLeft:'-'+(c/2)+'px',marginTop:'-'+b/2+'px',height:'auto',top:!f?'50%':$(window).scrollTop()+($(window).height()/2)+"px",left:'50%'})};$.fn.jOverlay.options={method:'GET',data:'',url:'',color:'#000',opacity:'0.6',zIndex:9999,center:true,imgLoading:'',bgClickToClose:true,success:null,timeout:0};$.closeOverlay=function(){if(f){$("select").show()}$('#jOverlayContent .jOverlayChildren').hide().prependTo($('body'));$('#jOverlayLoading, #jOverlayContent, #jOverlay').remove()}})(jQuery);
|
39
js/util.js
39
js/util.js
@ -17,6 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
$('.attachments').click(function() {$().jOverlay({zIndex:999, success:function(html) {$('.attachment').click(function() {$().jOverlay({url:$(this).attr('href') + '/ajax'}); return false; });
|
||||||
|
}, url:$(this).attr('href') + '/ajax'}); return false; });
|
||||||
|
$('.attachment').click(function() {$().jOverlay({url:$(this).attr('href') + '/ajax'}); return false; });
|
||||||
|
|
||||||
// count character on keyup
|
// count character on keyup
|
||||||
function counter(event){
|
function counter(event){
|
||||||
var maxLength = 140;
|
var maxLength = 140;
|
||||||
@ -166,19 +170,45 @@ $(document).ready(function(){
|
|||||||
$("#notice_action-submit").addClass("disabled");
|
$("#notice_action-submit").addClass("disabled");
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
success: function(xml) { if ($("#error", xml).length > 0 || $("#command_result", xml).length > 0) {
|
timeout: '60000',
|
||||||
|
error: function (xhr, textStatus, errorThrown) { $("#form_notice").removeClass("processing");
|
||||||
|
$("#notice_action-submit").removeAttr("disabled");
|
||||||
|
$("#notice_action-submit").removeClass("disabled");
|
||||||
|
if (textStatus == "timeout") {
|
||||||
|
alert ("Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ($(".error", xhr.responseXML).length > 0) {
|
||||||
|
$('#form_notice').append(document._importNode($(".error", xhr.responseXML).get(0), true));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert("Sorry! We had trouble sending your notice ("+xhr.status+" "+xhr.statusText+"). Please report the problem to the site administrator if this happens again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
success: function(xml) { if ($("#error", xml).length > 0) {
|
||||||
var result = document._importNode($("p", xml).get(0), true);
|
var result = document._importNode($("p", xml).get(0), true);
|
||||||
result = result.textContent || result.innerHTML;
|
result = result.textContent || result.innerHTML;
|
||||||
alert(result);
|
alert(result);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$("#notices_primary .notices").prepend(document._importNode($("li", xml).get(0), true));
|
if ($("#command_result", xml).length > 0) {
|
||||||
$("#notice_data-text").val("");
|
var result = document._importNode($("p", xml).get(0), true);
|
||||||
counter();
|
result = result.textContent || result.innerHTML;
|
||||||
|
alert(result);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
li = $("li", xml).get(0);
|
||||||
|
if ($("#"+li.id).length == 0) {
|
||||||
|
$("#notices_primary .notices").prepend(document._importNode(li, true));
|
||||||
$("#notices_primary .notice:first").css({display:"none"});
|
$("#notices_primary .notice:first").css({display:"none"});
|
||||||
$("#notices_primary .notice:first").fadeIn(2500);
|
$("#notices_primary .notice:first").fadeIn(2500);
|
||||||
NoticeHover();
|
NoticeHover();
|
||||||
NoticeReply();
|
NoticeReply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$("#notice_data-text").val("");
|
||||||
|
counter();
|
||||||
}
|
}
|
||||||
$("#form_notice").removeClass("processing");
|
$("#form_notice").removeClass("processing");
|
||||||
$("#notice_action-submit").removeAttr("disabled");
|
$("#notice_action-submit").removeAttr("disabled");
|
||||||
@ -187,7 +217,6 @@ $(document).ready(function(){
|
|||||||
};
|
};
|
||||||
$("#form_notice").ajaxForm(PostNotice);
|
$("#form_notice").ajaxForm(PostNotice);
|
||||||
$("#form_notice").each(addAjaxHidden);
|
$("#form_notice").each(addAjaxHidden);
|
||||||
|
|
||||||
NoticeHover();
|
NoticeHover();
|
||||||
NoticeReply();
|
NoticeReply();
|
||||||
});
|
});
|
||||||
|
@ -22,6 +22,7 @@ if (!defined('LACONICA')) { exit(1); }
|
|||||||
class ShortUrlApi
|
class ShortUrlApi
|
||||||
{
|
{
|
||||||
protected $service_url;
|
protected $service_url;
|
||||||
|
protected $long_limit = 27;
|
||||||
|
|
||||||
function __construct($service_url)
|
function __construct($service_url)
|
||||||
{
|
{
|
||||||
@ -39,7 +40,7 @@ class ShortUrlApi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function is_long($url) {
|
private function is_long($url) {
|
||||||
return strlen($url) >= 30;
|
return strlen($url) >= $this->long_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function http_post($data) {
|
protected function http_post($data) {
|
||||||
|
@ -243,6 +243,12 @@ class Action extends HTMLOutputter // lawsuit
|
|||||||
$this->element('script', array('type' => 'text/javascript',
|
$this->element('script', array('type' => 'text/javascript',
|
||||||
'src' => common_path('js/jquery.form.js')),
|
'src' => common_path('js/jquery.form.js')),
|
||||||
' ');
|
' ');
|
||||||
|
|
||||||
|
$this->element('script', array('type' => 'text/javascript',
|
||||||
|
'src' => common_path('js/jquery.joverlay.min.js')),
|
||||||
|
' ');
|
||||||
|
|
||||||
|
|
||||||
Event::handle('EndShowJQueryScripts', array($this));
|
Event::handle('EndShowJQueryScripts', array($this));
|
||||||
}
|
}
|
||||||
if (Event::handle('StartShowLaconicaScripts', array($this))) {
|
if (Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||||
@ -591,7 +597,10 @@ class Action extends HTMLOutputter // lawsuit
|
|||||||
'class' => 'system_notice'));
|
'class' => 'system_notice'));
|
||||||
$this->element('dt', null, _('Page notice'));
|
$this->element('dt', null, _('Page notice'));
|
||||||
$this->elementStart('dd');
|
$this->elementStart('dd');
|
||||||
|
if (Event::handle('StartShowPageNotice', array($this))) {
|
||||||
$this->showPageNotice();
|
$this->showPageNotice();
|
||||||
|
Event::handle('EndShowPageNotice', array($this));
|
||||||
|
}
|
||||||
$this->elementEnd('dd');
|
$this->elementEnd('dd');
|
||||||
$this->elementEnd('dl');
|
$this->elementEnd('dl');
|
||||||
}
|
}
|
||||||
|
300
lib/attachmentlist.php
Normal file
300
lib/attachmentlist.php
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* widget for displaying a list of notice attachments
|
||||||
|
*
|
||||||
|
* 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 UI
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||||
|
* @copyright 2008 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* widget for displaying a list of notice attachments
|
||||||
|
*
|
||||||
|
* There are a number of actions that display a list of notices, in
|
||||||
|
* reverse chronological order. This widget abstracts out most of the
|
||||||
|
* code for UI for notice lists. It's overridden to hide some
|
||||||
|
* data for e.g. the profile page.
|
||||||
|
*
|
||||||
|
* @category UI
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
* @see Notice
|
||||||
|
* @see StreamAction
|
||||||
|
* @see NoticeListItem
|
||||||
|
* @see ProfileNoticeList
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AttachmentList extends Widget
|
||||||
|
{
|
||||||
|
/** the current stream of notices being displayed. */
|
||||||
|
|
||||||
|
var $notice = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param Notice $notice stream of notices from DB_DataObject
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __construct($notice, $out=null)
|
||||||
|
{
|
||||||
|
parent::__construct($out);
|
||||||
|
$this->notice = $notice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show the list of notices
|
||||||
|
*
|
||||||
|
* "Uses up" the stream by looping through it. So, probably can't
|
||||||
|
* be called twice on the same list.
|
||||||
|
*
|
||||||
|
* @return int count of notices listed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
// $this->out->elementStart('div', array('id' =>'attachments_primary'));
|
||||||
|
$this->out->elementStart('div', array('id' =>'content'));
|
||||||
|
$this->out->element('h2', null, _('Attachments'));
|
||||||
|
$this->out->elementStart('ul', array('class' => 'attachments'));
|
||||||
|
|
||||||
|
$atts = new File;
|
||||||
|
$att = $atts->getAttachments($this->notice->id);
|
||||||
|
foreach ($att as $n=>$attachment) {
|
||||||
|
$item = $this->newListItem($attachment);
|
||||||
|
$item->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
|
return count($att);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a new list item for the current notice
|
||||||
|
*
|
||||||
|
* Recipe (factory?) method; overridden by sub-classes to give
|
||||||
|
* a different list item class.
|
||||||
|
*
|
||||||
|
* @param Notice $notice the current notice
|
||||||
|
*
|
||||||
|
* @return NoticeListItem a list item for displaying the notice
|
||||||
|
*/
|
||||||
|
|
||||||
|
function newListItem($attachment)
|
||||||
|
{
|
||||||
|
return new AttachmentListItem($attachment, $this->out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* widget for displaying a single notice
|
||||||
|
*
|
||||||
|
* This widget has the core smarts for showing a single notice: what to display,
|
||||||
|
* where, and under which circumstances. Its key method is show(); this is a recipe
|
||||||
|
* that calls all the other show*() methods to build up a single notice. The
|
||||||
|
* ProfileNoticeListItem subclass, for example, overrides showAuthor() to skip
|
||||||
|
* author info (since that's implicit by the data in the page).
|
||||||
|
*
|
||||||
|
* @category UI
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
* @see NoticeList
|
||||||
|
* @see ProfileNoticeListItem
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AttachmentListItem extends Widget
|
||||||
|
{
|
||||||
|
/** The attachment this item will show. */
|
||||||
|
|
||||||
|
var $attachment = null;
|
||||||
|
|
||||||
|
var $oembed = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* Also initializes the profile attribute.
|
||||||
|
*
|
||||||
|
* @param Notice $notice The notice we'll display
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __construct($attachment, $out=null)
|
||||||
|
{
|
||||||
|
parent::__construct($out);
|
||||||
|
$this->attachment = $attachment;
|
||||||
|
$this->oembed = File_oembed::staticGet('file_id', $this->attachment->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function title() {
|
||||||
|
if (empty($this->attachment->title)) {
|
||||||
|
if (empty($this->oembed->title)) {
|
||||||
|
$title = $this->attachment->url;
|
||||||
|
} else {
|
||||||
|
$title = $this->oembed->title;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$title = $this->attachment->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
function linkTitle() {
|
||||||
|
return 'Our page for ' . $this->title();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* recipe function for displaying a single notice.
|
||||||
|
*
|
||||||
|
* This uses all the other methods to correctly display a notice. Override
|
||||||
|
* it or one of the others to fine-tune the output.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$this->showStart();
|
||||||
|
$this->showNoticeAttachment();
|
||||||
|
$this->showEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
function linkAttr() {
|
||||||
|
return array('class' => 'attachment', 'href' => common_local_url('attachment', array('attachment' => $this->attachment->id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLink() {
|
||||||
|
$attr = $this->linkAttr();
|
||||||
|
$text = $this->linkTitle();
|
||||||
|
$this->out->elementStart('h4');
|
||||||
|
$this->out->element('a', $attr, $text);
|
||||||
|
|
||||||
|
if ($this->attachment->url !== $this->title())
|
||||||
|
$this->out->element('span', null, " ({$this->attachment->url})");
|
||||||
|
|
||||||
|
|
||||||
|
$this->out->elementEnd('h4');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNoticeAttachment()
|
||||||
|
{
|
||||||
|
$this->showLink();
|
||||||
|
$this->showRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showRepresentation() {
|
||||||
|
$thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
|
||||||
|
if (!empty($thumbnail)) {
|
||||||
|
$this->out->elementStart('a', $this->linkAttr()/*'href' => $this->linkTo()*/);
|
||||||
|
$this->out->element('img', array('alt' => 'nothing to say', 'src' => $thumbnail->url, 'width' => $thumbnail->width, 'height' => $thumbnail->height));
|
||||||
|
$this->out->elementEnd('a');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start a single notice.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showStart()
|
||||||
|
{
|
||||||
|
// XXX: RDFa
|
||||||
|
// TODO: add notice_type class e.g., notice_video, notice_image
|
||||||
|
$this->out->elementStart('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finish the notice
|
||||||
|
*
|
||||||
|
* Close the last elements in the notice list item
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showEnd()
|
||||||
|
{
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Attachment extends AttachmentListItem
|
||||||
|
{
|
||||||
|
function show() {
|
||||||
|
$this->showNoticeAttachment();
|
||||||
|
}
|
||||||
|
|
||||||
|
function linkAttr() {
|
||||||
|
return array('class' => 'external', 'href' => $this->attachment->url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function linkTitle() {
|
||||||
|
return 'Direct link to ' . $this->title();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showRepresentation() {
|
||||||
|
if (empty($this->oembed->type)) {
|
||||||
|
if (empty($this->attachment->mimetype)) {
|
||||||
|
$this->out->element('pre', null, 'oh well... not sure how to handle the following: ' . print_r($this->attachment, true));
|
||||||
|
} else {
|
||||||
|
switch ($this->attachment->mimetype) {
|
||||||
|
case 'image/gif':
|
||||||
|
case 'image/png':
|
||||||
|
case 'image/jpg':
|
||||||
|
case 'image/jpeg':
|
||||||
|
$this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch ($this->oembed->type) {
|
||||||
|
case 'rich':
|
||||||
|
case 'video':
|
||||||
|
case 'link':
|
||||||
|
if (!empty($this->oembed->html)) {
|
||||||
|
$this->out->raw($this->oembed->html);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'photo':
|
||||||
|
$this->out->element('img', array('src' => $this->oembed->url, 'width' => $this->oembed->width, 'height' => $this->oembed->height, 'alt' => 'alt'));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$this->out->element('pre', null, 'oh well... not sure how to handle the following oembed: ' . print_r($this->oembed, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
75
lib/attachmentnoticesection.php
Normal file
75
lib/attachmentnoticesection.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
* These are the widgets that show interesting data about a person * group, or site.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AttachmentNoticeSection extends NoticeSection
|
||||||
|
{
|
||||||
|
function showContent() {
|
||||||
|
parent::showContent();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNotices()
|
||||||
|
{
|
||||||
|
$notice = new Notice;
|
||||||
|
$f2p = new File_to_post;
|
||||||
|
$f2p->file_id = $this->out->attachment->id;
|
||||||
|
$notice->joinAdd($f2p);
|
||||||
|
$notice->orderBy('created desc');
|
||||||
|
$notice->selectAdd('post_id as id');
|
||||||
|
$notice->find();
|
||||||
|
return $notice;
|
||||||
|
}
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('Notices where this attachment appears');
|
||||||
|
}
|
||||||
|
|
||||||
|
function divId()
|
||||||
|
{
|
||||||
|
return 'popular_notices';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
80
lib/attachmentsection.php
Normal file
80
lib/attachmentsection.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Base class for sections showing lists of attachments
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
define('ATTACHMENTS_PER_SECTION', 6);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for sections showing lists of attachments
|
||||||
|
*
|
||||||
|
* These are the widgets that show interesting data about a person
|
||||||
|
* group, or site.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AttachmentSection extends Section
|
||||||
|
{
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$attachments = $this->getAttachments();
|
||||||
|
|
||||||
|
$cnt = 0;
|
||||||
|
|
||||||
|
$this->out->elementStart('ul', 'attachments');
|
||||||
|
|
||||||
|
while ($attachments->fetch() && ++$cnt <= ATTACHMENTS_PER_SECTION) {
|
||||||
|
$this->showAttachment($attachments);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
|
||||||
|
return ($cnt > ATTACHMENTS_PER_SECTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAttachments()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAttachment($attachment)
|
||||||
|
{
|
||||||
|
$this->out->elementStart('li');
|
||||||
|
$this->out->element('a', array('class' => 'attachment', 'href' => common_local_url('attachment', array('attachment' => $attachment->file_id))), "Attachment tagged {$attachment->c} times");
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
83
lib/attachmenttagcloudsection.php
Normal file
83
lib/attachmenttagcloudsection.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Attachment tag cloud section
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attachment tag cloud section
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AttachmentTagCloudSection extends TagCloudSection
|
||||||
|
{
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('Tags for this attachment');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showTag($tag, $weight, $relative)
|
||||||
|
{
|
||||||
|
if ($relative > 0.5) {
|
||||||
|
$rel = 'tag-cloud-7';
|
||||||
|
} else if ($relative > 0.4) {
|
||||||
|
$rel = 'tag-cloud-6';
|
||||||
|
} else if ($relative > 0.3) {
|
||||||
|
$rel = 'tag-cloud-5';
|
||||||
|
} else if ($relative > 0.2) {
|
||||||
|
$rel = 'tag-cloud-4';
|
||||||
|
} else if ($relative > 0.1) {
|
||||||
|
$rel = 'tag-cloud-3';
|
||||||
|
} else if ($relative > 0.05) {
|
||||||
|
$rel = 'tag-cloud-2';
|
||||||
|
} else {
|
||||||
|
$rel = 'tag-cloud-1';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementStart('li', $rel);
|
||||||
|
$this->out->element('a', array('href' => $this->tagUrl($tag)),
|
||||||
|
$tag);
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTags()
|
||||||
|
{
|
||||||
|
$notice_tag = new Notice_tag;
|
||||||
|
$query = 'select tag,count(tag) as weight from notice_tag join file_to_post on (notice_tag.notice_id=post_id) join notice on notice_id = notice.id where file_id=' . $notice_tag->escape($this->out->attachment->id) . ' group by tag order by weight desc';
|
||||||
|
$notice_tag->query($query);
|
||||||
|
return $notice_tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -143,6 +143,8 @@ $config =
|
|||||||
array('piddir' => '/var/run',
|
array('piddir' => '/var/run',
|
||||||
'user' => false,
|
'user' => false,
|
||||||
'group' => false),
|
'group' => false),
|
||||||
|
'twitterbridge' =>
|
||||||
|
array('enabled' => false),
|
||||||
'integration' =>
|
'integration' =>
|
||||||
array('source' => 'Laconica', # source attribute for Twitter
|
array('source' => 'Laconica', # source attribute for Twitter
|
||||||
'taguri' => $_server.',2009'), # base for tag URIs
|
'taguri' => $_server.',2009'), # base for tag URIs
|
||||||
@ -197,7 +199,7 @@ $_config_files[] = INSTALLDIR.'/config.php';
|
|||||||
$_have_a_config = false;
|
$_have_a_config = false;
|
||||||
|
|
||||||
foreach ($_config_files as $_config_file) {
|
foreach ($_config_files as $_config_file) {
|
||||||
if (file_exists($_config_file)) {
|
if (@file_exists($_config_file)) {
|
||||||
include_once($_config_file);
|
include_once($_config_file);
|
||||||
$_have_a_config = true;
|
$_have_a_config = true;
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,21 @@ define("FACEBOOK_PROMPTED_UPDATE_PREF", 2);
|
|||||||
|
|
||||||
function getFacebook()
|
function getFacebook()
|
||||||
{
|
{
|
||||||
|
static $facebook = null;
|
||||||
|
|
||||||
$apikey = common_config('facebook', 'apikey');
|
$apikey = common_config('facebook', 'apikey');
|
||||||
$secret = common_config('facebook', 'secret');
|
$secret = common_config('facebook', 'secret');
|
||||||
return new Facebook($apikey, $secret);
|
|
||||||
|
if ($facebook === null) {
|
||||||
|
$facebook = new Facebook($apikey, $secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$facebook) {
|
||||||
|
common_log(LOG_ERR, 'Could not make new Facebook client obj!',
|
||||||
|
__FILE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $facebook;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateProfileBox($facebook, $flink, $notice) {
|
function updateProfileBox($facebook, $flink, $notice) {
|
||||||
@ -92,7 +104,6 @@ function isFacebookBound($notice, $flink) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function facebookBroadcastNotice($notice)
|
function facebookBroadcastNotice($notice)
|
||||||
{
|
{
|
||||||
$facebook = getFacebook();
|
$facebook = getFacebook();
|
||||||
|
66
lib/frequentattachmentsection.php
Normal file
66
lib/frequentattachmentsection.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME
|
||||||
|
*
|
||||||
|
* These are the widgets that show interesting data about a person
|
||||||
|
* group, or site.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FrequentAttachmentSection extends AttachmentSection
|
||||||
|
{
|
||||||
|
function getAttachments() {
|
||||||
|
$notice_tag = new Notice_tag;
|
||||||
|
$query = 'select file_id, count(file_id) as c from notice_tag join file_to_post on post_id = notice_id where tag="' . $notice_tag->escape($this->out->tag) . '" group by file_id order by c desc';
|
||||||
|
$notice_tag->query($query);
|
||||||
|
return $notice_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return sprintf(_('Attachments frequently tagged with %s'), $this->out->tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
function divId()
|
||||||
|
{
|
||||||
|
return 'frequent_attachments';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -134,9 +134,11 @@ class GalleryAction extends Action
|
|||||||
$this->elementStart('li', array('id'=>'filter_tags_item'));
|
$this->elementStart('li', array('id'=>'filter_tags_item'));
|
||||||
$this->elementStart('form', array('name' => 'bytag',
|
$this->elementStart('form', array('name' => 'bytag',
|
||||||
'id' => 'bytag',
|
'id' => 'bytag',
|
||||||
|
'action' => common_path('?action=' . $this->trimmed('action')),
|
||||||
'method' => 'post'));
|
'method' => 'post'));
|
||||||
$this->dropdown('tag', _('Tag'), $content,
|
$this->dropdown('tag', _('Tag'), $content,
|
||||||
_('Choose a tag to narrow list'), false, $tag);
|
_('Choose a tag to narrow list'), false, $tag);
|
||||||
|
$this->hidden('nickname', $this->user->nickname);
|
||||||
$this->submit('submit', _('Go'));
|
$this->submit('submit', _('Go'));
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
|
@ -179,6 +179,7 @@ class NoticeListItem extends Widget
|
|||||||
{
|
{
|
||||||
$this->showStart();
|
$this->showStart();
|
||||||
$this->showNotice();
|
$this->showNotice();
|
||||||
|
$this->showNoticeAttachments();
|
||||||
$this->showNoticeInfo();
|
$this->showNoticeInfo();
|
||||||
$this->showNoticeOptions();
|
$this->showNoticeOptions();
|
||||||
$this->showEnd();
|
$this->showEnd();
|
||||||
@ -192,6 +193,48 @@ class NoticeListItem extends Widget
|
|||||||
$this->out->elementEnd('div');
|
$this->out->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showNoticeAttachments()
|
||||||
|
{
|
||||||
|
$f2p = new File_to_post;
|
||||||
|
$f2p->post_id = $this->notice->id;
|
||||||
|
$file = new File;
|
||||||
|
$file->joinAdd($f2p);
|
||||||
|
$file->selectAdd();
|
||||||
|
$file->selectAdd('file.id as id');
|
||||||
|
$count = $file->find(true);
|
||||||
|
if (!$count) return;
|
||||||
|
if (1 === $count) {
|
||||||
|
$href = common_local_url('attachment', array('attachment' => $file->id));
|
||||||
|
$att_class = 'attachment';
|
||||||
|
} else {
|
||||||
|
$href = common_local_url('attachments', array('notice' => $this->notice->id));
|
||||||
|
$att_class = 'attachments';
|
||||||
|
}
|
||||||
|
|
||||||
|
$clip = theme_path('images/icons/clip', 'base');
|
||||||
|
if ('shownotice' === $this->out->args['action']) {
|
||||||
|
$height = '96px';
|
||||||
|
$width = '83%';
|
||||||
|
$width_att = '15%';
|
||||||
|
$clip .= '-big.png';
|
||||||
|
$top = '70px';
|
||||||
|
} else {
|
||||||
|
$height = '48px';
|
||||||
|
$width = '90%';
|
||||||
|
$width_att = '8%';
|
||||||
|
$clip .= '.png';
|
||||||
|
$top = '20px';
|
||||||
|
}
|
||||||
|
if(0)
|
||||||
|
$this->out->elementStart('div', 'entry-attachments');
|
||||||
|
else
|
||||||
|
$this->out->elementStart('p', array('class' => 'entry-attachments', 'style' => "float: right; width: $width_att; background: url($clip) no-repeat; text-align: right; height: $height;"));
|
||||||
|
$this->out->element('a', array('class' => $att_class, 'style' => "text-decoration: none; padding-top: $top; display: block; height: $height;", 'href' => $href, 'title' => "# of attachments: $count"), $count === 1 ? '' : $count);
|
||||||
|
|
||||||
|
|
||||||
|
$this->out->elementEnd('p');
|
||||||
|
}
|
||||||
|
|
||||||
function showNoticeInfo()
|
function showNoticeInfo()
|
||||||
{
|
{
|
||||||
$this->out->elementStart('div', 'entry-content');
|
$this->out->elementStart('div', 'entry-content');
|
||||||
|
@ -51,17 +51,13 @@ class NoticeSection extends Section
|
|||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$notices = $this->getNotices();
|
$notices = $this->getNotices();
|
||||||
|
|
||||||
$cnt = 0;
|
$cnt = 0;
|
||||||
|
|
||||||
$this->out->elementStart('ul', 'notices');
|
$this->out->elementStart('ul', 'notices');
|
||||||
|
|
||||||
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
||||||
$this->showNotice($notices);
|
$this->showNotice($notices);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
|
|
||||||
return ($cnt > NOTICES_PER_SECTION);
|
return ($cnt > NOTICES_PER_SECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +96,37 @@ class NoticeSection extends Section
|
|||||||
|
|
||||||
$this->out->elementStart('p', 'entry-content');
|
$this->out->elementStart('p', 'entry-content');
|
||||||
$this->out->raw($notice->rendered);
|
$this->out->raw($notice->rendered);
|
||||||
|
|
||||||
|
$notice_link_cfg = common_config('site', 'notice_link');
|
||||||
|
if ('direct' === $notice_link_cfg) {
|
||||||
|
$this->out->text(' (');
|
||||||
|
$this->out->element('a', array('href' => $notice->uri), 'see');
|
||||||
|
$this->out->text(')');
|
||||||
|
} elseif ('attachment' === $notice_link_cfg) {
|
||||||
|
if ($count = $notice->hasAttachments()) {
|
||||||
|
// link to attachment(s) pages
|
||||||
|
if (1 === $count) {
|
||||||
|
$f2p = File_to_post::staticGet('post_id', $notice->id);
|
||||||
|
$href = common_local_url('attachment', array('attachment' => $f2p->file_id));
|
||||||
|
$att_class = 'attachment';
|
||||||
|
} else {
|
||||||
|
$href = common_local_url('attachments', array('notice' => $notice->id));
|
||||||
|
$att_class = 'attachments';
|
||||||
|
}
|
||||||
|
|
||||||
|
$clip = theme_path('images/icons/clip.png', 'base');
|
||||||
|
$this->out->elementStart('a', array('class' => $att_class, 'style' => "font-style: italic;", 'href' => $href, 'title' => "# of attachments: $count"));
|
||||||
|
$this->out->raw(" ($count ");
|
||||||
|
$this->out->element('img', array('style' => 'display: inline', 'align' => 'top', 'width' => 20, 'height' => 20, 'src' => $clip, 'alt' => 'alt'));
|
||||||
|
$this->out->text(')');
|
||||||
|
$this->out->elementEnd('a');
|
||||||
|
} else {
|
||||||
|
$this->out->text(' (');
|
||||||
|
$this->out->element('a', array('href' => $notice->uri), 'see');
|
||||||
|
$this->out->text(')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('p');
|
$this->out->elementEnd('p');
|
||||||
if (!empty($notice->value)) {
|
if (!empty($notice->value)) {
|
||||||
$this->out->elementStart('p');
|
$this->out->elementStart('p');
|
||||||
|
@ -93,6 +93,7 @@ class PersonalGroupNav extends Widget
|
|||||||
|
|
||||||
$this->out->elementStart('ul', array('class' => 'nav'));
|
$this->out->elementStart('ul', array('class' => 'nav'));
|
||||||
|
|
||||||
|
if (Event::handle('StartPersonalGroupNav', array($this))) {
|
||||||
$this->out->menuItem(common_local_url('all', array('nickname' =>
|
$this->out->menuItem(common_local_url('all', array('nickname' =>
|
||||||
$nickname)),
|
$nickname)),
|
||||||
_('Personal'),
|
_('Personal'),
|
||||||
@ -129,7 +130,8 @@ class PersonalGroupNav extends Widget
|
|||||||
_('Your sent messages'),
|
_('Your sent messages'),
|
||||||
$action == 'outbox');
|
$action == 'outbox');
|
||||||
}
|
}
|
||||||
|
Event::handle('EndPersonalGroupNav', array($this));
|
||||||
|
}
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ class PopularNoticeSection extends NoticeSection
|
|||||||
if (common_config('db', 'type') == 'pgsql') {
|
if (common_config('db', 'type') == 'pgsql') {
|
||||||
$weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))';
|
$weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))';
|
||||||
if (!empty($this->out->tag)) {
|
if (!empty($this->out->tag)) {
|
||||||
$tag = pg_escape_string($this->tag);
|
$tag = pg_escape_string($this->out->tag);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$weightexpr='sum(exp(-(now() - fave.modified) / %s))';
|
$weightexpr='sum(exp(-(now() - fave.modified) / %s))';
|
||||||
|
@ -52,6 +52,7 @@ class ProfileAction extends Action
|
|||||||
var $user = null;
|
var $user = null;
|
||||||
var $page = null;
|
var $page = null;
|
||||||
var $profile = null;
|
var $profile = null;
|
||||||
|
var $tag = null;
|
||||||
|
|
||||||
function prepare($args)
|
function prepare($args)
|
||||||
{
|
{
|
||||||
@ -85,10 +86,9 @@ class ProfileAction extends Action
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->tag = $this->trimmed('tag');
|
||||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||||
|
|
||||||
common_set_returnto($this->selfUrl());
|
common_set_returnto($this->selfUrl());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,3 +245,4 @@ class ProfileAction extends Action
|
|||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,12 +151,26 @@ class Router
|
|||||||
$m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'),
|
$m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'),
|
||||||
array('q' => '.+'));
|
array('q' => '.+'));
|
||||||
|
|
||||||
|
$m->connect('attachment/:attachment/ajax',
|
||||||
|
array('action' => 'attachment_ajax'),
|
||||||
|
array('notice' => '[0-9]+'));
|
||||||
|
|
||||||
|
$m->connect('attachment/:attachment',
|
||||||
|
array('action' => 'attachment'),
|
||||||
|
array('notice' => '[0-9]+'));
|
||||||
|
|
||||||
// notice
|
// notice
|
||||||
|
|
||||||
$m->connect('notice/new', array('action' => 'newnotice'));
|
$m->connect('notice/new', array('action' => 'newnotice'));
|
||||||
$m->connect('notice/new?replyto=:replyto',
|
$m->connect('notice/new?replyto=:replyto',
|
||||||
array('action' => 'newnotice'),
|
array('action' => 'newnotice'),
|
||||||
array('replyto' => '[A-Za-z0-9_-]+'));
|
array('replyto' => '[A-Za-z0-9_-]+'));
|
||||||
|
$m->connect('notice/:notice/attachments/ajax',
|
||||||
|
array('action' => 'attachments_ajax'),
|
||||||
|
array('notice' => '[0-9]+'));
|
||||||
|
$m->connect('notice/:notice/attachments',
|
||||||
|
array('action' => 'attachments'),
|
||||||
|
array('notice' => '[0-9]+'));
|
||||||
$m->connect('notice/:notice',
|
$m->connect('notice/:notice',
|
||||||
array('action' => 'shownotice'),
|
array('action' => 'shownotice'),
|
||||||
array('notice' => '[0-9]+'));
|
array('notice' => '[0-9]+'));
|
||||||
@ -237,12 +251,12 @@ class Router
|
|||||||
$m->connect('api/statuses/:method',
|
$m->connect('api/statuses/:method',
|
||||||
array('action' => 'api',
|
array('action' => 'api',
|
||||||
'apiaction' => 'statuses'),
|
'apiaction' => 'statuses'),
|
||||||
array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|friends|followers|featured)(\.(atom|rss|xml|json))?'));
|
array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|mentions|friends|followers|featured)(\.(atom|rss|xml|json))?'));
|
||||||
|
|
||||||
$m->connect('api/statuses/:method/:argument',
|
$m->connect('api/statuses/:method/:argument',
|
||||||
array('action' => 'api',
|
array('action' => 'api',
|
||||||
'apiaction' => 'statuses'),
|
'apiaction' => 'statuses'),
|
||||||
array('method' => '(user_timeline|friends_timeline|replies|show|destroy|friends|followers)'));
|
array('method' => '(user_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)'));
|
||||||
|
|
||||||
// users
|
// users
|
||||||
|
|
||||||
@ -412,6 +426,16 @@ class Router
|
|||||||
array('size' => '(original|96|48|24)',
|
array('size' => '(original|96|48|24)',
|
||||||
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
'nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||||
|
|
||||||
|
$m->connect(':nickname/tag/:tag/rss',
|
||||||
|
array('action' => 'userrss'),
|
||||||
|
array('nickname' => '[a-zA-Z0-9]{1,64}'),
|
||||||
|
array('tag' => '[a-zA-Z0-9]+'));
|
||||||
|
|
||||||
|
$m->connect(':nickname/tag/:tag',
|
||||||
|
array('action' => 'showstream'),
|
||||||
|
array('nickname' => '[a-zA-Z0-9]{1,64}'),
|
||||||
|
array('tag' => '[a-zA-Z0-9]+'));
|
||||||
|
|
||||||
$m->connect(':nickname',
|
$m->connect(':nickname',
|
||||||
array('action' => 'showstream'),
|
array('action' => 'showstream'),
|
||||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||||
|
@ -97,7 +97,11 @@ class Rss10Action extends Action
|
|||||||
// Parent handling, including cache check
|
// Parent handling, including cache check
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
// Get the list of notices
|
// Get the list of notices
|
||||||
|
if (empty($this->tag)) {
|
||||||
$this->notices = $this->getNotices($this->limit);
|
$this->notices = $this->getNotices($this->limit);
|
||||||
|
} else {
|
||||||
|
$this->notices = $this->getTaggedNotices($this->tag, $this->limit);
|
||||||
|
}
|
||||||
$this->showRss();
|
$this->showRss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,8 @@ class SubGroupNav extends Widget
|
|||||||
|
|
||||||
$this->out->elementStart('ul', array('class' => 'nav'));
|
$this->out->elementStart('ul', array('class' => 'nav'));
|
||||||
|
|
||||||
|
if (Event::handle('StartSubGroupNav', array($this))) {
|
||||||
|
|
||||||
$this->out->menuItem(common_local_url('subscriptions',
|
$this->out->menuItem(common_local_url('subscriptions',
|
||||||
array('nickname' =>
|
array('nickname' =>
|
||||||
$this->user->nickname)),
|
$this->user->nickname)),
|
||||||
@ -106,6 +108,10 @@ class SubGroupNav extends Widget
|
|||||||
$action == 'invite',
|
$action == 'invite',
|
||||||
'nav_invite');
|
'nav_invite');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Event::handle('EndSubGroupNav', array($this));
|
||||||
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
77
lib/subpeopletagcloudsection.php
Normal file
77
lib/subpeopletagcloudsection.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SubPeopleTagCloudSection extends TagCloudSection
|
||||||
|
{
|
||||||
|
function getTags()
|
||||||
|
{
|
||||||
|
$qry = $this->query();
|
||||||
|
$limit = TAGS_PER_SECTION;
|
||||||
|
$offset = 0;
|
||||||
|
|
||||||
|
if (common_config('db','type') == 'pgsql') {
|
||||||
|
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||||
|
} else {
|
||||||
|
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$profile_tag = Memcached_DataObject::cachedQuery('Profile_tag',
|
||||||
|
sprintf($qry,
|
||||||
|
$this->out->user->id));
|
||||||
|
return $profile_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tagUrl($tag) {
|
||||||
|
return common_local_url('peopletag', array('tag' => $tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
function showTag($tag, $weight, $relative) {
|
||||||
|
$rel = 'tag-cloud-';
|
||||||
|
$rel .= 1+intval(7 * $relative * $weight - 0.01);
|
||||||
|
|
||||||
|
$this->out->elementStart('li', $rel);
|
||||||
|
$this->out->element('a', array('href' => $this->tagUrl($tag)), $tag);
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
62
lib/subscriberspeopleselftagcloudsection.php
Normal file
62
lib/subscriberspeopleselftagcloudsection.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SubscribersPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
|
||||||
|
{
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('People Tagcloud as self-tagged');
|
||||||
|
}
|
||||||
|
|
||||||
|
function query() {
|
||||||
|
// return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged group by tag order by weight desc';
|
||||||
|
|
||||||
|
|
||||||
|
return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
|
||||||
|
|
||||||
|
// return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscribed where subscriber=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
61
lib/subscriberspeopletagcloudsection.php
Normal file
61
lib/subscriberspeopletagcloudsection.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SubscribersPeopleTagCloudSection extends SubPeopleTagCloudSection
|
||||||
|
{
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('People Tagcloud as tagged');
|
||||||
|
}
|
||||||
|
|
||||||
|
function tagUrl($tag) {
|
||||||
|
$nickname = $this->out->profile->nickname;
|
||||||
|
return common_local_url('subscribers', array('nickname' => $nickname, 'tag' => $tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
function query() {
|
||||||
|
// return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagged and subscribed=tagger where subscribed=%d and subscriber != subscribed group by tag order by weight desc';
|
||||||
|
return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagged and subscribed=tagger where subscribed=%d and subscriber != subscribed and tag is not null group by tag order by weight desc';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
61
lib/subscriptionspeopleselftagcloudsection.php
Normal file
61
lib/subscriptionspeopleselftagcloudsection.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SubscriptionsPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
|
||||||
|
{
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('People Tagcloud as self-tagged');
|
||||||
|
}
|
||||||
|
|
||||||
|
function query() {
|
||||||
|
// return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscriber != subscribed and tagger = tagged group by tag order by weight desc';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscribed where subscriber=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
|
||||||
|
|
||||||
|
// return 'select tag, count(tag) as weight from subscription left join profile_tag on tagger = subscriber where subscribed=%d and subscribed != subscriber and tagger = tagged and tag is not null group by tag order by weight desc';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
61
lib/subscriptionspeopletagcloudsection.php
Normal file
61
lib/subscriptionspeopletagcloudsection.php
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Personal tag cloud section
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SubscriptionsPeopleTagCloudSection extends SubPeopleTagCloudSection
|
||||||
|
{
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('People Tagcloud as tagged');
|
||||||
|
}
|
||||||
|
|
||||||
|
function tagUrl($tag) {
|
||||||
|
$nickname = $this->out->profile->nickname;
|
||||||
|
return common_local_url('subscriptions', array('nickname' => $nickname, 'tag' => $tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
function query() {
|
||||||
|
// return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagger and subscribed=tagged where subscriber=%d and subscriber != subscribed group by tag order by weight desc';
|
||||||
|
return 'select tag, count(tag) as weight from subscription left join profile_tag on subscriber=tagger and subscribed=tagged where subscriber=%d and subscriber != subscribed and tag is not null group by tag order by weight desc';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -114,8 +114,12 @@ class TagCloudSection extends Section
|
|||||||
|
|
||||||
function tagUrl($tag)
|
function tagUrl($tag)
|
||||||
{
|
{
|
||||||
|
if ('showstream' === $this->out->trimmed('action')) {
|
||||||
|
return common_local_url('showstream', array('nickname' => $this->out->profile->nickname, 'tag' => $tag));
|
||||||
|
} else {
|
||||||
return common_local_url('tag', array('tag' => $tag));
|
return common_local_url('tag', array('tag' => $tag));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function divId()
|
function divId()
|
||||||
{
|
{
|
||||||
|
@ -51,6 +51,26 @@ class TwitterapiAction extends Action
|
|||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides XMLOutputter::element to write booleans as strings (true|false).
|
||||||
|
* See that method's documentation for more info.
|
||||||
|
*
|
||||||
|
* @param string $tag Element type or tagname
|
||||||
|
* @param array $attrs Array of element attributes, as
|
||||||
|
* key-value pairs
|
||||||
|
* @param string $content string content of the element
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function element($tag, $attrs=null, $content=null)
|
||||||
|
{
|
||||||
|
if (is_bool($content)) {
|
||||||
|
$content = ($content ? 'true' : 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::element($tag, $attrs, $content);
|
||||||
|
}
|
||||||
|
|
||||||
function twitter_user_array($profile, $get_notice=false)
|
function twitter_user_array($profile, $get_notice=false)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -66,7 +86,7 @@ class TwitterapiAction extends Action
|
|||||||
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
||||||
|
|
||||||
$twitter_user['profile_image_url'] = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE);
|
$twitter_user['profile_image_url'] = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE);
|
||||||
$twitter_user['protected'] = 'false'; # not supported by Laconica yet
|
$twitter_user['protected'] = false; # not supported by Laconica yet
|
||||||
$twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
|
$twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
|
||||||
|
|
||||||
if ($get_notice) {
|
if ($get_notice) {
|
||||||
@ -86,7 +106,7 @@ class TwitterapiAction extends Action
|
|||||||
|
|
||||||
$twitter_status = array();
|
$twitter_status = array();
|
||||||
$twitter_status['text'] = $notice->content;
|
$twitter_status['text'] = $notice->content;
|
||||||
$twitter_status['truncated'] = 'false'; # Not possible on Laconica
|
$twitter_status['truncated'] = false; # Not possible on Laconica
|
||||||
$twitter_status['created_at'] = $this->date_twitter($notice->created);
|
$twitter_status['created_at'] = $this->date_twitter($notice->created);
|
||||||
$twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ?
|
$twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ?
|
||||||
intval($notice->reply_to) : null;
|
intval($notice->reply_to) : null;
|
||||||
@ -108,10 +128,9 @@ class TwitterapiAction extends Action
|
|||||||
($replier_profile) ? $replier_profile->nickname : null;
|
($replier_profile) ? $replier_profile->nickname : null;
|
||||||
|
|
||||||
if (isset($this->auth_user)) {
|
if (isset($this->auth_user)) {
|
||||||
$twitter_status['favorited'] =
|
$twitter_status['favorited'] = $this->auth_user->hasFave($notice);
|
||||||
($this->auth_user->hasFave($notice)) ? 'true' : 'false';
|
|
||||||
} else {
|
} else {
|
||||||
$twitter_status['favorited'] = 'false';
|
$twitter_status['favorited'] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($include_user) {
|
if ($include_user) {
|
||||||
@ -418,7 +437,7 @@ class TwitterapiAction extends Action
|
|||||||
function date_twitter($dt)
|
function date_twitter($dt)
|
||||||
{
|
{
|
||||||
$t = strtotime($dt);
|
$t = strtotime($dt);
|
||||||
return date("D M d G:i:s O Y", $t);
|
return date("D M d H:i:s O Y", $t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: Candidate for a general utility method somewhere?
|
// XXX: Candidate for a general utility method somewhere?
|
||||||
|
106
lib/util.php
106
lib/util.php
@ -395,7 +395,7 @@ function common_render_text($text)
|
|||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
function common_replace_urls_callback($text, $callback) {
|
function common_replace_urls_callback($text, $callback, $notice_id = null) {
|
||||||
// Start off with a regex
|
// Start off with a regex
|
||||||
$regex = '#'.
|
$regex = '#'.
|
||||||
'(?:'.
|
'(?:'.
|
||||||
@ -466,7 +466,11 @@ function common_replace_urls_callback($text, $callback) {
|
|||||||
$url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url);
|
$url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url);
|
||||||
|
|
||||||
// Call user specified func
|
// Call user specified func
|
||||||
|
if (empty($notice_id)) {
|
||||||
$modified_url = call_user_func($callback, $url);
|
$modified_url = call_user_func($callback, $url);
|
||||||
|
} else {
|
||||||
|
$modified_url = call_user_func($callback, array($url, $notice_id));
|
||||||
|
}
|
||||||
|
|
||||||
// Replace it!
|
// Replace it!
|
||||||
$start = mb_strpos($text, $url, $offset);
|
$start = mb_strpos($text, $url, $offset);
|
||||||
@ -481,102 +485,24 @@ function common_linkify($url) {
|
|||||||
// It comes in special'd, so we unspecial it before passing to the stringifying
|
// It comes in special'd, so we unspecial it before passing to the stringifying
|
||||||
// functions
|
// functions
|
||||||
$url = htmlspecialchars_decode($url);
|
$url = htmlspecialchars_decode($url);
|
||||||
$display = $url;
|
$display = File_redirection::_canonUrl($url);
|
||||||
$url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url : $url;
|
$longurl_data = File_redirection::where($url);
|
||||||
|
if (is_array($longurl_data)) {
|
||||||
$attrs = array('href' => $url, 'rel' => 'external');
|
$longurl = $longurl_data['url'];
|
||||||
|
} elseif (is_string($longurl_data)) {
|
||||||
if ($longurl = common_longurl($url)) {
|
$longurl = $longurl_data;
|
||||||
$attrs['title'] = $longurl;
|
} else {
|
||||||
|
die('impossible to linkify');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$attrs = array('href' => $longurl, 'rel' => 'external');
|
||||||
return XMLStringer::estring('a', $attrs, $display);
|
return XMLStringer::estring('a', $attrs, $display);
|
||||||
}
|
}
|
||||||
|
|
||||||
function common_longurl($short_url)
|
|
||||||
{
|
|
||||||
$long_url = common_shorten_link($short_url, true);
|
|
||||||
if ($long_url === $short_url) return false;
|
|
||||||
return $long_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
function common_longurl2($uri)
|
|
||||||
{
|
|
||||||
$uri_e = urlencode($uri);
|
|
||||||
$longurl = unserialize(file_get_contents("http://api.longurl.org/v1/expand?format=php&url=$uri_e"));
|
|
||||||
if (empty($longurl['long_url']) || $uri === $longurl['long_url']) return false;
|
|
||||||
return stripslashes($longurl['long_url']);
|
|
||||||
}
|
|
||||||
|
|
||||||
function common_shorten_links($text)
|
function common_shorten_links($text)
|
||||||
{
|
{
|
||||||
if (mb_strlen($text) <= 140) return $text;
|
if (mb_strlen($text) <= 140) return $text;
|
||||||
static $cache = array();
|
return common_replace_urls_callback($text, array('File_redirection', 'makeShort'));
|
||||||
if (isset($cache[$text])) return $cache[$text];
|
|
||||||
// \s = not a horizontal whitespace character (since PHP 5.2.4)
|
|
||||||
return $cache[$text] = common_replace_urls_callback($text, 'common_shorten_link');;
|
|
||||||
}
|
|
||||||
|
|
||||||
function common_shorten_link($url, $reverse = false)
|
|
||||||
{
|
|
||||||
static $url_cache = array();
|
|
||||||
if ($reverse) return isset($url_cache[$url]) ? $url_cache[$url] : $url;
|
|
||||||
|
|
||||||
$user = common_current_user();
|
|
||||||
|
|
||||||
$curlh = curl_init();
|
|
||||||
curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 20); // # seconds to wait
|
|
||||||
curl_setopt($curlh, CURLOPT_USERAGENT, 'Laconica');
|
|
||||||
curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
|
|
||||||
switch($user->urlshorteningservice) {
|
|
||||||
case 'ur1.ca':
|
|
||||||
$short_url_service = new LilUrl;
|
|
||||||
$short_url = $short_url_service->shorten($url);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '2tu.us':
|
|
||||||
$short_url_service = new TightUrl;
|
|
||||||
$short_url = $short_url_service->shorten($url);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'ptiturl.com':
|
|
||||||
$short_url_service = new PtitUrl;
|
|
||||||
$short_url = $short_url_service->shorten($url);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'bit.ly':
|
|
||||||
curl_setopt($curlh, CURLOPT_URL, 'http://bit.ly/api?method=shorten&long_url='.urlencode($url));
|
|
||||||
$short_url = current(json_decode(curl_exec($curlh))->results)->hashUrl;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'is.gd':
|
|
||||||
curl_setopt($curlh, CURLOPT_URL, 'http://is.gd/api.php?longurl='.urlencode($url));
|
|
||||||
$short_url = curl_exec($curlh);
|
|
||||||
break;
|
|
||||||
case 'snipr.com':
|
|
||||||
curl_setopt($curlh, CURLOPT_URL, 'http://snipr.com/site/snip?r=simple&link='.urlencode($url));
|
|
||||||
$short_url = curl_exec($curlh);
|
|
||||||
break;
|
|
||||||
case 'metamark.net':
|
|
||||||
curl_setopt($curlh, CURLOPT_URL, 'http://metamark.net/api/rest/simple?long_url='.urlencode($url));
|
|
||||||
$short_url = curl_exec($curlh);
|
|
||||||
break;
|
|
||||||
case 'tinyurl.com':
|
|
||||||
curl_setopt($curlh, CURLOPT_URL, 'http://tinyurl.com/api-create.php?url='.urlencode($url));
|
|
||||||
$short_url = curl_exec($curlh);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$short_url = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_close($curlh);
|
|
||||||
|
|
||||||
if ($short_url) {
|
|
||||||
$url_cache[(string)$short_url] = $url;
|
|
||||||
return (string)$short_url;
|
|
||||||
}
|
|
||||||
return $url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function common_xml_safe_str($str)
|
function common_xml_safe_str($str)
|
||||||
@ -1019,7 +945,7 @@ function common_root_url($ssl=false)
|
|||||||
function common_good_rand($bytes)
|
function common_good_rand($bytes)
|
||||||
{
|
{
|
||||||
// XXX: use random.org...?
|
// XXX: use random.org...?
|
||||||
if (file_exists('/dev/urandom')) {
|
if (@file_exists('/dev/urandom')) {
|
||||||
return common_urandom($bytes);
|
return common_urandom($bytes);
|
||||||
} else { // FIXME: this is probably not good enough
|
} else { // FIXME: this is probably not good enough
|
||||||
return common_mtrand($bytes);
|
return common_mtrand($bytes);
|
||||||
|
205
plugins/Comet/CometPlugin.php
Normal file
205
plugins/Comet/CometPlugin.php
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Plugin to do "real time" updates using Comet/Bayeux
|
||||||
|
*
|
||||||
|
* 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 Plugin
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin to do realtime updates using Comet
|
||||||
|
*
|
||||||
|
* @category Plugin
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CometPlugin extends Plugin
|
||||||
|
{
|
||||||
|
var $server = null;
|
||||||
|
|
||||||
|
function __construct($server=null, $username=null, $password=null)
|
||||||
|
{
|
||||||
|
$this->server = $server;
|
||||||
|
$this->username = $username;
|
||||||
|
$this->password = $password;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEndShowScripts($action)
|
||||||
|
{
|
||||||
|
$timeline = null;
|
||||||
|
|
||||||
|
$this->log(LOG_DEBUG, 'got action ' . $action->trimmed('action'));
|
||||||
|
|
||||||
|
switch ($action->trimmed('action')) {
|
||||||
|
case 'public':
|
||||||
|
$timeline = '/timelines/public';
|
||||||
|
break;
|
||||||
|
case 'tag':
|
||||||
|
$tag = $action->trimmed('tag');
|
||||||
|
if (!empty($tag)) {
|
||||||
|
$timeline = '/timelines/tag/'.$tag;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scripts = array('jquery.comet.js', 'json2.js', 'updatetimeline.js');
|
||||||
|
|
||||||
|
foreach ($scripts as $script) {
|
||||||
|
$action->element('script', array('type' => 'text/javascript',
|
||||||
|
'src' => common_path('plugins/Comet/'.$script)),
|
||||||
|
' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = common_current_user();
|
||||||
|
|
||||||
|
if (!empty($user->id)) {
|
||||||
|
$user_id = $user->id;
|
||||||
|
} else {
|
||||||
|
$user_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$replyurl = common_local_url('newnotice');
|
||||||
|
$favorurl = common_local_url('favor');
|
||||||
|
// FIXME: need to find a better way to pass this pattern in
|
||||||
|
$deleteurl = common_local_url('deletenotice',
|
||||||
|
array('notice' => '0000000000'));
|
||||||
|
|
||||||
|
$action->elementStart('script', array('type' => 'text/javascript'));
|
||||||
|
$action->raw("$(document).ready(function() { updater.init(\"$this->server\", \"$timeline\", $user_id, \"$replyurl\", \"$favorurl\", \"$deleteurl\"); });");
|
||||||
|
$action->elementEnd('script');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEndNoticeSave($notice)
|
||||||
|
{
|
||||||
|
$this->log(LOG_INFO, "Called for save notice.");
|
||||||
|
|
||||||
|
$timelines = array();
|
||||||
|
|
||||||
|
// XXX: Add other timelines; this is just for the public one
|
||||||
|
|
||||||
|
if ($notice->is_local ||
|
||||||
|
($notice->is_local == 0 && !common_config('public', 'localonly'))) {
|
||||||
|
$timelines[] = '/timelines/public';
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags = $this->getNoticeTags($notice);
|
||||||
|
|
||||||
|
if (!empty($tags)) {
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
$timelines[] = '/timelines/tag/' . $tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($timelines) > 0) {
|
||||||
|
// Require this, since we need it
|
||||||
|
require_once(INSTALLDIR.'/plugins/Comet/bayeux.class.inc.php');
|
||||||
|
|
||||||
|
$json = $this->noticeAsJson($notice);
|
||||||
|
|
||||||
|
// Bayeux? Comet? Huh? These terms confuse me
|
||||||
|
$bay = new Bayeux($this->server, $this->user, $this->password);
|
||||||
|
|
||||||
|
foreach ($timelines as $timeline) {
|
||||||
|
$this->log(LOG_INFO, "Posting notice $notice->id to '$timeline'.");
|
||||||
|
$bay->publish($timeline, $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
$bay = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function noticeAsJson($notice)
|
||||||
|
{
|
||||||
|
// FIXME: this code should be abstracted to a neutral third
|
||||||
|
// party, like Notice::asJson(). I'm not sure of the ethics
|
||||||
|
// of refactoring from within a plugin, so I'm just abusing
|
||||||
|
// the TwitterApiAction method. Don't do this unless you're me!
|
||||||
|
|
||||||
|
require_once(INSTALLDIR.'/lib/twitterapi.php');
|
||||||
|
|
||||||
|
$act = new TwitterApiAction('/dev/null');
|
||||||
|
|
||||||
|
$arr = $act->twitter_status_array($notice, true);
|
||||||
|
$arr['url'] = $notice->bestUrl();
|
||||||
|
$arr['html'] = htmlspecialchars($notice->rendered);
|
||||||
|
$arr['source'] = htmlspecialchars($arr['source']);
|
||||||
|
|
||||||
|
if (!empty($notice->reply_to)) {
|
||||||
|
$reply_to = Notice::staticGet('id', $notice->reply_to);
|
||||||
|
if (!empty($reply_to)) {
|
||||||
|
$arr['in_reply_to_status_url'] = $reply_to->bestUrl();
|
||||||
|
}
|
||||||
|
$reply_to = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$profile = $notice->getProfile();
|
||||||
|
$arr['user']['profile_url'] = $profile->profileurl;
|
||||||
|
|
||||||
|
return $arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNoticeTags($notice)
|
||||||
|
{
|
||||||
|
$tags = null;
|
||||||
|
|
||||||
|
$nt = new Notice_tag();
|
||||||
|
$nt->notice_id = $notice->id;
|
||||||
|
|
||||||
|
if ($nt->find()) {
|
||||||
|
$tags = array();
|
||||||
|
while ($nt->fetch()) {
|
||||||
|
$tags[] = $nt->tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nt->free();
|
||||||
|
$nt = null;
|
||||||
|
|
||||||
|
return $tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push this up to Plugin
|
||||||
|
|
||||||
|
function log($level, $msg)
|
||||||
|
{
|
||||||
|
common_log($level, get_class($this) . ': '.$msg);
|
||||||
|
}
|
||||||
|
}
|
26
plugins/Comet/README
Normal file
26
plugins/Comet/README
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
This is a plugin to automatically load notices in the browser no
|
||||||
|
matter who creates them -- the kind of thing we see with
|
||||||
|
search.twitter.com, rejaw.com, or FriendFeed's "real time" news.
|
||||||
|
|
||||||
|
NOTE: this is an insecure version; don't roll it out on a production
|
||||||
|
server.
|
||||||
|
|
||||||
|
It requires a cometd server. I've only had the cometd-java server work
|
||||||
|
correctly; something's wiggy with the Twisted-based server.
|
||||||
|
|
||||||
|
After you have a cometd server installed, just add this code to your
|
||||||
|
config.php:
|
||||||
|
|
||||||
|
require_once(INSTALLDIR.'/plugins/Comet/CometPlugin.php');
|
||||||
|
$cp = new CometPlugin('http://example.com:8080/cometd/');
|
||||||
|
|
||||||
|
Change 'example.com:8080' to the name and port of the server you
|
||||||
|
installed cometd on.
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
* Needs to be tested with Ajax submission. Probably messes everything
|
||||||
|
up.
|
||||||
|
* Add more timelines: personal inbox and tags would be great.
|
||||||
|
* Add security. In particular, only let the PHP code publish notices
|
||||||
|
to the cometd server. Currently, it doesn't try to authenticate.
|
134
plugins/Comet/bayeux.class.inc.php
Normal file
134
plugins/Comet/bayeux.class.inc.php
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Phomet: a php comet client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Morgan 'ARR!' Allen <morganrallen@gmail.com> http://morglog.alleycatracing.com
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Bayeux
|
||||||
|
{
|
||||||
|
private $oCurl = '';
|
||||||
|
private $nNextId = 0;
|
||||||
|
|
||||||
|
private $sUser = '';
|
||||||
|
private $sPassword = '';
|
||||||
|
|
||||||
|
public $sUrl = '';
|
||||||
|
|
||||||
|
function __construct($sUrl, $sUser='', $sPassword='')
|
||||||
|
{
|
||||||
|
$this->sUrl = $sUrl;
|
||||||
|
|
||||||
|
$this->oCurl = curl_init();
|
||||||
|
|
||||||
|
$aHeaders = array();
|
||||||
|
$aHeaders[] = 'Connection: Keep-Alive';
|
||||||
|
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_URL, $sUrl);
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_HTTPHEADER, $aHeaders);
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_HEADER, 0);
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_POST, 1);
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_RETURNTRANSFER,1);
|
||||||
|
|
||||||
|
if (!is_null($sUser) && mb_strlen($sUser) > 0) {
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_USERPWD,"$sUser:$sPassword");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->handShake();
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct()
|
||||||
|
{
|
||||||
|
$this->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handShake()
|
||||||
|
{
|
||||||
|
$msgHandshake = array();
|
||||||
|
$msgHandshake['channel'] = '/meta/handshake';
|
||||||
|
$msgHandshake['version'] = "1.0";
|
||||||
|
$msgHandshake['minimumVersion'] = "0.9";
|
||||||
|
$msgHandshake['supportedConnectionTypes'] = array('long-polling');
|
||||||
|
$msgHandshake['id'] = $this->nNextId++;
|
||||||
|
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_POSTFIELDS, "message=".urlencode(str_replace('\\', '', json_encode(array($msgHandshake)))));
|
||||||
|
|
||||||
|
$data = curl_exec($this->oCurl);
|
||||||
|
|
||||||
|
if(curl_errno($this->oCurl))
|
||||||
|
die("Error: " . curl_error($this->oCurl));
|
||||||
|
|
||||||
|
$oReturn = json_decode($data);
|
||||||
|
|
||||||
|
if (is_array($oReturn)) {
|
||||||
|
$oReturn = $oReturn[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$bSuccessful = ($oReturn->successful) ? true : false;
|
||||||
|
|
||||||
|
if($bSuccessful)
|
||||||
|
{
|
||||||
|
$this->clientId = $oReturn->clientId;
|
||||||
|
|
||||||
|
$this->connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function connect()
|
||||||
|
{
|
||||||
|
$aMsg['channel'] = '/meta/connect';
|
||||||
|
$aMsg['id'] = $this->nNextId++;
|
||||||
|
$aMsg['clientId'] = $this->clientId;
|
||||||
|
$aMsg['connectionType'] = 'long-polling';
|
||||||
|
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_POSTFIELDS, "message=".urlencode(str_replace('\\', '', json_encode(array($aMsg)))));
|
||||||
|
|
||||||
|
$data = curl_exec($this->oCurl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disconnect()
|
||||||
|
{
|
||||||
|
$msgHandshake = array();
|
||||||
|
$msgHandshake['channel'] = '/meta/disconnect';
|
||||||
|
$msgHandshake['id'] = $this->nNextId++;
|
||||||
|
$msgHandshake['clientId'] = $this->clientId;
|
||||||
|
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_POSTFIELDS, "message=".urlencode(str_replace('\\', '', json_encode(array($msgHandshake)))));
|
||||||
|
|
||||||
|
curl_exec($this->oCurl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function publish($sChannel, $oData)
|
||||||
|
{
|
||||||
|
if(!$sChannel || !$oData)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$aMsg = array();
|
||||||
|
|
||||||
|
$aMsg['channel'] = $sChannel;
|
||||||
|
$aMsg['id'] = $this->nNextId++;
|
||||||
|
$aMsg['data'] = $oData;
|
||||||
|
$aMsg['clientId'] = $this->clientId;
|
||||||
|
|
||||||
|
curl_setopt($this->oCurl, CURLOPT_POSTFIELDS, "message=".urlencode(str_replace('\\', '', json_encode(array($aMsg)))));
|
||||||
|
|
||||||
|
$data = curl_exec($this->oCurl);
|
||||||
|
// var_dump($data);
|
||||||
|
}
|
||||||
|
}
|
1451
plugins/Comet/jquery.comet.js
Normal file
1451
plugins/Comet/jquery.comet.js
Normal file
File diff suppressed because it is too large
Load Diff
478
plugins/Comet/json2.js
Normal file
478
plugins/Comet/json2.js
Normal file
@ -0,0 +1,478 @@
|
|||||||
|
/*
|
||||||
|
http://www.JSON.org/json2.js
|
||||||
|
2009-04-16
|
||||||
|
|
||||||
|
Public Domain.
|
||||||
|
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
See http://www.JSON.org/js.html
|
||||||
|
|
||||||
|
This file creates a global JSON object containing two methods: stringify
|
||||||
|
and parse.
|
||||||
|
|
||||||
|
JSON.stringify(value, replacer, space)
|
||||||
|
value any JavaScript value, usually an object or array.
|
||||||
|
|
||||||
|
replacer an optional parameter that determines how object
|
||||||
|
values are stringified for objects. It can be a
|
||||||
|
function or an array of strings.
|
||||||
|
|
||||||
|
space an optional parameter that specifies the indentation
|
||||||
|
of nested structures. If it is omitted, the text will
|
||||||
|
be packed without extra whitespace. If it is a number,
|
||||||
|
it will specify the number of spaces to indent at each
|
||||||
|
level. If it is a string (such as '\t' or ' '),
|
||||||
|
it contains the characters used to indent at each level.
|
||||||
|
|
||||||
|
This method produces a JSON text from a JavaScript value.
|
||||||
|
|
||||||
|
When an object value is found, if the object contains a toJSON
|
||||||
|
method, its toJSON method will be called and the result will be
|
||||||
|
stringified. A toJSON method does not serialize: it returns the
|
||||||
|
value represented by the name/value pair that should be serialized,
|
||||||
|
or undefined if nothing should be serialized. The toJSON method
|
||||||
|
will be passed the key associated with the value, and this will be
|
||||||
|
bound to the object holding the key.
|
||||||
|
|
||||||
|
For example, this would serialize Dates as ISO strings.
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function (key) {
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z';
|
||||||
|
};
|
||||||
|
|
||||||
|
You can provide an optional replacer method. It will be passed the
|
||||||
|
key and value of each member, with this bound to the containing
|
||||||
|
object. The value that is returned from your method will be
|
||||||
|
serialized. If your method returns undefined, then the member will
|
||||||
|
be excluded from the serialization.
|
||||||
|
|
||||||
|
If the replacer parameter is an array of strings, then it will be
|
||||||
|
used to select the members to be serialized. It filters the results
|
||||||
|
such that only members with keys listed in the replacer array are
|
||||||
|
stringified.
|
||||||
|
|
||||||
|
Values that do not have JSON representations, such as undefined or
|
||||||
|
functions, will not be serialized. Such values in objects will be
|
||||||
|
dropped; in arrays they will be replaced with null. You can use
|
||||||
|
a replacer function to replace those with JSON values.
|
||||||
|
JSON.stringify(undefined) returns undefined.
|
||||||
|
|
||||||
|
The optional space parameter produces a stringification of the
|
||||||
|
value that is filled with line breaks and indentation to make it
|
||||||
|
easier to read.
|
||||||
|
|
||||||
|
If the space parameter is a non-empty string, then that string will
|
||||||
|
be used for indentation. If the space parameter is a number, then
|
||||||
|
the indentation will be that many spaces.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||||
|
// text is '["e",{"pluribus":"unum"}]'
|
||||||
|
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||||
|
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||||
|
|
||||||
|
text = JSON.stringify([new Date()], function (key, value) {
|
||||||
|
return this[key] instanceof Date ?
|
||||||
|
'Date(' + this[key] + ')' : value;
|
||||||
|
});
|
||||||
|
// text is '["Date(---current time---)"]'
|
||||||
|
|
||||||
|
|
||||||
|
JSON.parse(text, reviver)
|
||||||
|
This method parses a JSON text to produce an object or array.
|
||||||
|
It can throw a SyntaxError exception.
|
||||||
|
|
||||||
|
The optional reviver parameter is a function that can filter and
|
||||||
|
transform the results. It receives each of the keys and values,
|
||||||
|
and its return value is used instead of the original value.
|
||||||
|
If it returns what it received, then the structure is not modified.
|
||||||
|
If it returns undefined then the member is deleted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
// Parse the text. Values that look like ISO date strings will
|
||||||
|
// be converted to Date objects.
|
||||||
|
|
||||||
|
myData = JSON.parse(text, function (key, value) {
|
||||||
|
var a;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
a =
|
||||||
|
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||||
|
if (a) {
|
||||||
|
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||||
|
+a[5], +a[6]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||||
|
var d;
|
||||||
|
if (typeof value === 'string' &&
|
||||||
|
value.slice(0, 5) === 'Date(' &&
|
||||||
|
value.slice(-1) === ')') {
|
||||||
|
d = new Date(value.slice(5, -1));
|
||||||
|
if (d) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
This is a reference implementation. You are free to copy, modify, or
|
||||||
|
redistribute.
|
||||||
|
|
||||||
|
This code should be minified before deployment.
|
||||||
|
See http://javascript.crockford.com/jsmin.html
|
||||||
|
|
||||||
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||||
|
NOT CONTROL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jslint evil: true */
|
||||||
|
|
||||||
|
/*global JSON */
|
||||||
|
|
||||||
|
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||||
|
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||||
|
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||||
|
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||||
|
test, toJSON, toString, valueOf
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Create a JSON object only if one does not already exist. We create the
|
||||||
|
// methods in a closure to avoid creating global variables.
|
||||||
|
|
||||||
|
if (!this.JSON) {
|
||||||
|
JSON = {};
|
||||||
|
}
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof Date.prototype.toJSON !== 'function') {
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function (key) {
|
||||||
|
|
||||||
|
return this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z';
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.toJSON =
|
||||||
|
Number.prototype.toJSON =
|
||||||
|
Boolean.prototype.toJSON = function (key) {
|
||||||
|
return this.valueOf();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
gap,
|
||||||
|
indent,
|
||||||
|
meta = { // table of character substitutions
|
||||||
|
'\b': '\\b',
|
||||||
|
'\t': '\\t',
|
||||||
|
'\n': '\\n',
|
||||||
|
'\f': '\\f',
|
||||||
|
'\r': '\\r',
|
||||||
|
'"' : '\\"',
|
||||||
|
'\\': '\\\\'
|
||||||
|
},
|
||||||
|
rep;
|
||||||
|
|
||||||
|
|
||||||
|
function quote(string) {
|
||||||
|
|
||||||
|
// If the string contains no control characters, no quote characters, and no
|
||||||
|
// backslash characters, then we can safely slap some quotes around it.
|
||||||
|
// Otherwise we must also replace the offending characters with safe escape
|
||||||
|
// sequences.
|
||||||
|
|
||||||
|
escapable.lastIndex = 0;
|
||||||
|
return escapable.test(string) ?
|
||||||
|
'"' + string.replace(escapable, function (a) {
|
||||||
|
var c = meta[a];
|
||||||
|
return typeof c === 'string' ? c :
|
||||||
|
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
}) + '"' :
|
||||||
|
'"' + string + '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function str(key, holder) {
|
||||||
|
|
||||||
|
// Produce a string from holder[key].
|
||||||
|
|
||||||
|
var i, // The loop counter.
|
||||||
|
k, // The member key.
|
||||||
|
v, // The member value.
|
||||||
|
length,
|
||||||
|
mind = gap,
|
||||||
|
partial,
|
||||||
|
value = holder[key];
|
||||||
|
|
||||||
|
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||||
|
|
||||||
|
if (value && typeof value === 'object' &&
|
||||||
|
typeof value.toJSON === 'function') {
|
||||||
|
value = value.toJSON(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we were called with a replacer function, then call the replacer to
|
||||||
|
// obtain a replacement value.
|
||||||
|
|
||||||
|
if (typeof rep === 'function') {
|
||||||
|
value = rep.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// What happens next depends on the value's type.
|
||||||
|
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'string':
|
||||||
|
return quote(value);
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
|
||||||
|
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||||
|
|
||||||
|
return isFinite(value) ? String(value) : 'null';
|
||||||
|
|
||||||
|
case 'boolean':
|
||||||
|
case 'null':
|
||||||
|
|
||||||
|
// If the value is a boolean or null, convert it to a string. Note:
|
||||||
|
// typeof null does not produce 'null'. The case is included here in
|
||||||
|
// the remote chance that this gets fixed someday.
|
||||||
|
|
||||||
|
return String(value);
|
||||||
|
|
||||||
|
// If the type is 'object', we might be dealing with an object or an array or
|
||||||
|
// null.
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
|
||||||
|
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||||
|
// so watch out for that case.
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an array to hold the partial results of stringifying this object value.
|
||||||
|
|
||||||
|
gap += indent;
|
||||||
|
partial = [];
|
||||||
|
|
||||||
|
// Is the value an array?
|
||||||
|
|
||||||
|
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||||
|
|
||||||
|
// The value is an array. Stringify every element. Use null as a placeholder
|
||||||
|
// for non-JSON values.
|
||||||
|
|
||||||
|
length = value.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
partial[i] = str(i, value) || 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the elements together, separated with commas, and wrap them in
|
||||||
|
// brackets.
|
||||||
|
|
||||||
|
v = partial.length === 0 ? '[]' :
|
||||||
|
gap ? '[\n' + gap +
|
||||||
|
partial.join(',\n' + gap) + '\n' +
|
||||||
|
mind + ']' :
|
||||||
|
'[' + partial.join(',') + ']';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the replacer is an array, use it to select the members to be stringified.
|
||||||
|
|
||||||
|
if (rep && typeof rep === 'object') {
|
||||||
|
length = rep.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
k = rep[i];
|
||||||
|
if (typeof k === 'string') {
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Otherwise, iterate through all of the keys in the object.
|
||||||
|
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.hasOwnProperty.call(value, k)) {
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the member texts together, separated with commas,
|
||||||
|
// and wrap them in braces.
|
||||||
|
|
||||||
|
v = partial.length === 0 ? '{}' :
|
||||||
|
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
|
||||||
|
mind + '}' : '{' + partial.join(',') + '}';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a stringify method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.stringify !== 'function') {
|
||||||
|
JSON.stringify = function (value, replacer, space) {
|
||||||
|
|
||||||
|
// The stringify method takes a value and an optional replacer, and an optional
|
||||||
|
// space parameter, and returns a JSON text. The replacer can be a function
|
||||||
|
// that can replace values, or an array of strings that will select the keys.
|
||||||
|
// A default replacer method can be provided. Use of the space parameter can
|
||||||
|
// produce text that is more easily readable.
|
||||||
|
|
||||||
|
var i;
|
||||||
|
gap = '';
|
||||||
|
indent = '';
|
||||||
|
|
||||||
|
// If the space parameter is a number, make an indent string containing that
|
||||||
|
// many spaces.
|
||||||
|
|
||||||
|
if (typeof space === 'number') {
|
||||||
|
for (i = 0; i < space; i += 1) {
|
||||||
|
indent += ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the space parameter is a string, it will be used as the indent string.
|
||||||
|
|
||||||
|
} else if (typeof space === 'string') {
|
||||||
|
indent = space;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a replacer, it must be a function or an array.
|
||||||
|
// Otherwise, throw an error.
|
||||||
|
|
||||||
|
rep = replacer;
|
||||||
|
if (replacer && typeof replacer !== 'function' &&
|
||||||
|
(typeof replacer !== 'object' ||
|
||||||
|
typeof replacer.length !== 'number')) {
|
||||||
|
throw new Error('JSON.stringify');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a fake root object containing our value under the key of ''.
|
||||||
|
// Return the result of stringifying the value.
|
||||||
|
|
||||||
|
return str('', {'': value});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a parse method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.parse !== 'function') {
|
||||||
|
JSON.parse = function (text, reviver) {
|
||||||
|
|
||||||
|
// The parse method takes a text and an optional reviver function, and returns
|
||||||
|
// a JavaScript value if the text is a valid JSON text.
|
||||||
|
|
||||||
|
var j;
|
||||||
|
|
||||||
|
function walk(holder, key) {
|
||||||
|
|
||||||
|
// The walk method is used to recursively walk the resulting structure so
|
||||||
|
// that modifications can be made.
|
||||||
|
|
||||||
|
var k, v, value = holder[key];
|
||||||
|
if (value && typeof value === 'object') {
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.hasOwnProperty.call(value, k)) {
|
||||||
|
v = walk(value, k);
|
||||||
|
if (v !== undefined) {
|
||||||
|
value[k] = v;
|
||||||
|
} else {
|
||||||
|
delete value[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reviver.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Parsing happens in four stages. In the first stage, we replace certain
|
||||||
|
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||||
|
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||||
|
|
||||||
|
cx.lastIndex = 0;
|
||||||
|
if (cx.test(text)) {
|
||||||
|
text = text.replace(cx, function (a) {
|
||||||
|
return '\\u' +
|
||||||
|
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the second stage, we run the text against regular expressions that look
|
||||||
|
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||||
|
// because they can cause invocation, and '=' because it can cause mutation.
|
||||||
|
// But just to be safe, we want to reject all unexpected forms.
|
||||||
|
|
||||||
|
// We split the second stage into 4 regexp operations in order to work around
|
||||||
|
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||||
|
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||||
|
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||||
|
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||||
|
// we look to see that the remaining characters are only whitespace or ']' or
|
||||||
|
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||||
|
|
||||||
|
if (/^[\],:{}\s]*$/.
|
||||||
|
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
|
||||||
|
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
|
||||||
|
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||||
|
|
||||||
|
// In the third stage we use the eval function to compile the text into a
|
||||||
|
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||||
|
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||||
|
// in parens to eliminate the ambiguity.
|
||||||
|
|
||||||
|
j = eval('(' + text + ')');
|
||||||
|
|
||||||
|
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||||
|
// each name/value pair to a reviver function for possible transformation.
|
||||||
|
|
||||||
|
return typeof reviver === 'function' ?
|
||||||
|
walk({'': j}, '') : j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||||
|
|
||||||
|
throw new SyntaxError('JSON.parse');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}());
|
154
plugins/Comet/updatetimeline.js
Normal file
154
plugins/Comet/updatetimeline.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// update the local timeline from a Comet server
|
||||||
|
//
|
||||||
|
|
||||||
|
var updater = function()
|
||||||
|
{
|
||||||
|
var _server;
|
||||||
|
var _timeline;
|
||||||
|
var _userid;
|
||||||
|
var _replyurl;
|
||||||
|
var _favorurl;
|
||||||
|
var _deleteurl;
|
||||||
|
var _cometd;
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: function(server, timeline, userid, replyurl, favorurl, deleteurl)
|
||||||
|
{
|
||||||
|
_cometd = $.cometd; // Uses the default Comet object
|
||||||
|
_cometd.setLogLevel('debug');
|
||||||
|
_cometd.init(server);
|
||||||
|
_server = server;
|
||||||
|
_timeline = timeline;
|
||||||
|
_userid = userid;
|
||||||
|
_favorurl = favorurl;
|
||||||
|
_replyurl = replyurl;
|
||||||
|
_deleteurl = deleteurl;
|
||||||
|
_cometd.subscribe(timeline, receive);
|
||||||
|
$(window).unload(leave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function leave()
|
||||||
|
{
|
||||||
|
_cometd.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function receive(message)
|
||||||
|
{
|
||||||
|
id = message.data.id;
|
||||||
|
|
||||||
|
// Don't add it if it already exists
|
||||||
|
|
||||||
|
if ($("#notice-"+id).length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var noticeItem = makeNoticeItem(message.data);
|
||||||
|
$("#notices_primary .notices").prepend(noticeItem, true);
|
||||||
|
$("#notices_primary .notice:first").css({display:"none"});
|
||||||
|
$("#notices_primary .notice:first").fadeIn(1000);
|
||||||
|
NoticeHover();
|
||||||
|
NoticeReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeNoticeItem(data)
|
||||||
|
{
|
||||||
|
user = data['user'];
|
||||||
|
html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||||
|
source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||||
|
|
||||||
|
ni = "<li class=\"hentry notice\" id=\"notice-"+data['id']+"\">"+
|
||||||
|
"<div class=\"entry-title\">"+
|
||||||
|
"<span class=\"vcard author\">"+
|
||||||
|
"<a href=\""+user['profile_url']+"\" class=\"url\">"+
|
||||||
|
"<img src=\""+user['profile_image_url']+"\" class=\"avatar photo\" width=\"48\" height=\"48\" alt=\""+user['screen_name']+"\"/>"+
|
||||||
|
"<span class=\"nickname fn\">"+user['screen_name']+"</span>"+
|
||||||
|
"</a>"+
|
||||||
|
"</span>"+
|
||||||
|
"<p class=\"entry-content\">"+html+"</p>"+
|
||||||
|
"</div>"+
|
||||||
|
"<div class=\"entry-content\">"+
|
||||||
|
"<dl class=\"timestamp\">"+
|
||||||
|
"<dt>Published</dt>"+
|
||||||
|
"<dd>"+
|
||||||
|
"<a rel=\"bookmark\" href=\""+data['url']+"\" >"+
|
||||||
|
"<abbr class=\"published\" title=\""+data['created_at']+"\">a few seconds ago</abbr>"+
|
||||||
|
"</a> "+
|
||||||
|
"</dd>"+
|
||||||
|
"</dl>"+
|
||||||
|
"<dl class=\"device\">"+
|
||||||
|
"<dt>From</dt> "+
|
||||||
|
"<dd>"+source+"</dd>"+ // may have a link, I think
|
||||||
|
"</dl>";
|
||||||
|
|
||||||
|
if (data['in_reply_to_status_id']) {
|
||||||
|
ni = ni+" <dl class=\"response\">"+
|
||||||
|
"<dt>To</dt>"+
|
||||||
|
"<dd>"+
|
||||||
|
"<a href=\""+data['in_reply_to_status_url']+"\" rel=\"in-reply-to\">in reply to</a>"+
|
||||||
|
"</dd>"+
|
||||||
|
"</dl>";
|
||||||
|
}
|
||||||
|
|
||||||
|
ni = ni+"</div>"+
|
||||||
|
"<div class=\"notice-options\">";
|
||||||
|
|
||||||
|
if (_userid != 0) {
|
||||||
|
var input = $("form#form_notice fieldset input#token");
|
||||||
|
var session_key = input.val();
|
||||||
|
ni = ni+makeFavoriteForm(data['id'], session_key);
|
||||||
|
ni = ni+makeReplyLink(data['id'], data['user']['screen_name']);
|
||||||
|
if (_userid == data['user']['id']) {
|
||||||
|
ni = ni+makeDeleteLink(data['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ni = ni+"</div>"+
|
||||||
|
"</li>";
|
||||||
|
return ni;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeFavoriteForm(id, session_key)
|
||||||
|
{
|
||||||
|
var ff;
|
||||||
|
|
||||||
|
ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+_favorurl+"\">"+
|
||||||
|
"<fieldset>"+
|
||||||
|
"<legend>Favor this notice</legend>"+ // XXX: i18n
|
||||||
|
"<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
|
||||||
|
"<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
|
||||||
|
"<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
|
||||||
|
"</fieldset>"+
|
||||||
|
"</form>";
|
||||||
|
return ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeReplyLink(id, nickname)
|
||||||
|
{
|
||||||
|
var rl;
|
||||||
|
rl = "<dl class=\"notice_reply\">"+
|
||||||
|
"<dt>Reply to this notice</dt>"+
|
||||||
|
"<dd>"+
|
||||||
|
"<a href=\""+_replyurl+"?replyto="+nickname+"\" title=\"Reply to this notice\">Reply <span class=\"notice_id\">"+id+"</span>"+
|
||||||
|
"</a>"+
|
||||||
|
"</dd>"+
|
||||||
|
"</dl>";
|
||||||
|
return rl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeDeleteLink(id)
|
||||||
|
{
|
||||||
|
var dl, delurl;
|
||||||
|
delurl = _deleteurl.replace("0000000000", id);
|
||||||
|
|
||||||
|
dl = "<dl class=\"notice_delete\">"+
|
||||||
|
"<dt>Delete this notice</dt>"+
|
||||||
|
"<dd>"+
|
||||||
|
"<a href=\""+delurl+"\" title=\"Delete this notice\">Delete</a>"+
|
||||||
|
"</dd>"+
|
||||||
|
"</dl>";
|
||||||
|
|
||||||
|
return dl;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user