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
|
||||
.#*
|
||||
*.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
|
||||
- $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
|
||||
- $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
|
||||
'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
|
||||
--------
|
||||
|
||||
|
@ -59,7 +59,7 @@ class AccesstokenAction extends Action
|
||||
try {
|
||||
common_debug('getting request from env variables', __FILE__);
|
||||
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__);
|
||||
$server = omb_oauth_server();
|
||||
common_debug('fetching the access token', __FILE__);
|
||||
|
@ -93,7 +93,7 @@ class AllAction extends ProfileAction
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
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 {
|
||||
$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',
|
||||
'statuses/replies',
|
||||
'statuses/mentions',
|
||||
'statuses/followers',
|
||||
'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/
|
||||
*
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
@ -31,7 +31,7 @@ if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once(INSTALLDIR.'/lib/noticelist.php');
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
|
||||
/**
|
||||
* Conversation tree in the browser
|
||||
@ -42,9 +42,10 @@ require_once(INSTALLDIR.'/lib/noticelist.php');
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class ConversationAction extends Action
|
||||
{
|
||||
var $id = null;
|
||||
var $id = null;
|
||||
var $page = null;
|
||||
|
||||
/**
|
||||
@ -69,24 +70,47 @@ class ConversationAction extends Action
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the action
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page title
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
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()
|
||||
{
|
||||
// FIXME this needs to be a tree, not a list
|
||||
|
||||
$qry = 'SELECT * FROM notice WHERE conversation = %s ';
|
||||
|
||||
$offset = ($this->page-1)*NOTICES_PER_PAGE;
|
||||
$offset = ($this->page-1) * NOTICES_PER_PAGE;
|
||||
$limit = NOTICES_PER_PAGE + 1;
|
||||
|
||||
$txt = sprintf($qry, $this->id);
|
||||
@ -95,9 +119,9 @@ class ConversationAction extends Action
|
||||
'notice:conversation:'.$this->id,
|
||||
$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->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('notice', $this->trimmed('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-secondary', 'no');
|
||||
$this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not delete this notice"));
|
||||
$this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Delete this notice'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
@ -76,14 +76,22 @@ class DesignsettingsAction extends AccountSettingsAction
|
||||
'action' =>
|
||||
common_local_url('designsettings')));
|
||||
$this->elementStart('fieldset');
|
||||
// $this->element('legend', null, _('Design settings'));
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
$this->elementStart('fieldset', array('id' => 'settings_design_background-image'));
|
||||
$this->element('legend', null, _('Change background image'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$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('ul');
|
||||
$this->elementEnd('fieldset');
|
||||
@ -91,28 +99,59 @@ class DesignsettingsAction extends AccountSettingsAction
|
||||
$this->elementStart('fieldset', array('id' => 'settings_design_color'));
|
||||
$this->element('legend', null, _('Change colours'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('color-1', _('Background color'), '#F0F2F5', null);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('color-2', _('Content background color'), '#FFFFFF', null);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('color-3', _('Sidebar background color'), '#CEE1E9', null);
|
||||
$this->elementEnd('li');
|
||||
$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 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->element('label', array('for' => 'swatch-'.$s), _($labelSwatch[$s]));
|
||||
$this->element('input', array('name' => 'swatch-'.$s, //prefer swatch[$s] ?
|
||||
'type' => 'text',
|
||||
'id' => 'swatch-'.$s,
|
||||
'class' => 'swatch',
|
||||
'maxlength' => '7',
|
||||
'size' => '7',
|
||||
'value' => $foo[0]));
|
||||
$this->elementEnd('li');
|
||||
$s++;
|
||||
}
|
||||
|
||||
$this->elementEnd('ul');
|
||||
$this->element('div', array('id' => 'color-picker'));
|
||||
$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('form');
|
||||
|
||||
@ -187,7 +226,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
||||
|
||||
|
||||
/**
|
||||
* Add the jCrop stylesheet
|
||||
* Add the Farbtastic stylesheet
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -205,7 +244,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the jCrop scripts
|
||||
* Add the Farbtastic scripts
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -214,14 +253,12 @@ class DesignsettingsAction extends AccountSettingsAction
|
||||
{
|
||||
parent::showScripts();
|
||||
|
||||
// if ($this->mode == 'crop') {
|
||||
$farbtasticPack = common_path('js/farbtastic/farbtastic.js');
|
||||
$farbtasticGo = common_path('js/farbtastic/farbtastic.go.js');
|
||||
$farbtasticPack = common_path('js/farbtastic/farbtastic.js');
|
||||
$farbtasticGo = common_path('js/farbtastic/farbtastic.go.js');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $farbtasticPack));
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $farbtasticGo));
|
||||
// }
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $farbtasticPack));
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $farbtasticGo));
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ class FavoritesrssAction extends Rss10Action
|
||||
$c = array('url' => common_local_url('favoritesrss',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
'title' => sprintf(_("%s favorite notices"), $user->nickname),
|
||||
'title' => sprintf(_("%s's favorite notices"), $user->nickname),
|
||||
'link' => common_local_url('showfavorites',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
|
@ -191,11 +191,28 @@ class FinishopenidloginAction extends Action
|
||||
{
|
||||
# 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.'));
|
||||
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');
|
||||
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
@ -257,10 +274,16 @@ class FinishopenidloginAction extends Action
|
||||
# XXX: add language
|
||||
# XXX: add timezone
|
||||
|
||||
$user = User::register(array('nickname' => $nickname,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'location' => $location));
|
||||
$args = array('nickname' => $nickname,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'location' => $location);
|
||||
|
||||
if (!empty($invite)) {
|
||||
$args['code'] = $invite->code;
|
||||
}
|
||||
|
||||
$user = User::register($args);
|
||||
|
||||
$result = oid_link_user($user->id, $canonical, $display);
|
||||
|
||||
|
@ -34,7 +34,7 @@ if (!defined('LACONICA')) {
|
||||
|
||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
|
||||
define('MEMBERS_PER_SECTION', 81);
|
||||
define('MEMBERS_PER_SECTION', 27);
|
||||
|
||||
/**
|
||||
* Group RSS feed
|
||||
|
@ -70,10 +70,20 @@ class LogoutAction extends Action
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('Not logged in.'));
|
||||
} else {
|
||||
common_set_user(null);
|
||||
common_real_login(false); // not logged in
|
||||
common_forgetme(); // don't log back in!
|
||||
if (Event::handle('StartLogout', array($this))) {
|
||||
$this->logout();
|
||||
}
|
||||
Event::handle('EndLogout', array($this));
|
||||
|
||||
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);
|
||||
|
||||
$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)
|
||||
{
|
||||
$this->msg = $msg;
|
||||
if ($msg && $this->boolean('ajax')) {
|
||||
$this->ajaxErrorMsg($msg);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->msg = $msg;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,8 @@ class NewnoticeAction extends Action
|
||||
$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);
|
||||
|
||||
if (is_string($notice)) {
|
||||
@ -166,6 +167,8 @@ class NewnoticeAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$this->saveUrls($notice);
|
||||
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
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
|
||||
*
|
||||
|
@ -67,8 +67,8 @@ class OpenidsettingsAction extends AccountSettingsAction
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('[OpenID](%%doc.openid%%) lets you log into many sites ' .
|
||||
' with the same user account. '.
|
||||
return _('[OpenID](%%doc.openid%%) lets you log into many sites' .
|
||||
' with the same user account.'.
|
||||
' Manage your associated OpenIDs from here.');
|
||||
}
|
||||
|
||||
|
@ -91,67 +91,68 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
$this->element('legend', null, _('Profile information'));
|
||||
$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('li');
|
||||
$this->input('nickname', _('Nickname'),
|
||||
($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname,
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('fullname', _('Full name'),
|
||||
($this->arg('fullname')) ? $this->arg('fullname') : $profile->fullname);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('homepage', _('Homepage'),
|
||||
($this->arg('homepage')) ? $this->arg('homepage') : $profile->homepage,
|
||||
_('URL of your homepage, blog, or profile on another site'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->textarea('bio', _('Bio'),
|
||||
($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
|
||||
_('Describe yourself and your interests in 140 chars'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('location', _('Location'),
|
||||
($this->arg('location')) ? $this->arg('location') : $profile->location,
|
||||
_('Where you are, like "City, State (or Region), Country"'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('tags', _('Tags'),
|
||||
($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
|
||||
_('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$language = common_language();
|
||||
$this->dropdown('language', _('Language'),
|
||||
get_nice_language_list(), _('Preferred language'),
|
||||
true, $language);
|
||||
$this->elementEnd('li');
|
||||
$timezone = common_timezone();
|
||||
$timezones = array();
|
||||
foreach(DateTimeZone::listIdentifiers() as $k => $v) {
|
||||
$timezones[$v] = $v;
|
||||
if (Event::handle('StartProfileFormData', array($this))) {
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Nickname'),
|
||||
($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname,
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('fullname', _('Full name'),
|
||||
($this->arg('fullname')) ? $this->arg('fullname') : $profile->fullname);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('homepage', _('Homepage'),
|
||||
($this->arg('homepage')) ? $this->arg('homepage') : $profile->homepage,
|
||||
_('URL of your homepage, blog, or profile on another site'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->textarea('bio', _('Bio'),
|
||||
($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
|
||||
_('Describe yourself and your interests in 140 chars'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('location', _('Location'),
|
||||
($this->arg('location')) ? $this->arg('location') : $profile->location,
|
||||
_('Where you are, like "City, State (or Region), Country"'));
|
||||
$this->elementEnd('li');
|
||||
Event::handle('EndProfileFormData', array($this));
|
||||
$this->elementStart('li');
|
||||
$this->input('tags', _('Tags'),
|
||||
($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
|
||||
_('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$language = common_language();
|
||||
$this->dropdown('language', _('Language'),
|
||||
get_nice_language_list(), _('Preferred language'),
|
||||
false, $language);
|
||||
$this->elementEnd('li');
|
||||
$timezone = common_timezone();
|
||||
$timezones = array();
|
||||
foreach(DateTimeZone::listIdentifiers() as $k => $v) {
|
||||
$timezones[$v] = $v;
|
||||
}
|
||||
$this->elementStart('li');
|
||||
$this->dropdown('timezone', _('Timezone'),
|
||||
$timezones, _('What timezone are you normally in?'),
|
||||
true, $timezone);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('autosubscribe',
|
||||
_('Automatically subscribe to whoever '.
|
||||
'subscribes to me (best for non-humans)'),
|
||||
($this->arg('autosubscribe')) ?
|
||||
$this->boolean('autosubscribe') : $user->autosubscribe);
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementStart('li');
|
||||
$this->dropdown('timezone', _('Timezone'),
|
||||
$timezones, _('What timezone are you normally in?'),
|
||||
true, $timezone);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('autosubscribe',
|
||||
_('Automatically subscribe to whoever '.
|
||||
'subscribes to me (best for non-humans)'),
|
||||
($this->arg('autosubscribe')) ?
|
||||
$this->boolean('autosubscribe') : $user->autosubscribe);
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('save', _('Save'));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,158 +166,158 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
# CSRF protection
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$bio = $this->trimmed('bio');
|
||||
$location = $this->trimmed('location');
|
||||
$autosubscribe = $this->boolean('autosubscribe');
|
||||
$language = $this->trimmed('language');
|
||||
$timezone = $this->trimmed('timezone');
|
||||
$tagstring = $this->trimmed('tags');
|
||||
if (Event::handle('StartProfileSaveForm', array($this))) {
|
||||
|
||||
# Some validation
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$bio = $this->trimmed('bio');
|
||||
$location = $this->trimmed('location');
|
||||
$autosubscribe = $this->boolean('autosubscribe');
|
||||
$language = $this->trimmed('language');
|
||||
$timezone = $this->trimmed('timezone');
|
||||
$tagstring = $this->trimmed('tags');
|
||||
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||
return;
|
||||
} else if (!User::allowed_nickname($nickname)) {
|
||||
$this->showForm(_('Not a valid nickname.'));
|
||||
return;
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!Validate::uri($homepage, array('allowed_schemes' => array('http', 'https')))) {
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
$this->showForm(_('Full name is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (!is_null($bio) && mb_strlen($bio) > 140) {
|
||||
$this->showForm(_('Bio is too long (max 140 chars).'));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
$this->showForm(_('Location is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) {
|
||||
$this->showForm(_('Timezone not selected.'));
|
||||
return;
|
||||
} else if ($this->nicknameExists($nickname)) {
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
return;
|
||||
} else if (!is_null($language) && strlen($language) > 50) {
|
||||
$this->showForm(_('Language is too long (max 50 chars).'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($tagstring) {
|
||||
$tags = array_map('common_canonical_tag', preg_split('/[\s,]+/', $tagstring));
|
||||
} else {
|
||||
$tags = array();
|
||||
}
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
if (!common_valid_profile_tag($tag)) {
|
||||
$this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
|
||||
// Some validation
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||
return;
|
||||
} else if (!User::allowed_nickname($nickname)) {
|
||||
$this->showForm(_('Not a valid nickname.'));
|
||||
return;
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!Validate::uri($homepage, array('allowed_schemes' => array('http', 'https')))) {
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
$this->showForm(_('Full name is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (!is_null($bio) && mb_strlen($bio) > 140) {
|
||||
$this->showForm(_('Bio is too long (max 140 chars).'));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
$this->showForm(_('Location is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) {
|
||||
$this->showForm(_('Timezone not selected.'));
|
||||
return;
|
||||
} else if ($this->nicknameExists($nickname)) {
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
return;
|
||||
} else if (!is_null($language) && strlen($language) > 50) {
|
||||
$this->showForm(_('Language is too long (max 50 chars).'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
$user->query('BEGIN');
|
||||
|
||||
if ($user->nickname != $nickname ||
|
||||
$user->language != $language ||
|
||||
$user->timezone != $timezone) {
|
||||
|
||||
common_debug('Updating user nickname from ' . $user->nickname . ' to ' . $nickname,
|
||||
__FILE__);
|
||||
common_debug('Updating user language from ' . $user->language . ' to ' . $language,
|
||||
__FILE__);
|
||||
common_debug('Updating user timezone from ' . $user->timezone . ' to ' . $timezone,
|
||||
__FILE__);
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
$user->nickname = $nickname;
|
||||
$user->language = $language;
|
||||
$user->timezone = $timezone;
|
||||
|
||||
$result = $user->updateKeys($original);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Couldn\'t update user.'));
|
||||
return;
|
||||
if ($tagstring) {
|
||||
$tags = array_map('common_canonical_tag', preg_split('/[\s,]+/', $tagstring));
|
||||
} else {
|
||||
# Re-initialize language environment if it changed
|
||||
common_init_language();
|
||||
$tags = array();
|
||||
}
|
||||
}
|
||||
|
||||
# XXX: XOR
|
||||
foreach ($tags as $tag) {
|
||||
if (!common_valid_profile_tag($tag)) {
|
||||
$this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($user->autosubscribe ^ $autosubscribe) {
|
||||
$user = common_current_user();
|
||||
|
||||
$original = clone($user);
|
||||
$user->query('BEGIN');
|
||||
|
||||
$user->autosubscribe = $autosubscribe;
|
||||
if ($user->nickname != $nickname ||
|
||||
$user->language != $language ||
|
||||
$user->timezone != $timezone) {
|
||||
|
||||
$result = $user->update($original);
|
||||
common_debug('Updating user nickname from ' . $user->nickname . ' to ' . $nickname,
|
||||
__FILE__);
|
||||
common_debug('Updating user language from ' . $user->language . ' to ' . $language,
|
||||
__FILE__);
|
||||
common_debug('Updating user timezone from ' . $user->timezone . ' to ' . $timezone,
|
||||
__FILE__);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Couldn\'t update user for autosubscribe.'));
|
||||
$original = clone($user);
|
||||
|
||||
$user->nickname = $nickname;
|
||||
$user->language = $language;
|
||||
$user->timezone = $timezone;
|
||||
|
||||
$result = $user->updateKeys($original);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Couldn\'t update user.'));
|
||||
return;
|
||||
} else {
|
||||
// Re-initialize language environment if it changed
|
||||
common_init_language();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: XOR
|
||||
if ($user->autosubscribe ^ $autosubscribe) {
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
$user->autosubscribe = $autosubscribe;
|
||||
|
||||
$result = $user->update($original);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Couldn\'t update user for autosubscribe.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$orig_profile = clone($profile);
|
||||
|
||||
$profile->nickname = $user->nickname;
|
||||
$profile->fullname = $fullname;
|
||||
$profile->homepage = $homepage;
|
||||
$profile->bio = $bio;
|
||||
$profile->location = $location;
|
||||
$profile->profileurl = common_profile_url($nickname);
|
||||
|
||||
common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__);
|
||||
common_debug('New profile: ' . common_log_objstring($profile), __FILE__);
|
||||
|
||||
$result = $profile->update($orig_profile);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($profile, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Couldn\'t save profile.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the user tags
|
||||
$result = $user->setSelfTags($tags);
|
||||
|
||||
if (!$result) {
|
||||
$this->serverError(_('Couldn\'t save tags.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user->query('COMMIT');
|
||||
Event::handle('EndProfileSaveForm', array($this));
|
||||
common_broadcast_profile($profile);
|
||||
|
||||
$this->showForm(_('Settings saved.'), true);
|
||||
|
||||
}
|
||||
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$orig_profile = clone($profile);
|
||||
|
||||
$profile->nickname = $user->nickname;
|
||||
$profile->fullname = $fullname;
|
||||
$profile->homepage = $homepage;
|
||||
$profile->bio = $bio;
|
||||
$profile->location = $location;
|
||||
$profile->profileurl = common_profile_url($nickname);
|
||||
|
||||
common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__);
|
||||
common_debug('New profile: ' . common_log_objstring($profile), __FILE__);
|
||||
|
||||
$result = $profile->update($orig_profile);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($profile, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Couldn\'t save profile.'));
|
||||
return;
|
||||
}
|
||||
|
||||
# Set the user tags
|
||||
|
||||
$result = $user->setSelfTags($tags);
|
||||
|
||||
if (!$result) {
|
||||
$this->serverError(_('Couldn\'t save tags.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user->query('COMMIT');
|
||||
|
||||
common_broadcast_profile($profile);
|
||||
|
||||
$this->showForm(_('Settings saved.'), true);
|
||||
}
|
||||
|
||||
function nicknameExists($nickname)
|
||||
|
@ -151,11 +151,11 @@ class RecoverpasswordAction extends Action
|
||||
$this->element('p', null,
|
||||
_('If you\'ve forgotten or lost your' .
|
||||
' password, you can get a new one sent to' .
|
||||
' the email address you have stored ' .
|
||||
' the email address you have stored' .
|
||||
' in your account.'));
|
||||
} else if ($this->mode == 'reset') {
|
||||
$this->element('p', null,
|
||||
_('You\'ve been identified. Enter a ' .
|
||||
_('You\'ve been identified. Enter a' .
|
||||
' new password below. '));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
|
@ -55,6 +55,45 @@ class RegisterAction extends Action
|
||||
|
||||
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
|
||||
*
|
||||
@ -108,109 +147,109 @@ class RegisterAction extends Action
|
||||
|
||||
function tryRegister()
|
||||
{
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
if (Event::handle('StartRegistrationTry', array($this))) {
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$email = $this->trimmed('email');
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$bio = $this->trimmed('bio');
|
||||
$location = $this->trimmed('location');
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$email = $this->trimmed('email');
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$bio = $this->trimmed('bio');
|
||||
$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');
|
||||
$confirm = $this->arg('confirm');
|
||||
|
||||
$password = $this->arg('password');
|
||||
$confirm = $this->arg('confirm');
|
||||
// invitation code, if any
|
||||
$code = $this->trimmed('code');
|
||||
|
||||
// invitation code, if any
|
||||
if ($code) {
|
||||
$invite = Invitation::staticGet($code);
|
||||
}
|
||||
|
||||
$code = $this->trimmed('code');
|
||||
if (common_config('site', 'inviteonly') && !($code && $invite)) {
|
||||
$this->clientError(_('Sorry, only invited people can register.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$invite = null;
|
||||
// Input scrubbing
|
||||
$nickname = common_canonical_nickname($nickname);
|
||||
$email = common_canonical_email($email);
|
||||
|
||||
if ($code) {
|
||||
$invite = Invitation::staticGet($code);
|
||||
}
|
||||
if (!$this->boolean('license')) {
|
||||
$this->showForm(_('You can\'t register if you don\'t '.
|
||||
'agree to the license.'));
|
||||
} else if ($email && !Validate::email($email, true)) {
|
||||
$this->showForm(_('Not a valid email address.'));
|
||||
} else if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => NICKNAME_FMT))) {
|
||||
$this->showForm(_('Nickname must have only lowercase letters '.
|
||||
'and numbers and no spaces.'));
|
||||
} else if ($this->nicknameExists($nickname)) {
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
} else if (!User::allowed_nickname($nickname)) {
|
||||
$this->showForm(_('Not a valid nickname.'));
|
||||
} else if ($this->emailExists($email)) {
|
||||
$this->showForm(_('Email address already exists.'));
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!Validate::uri($homepage,
|
||||
array('allowed_schemes' =>
|
||||
array('http', 'https')))) {
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
$this->showForm(_('Full name is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (!is_null($bio) && mb_strlen($bio) > 140) {
|
||||
$this->showForm(_('Bio is too long (max 140 chars).'));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
$this->showForm(_('Location is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (strlen($password) < 6) {
|
||||
$this->showForm(_('Password must be 6 or more characters.'));
|
||||
return;
|
||||
} else if ($password != $confirm) {
|
||||
$this->showForm(_('Passwords don\'t match.'));
|
||||
} else if ($user = User::register(array('nickname' => $nickname,
|
||||
'password' => $password,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'bio' => $bio,
|
||||
'location' => $location,
|
||||
'code' => $code))) {
|
||||
if (!$user) {
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
return;
|
||||
}
|
||||
// success!
|
||||
if (!common_set_user($user)) {
|
||||
$this->serverError(_('Error setting user.'));
|
||||
return;
|
||||
}
|
||||
// this is a real login
|
||||
common_real_login(true);
|
||||
if ($this->boolean('rememberme')) {
|
||||
common_debug('Adding rememberme cookie for ' . $nickname);
|
||||
common_rememberme($user);
|
||||
}
|
||||
|
||||
if (common_config('site', 'inviteonly') && !($code && !empty($invite))) {
|
||||
$this->clientError(_('Sorry, only invited people can register.'));
|
||||
return;
|
||||
}
|
||||
Event::handle('EndRegistrationTry', array($this));
|
||||
|
||||
// Input scrubbing
|
||||
|
||||
$nickname = common_canonical_nickname($nickname);
|
||||
$email = common_canonical_email($email);
|
||||
|
||||
if (!$this->boolean('license')) {
|
||||
$this->showForm(_('You can\'t register if you don\'t '.
|
||||
'agree to the license.'));
|
||||
} else if ($email && !Validate::email($email, true)) {
|
||||
$this->showForm(_('Not a valid email address.'));
|
||||
} else if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => NICKNAME_FMT))) {
|
||||
$this->showForm(_('Nickname must have only lowercase letters '.
|
||||
'and numbers and no spaces.'));
|
||||
} else if ($this->nicknameExists($nickname)) {
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
} else if (!User::allowed_nickname($nickname)) {
|
||||
$this->showForm(_('Not a valid nickname.'));
|
||||
} else if ($this->emailExists($email)) {
|
||||
$this->showForm(_('Email address already exists.'));
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!Validate::uri($homepage,
|
||||
array('allowed_schemes' =>
|
||||
array('http', 'https')))) {
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
$this->showForm(_('Full name is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (!is_null($bio) && mb_strlen($bio) > 140) {
|
||||
$this->showForm(_('Bio is too long (max 140 chars).'));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
$this->showForm(_('Location is too long (max 255 chars).'));
|
||||
return;
|
||||
} else if (strlen($password) < 6) {
|
||||
$this->showForm(_('Password must be 6 or more characters.'));
|
||||
return;
|
||||
} else if ($password != $confirm) {
|
||||
$this->showForm(_('Passwords don\'t match.'));
|
||||
} else if ($user = User::register(array('nickname' => $nickname,
|
||||
'password' => $password,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'bio' => $bio,
|
||||
'location' => $location,
|
||||
'code' => $code))) {
|
||||
if (!$user) {
|
||||
// Re-init language env in case it changed (not yet, but soon)
|
||||
common_init_language();
|
||||
$this->showSuccess();
|
||||
} else {
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
return;
|
||||
}
|
||||
// success!
|
||||
if (!common_set_user($user)) {
|
||||
$this->serverError(_('Error setting user.'));
|
||||
return;
|
||||
}
|
||||
// this is a real login
|
||||
common_real_login(true);
|
||||
if ($this->boolean('rememberme')) {
|
||||
common_debug('Adding rememberme cookie for ' . $nickname);
|
||||
common_rememberme($user);
|
||||
}
|
||||
// Re-init language env in case it changed (not yet, but soon)
|
||||
common_init_language();
|
||||
$this->showSuccess();
|
||||
} else {
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,22 +291,24 @@ class RegisterAction extends Action
|
||||
|
||||
// overrrided to add entry-title class
|
||||
function showPageTitle() {
|
||||
$this->element('h1', array('class' => 'entry-title'), $this->title());
|
||||
if (Event::handle('StartShowPageTitle', array($this))) {
|
||||
$this->element('h1', array('class' => 'entry-title'), $this->title());
|
||||
}
|
||||
}
|
||||
|
||||
// overrided to add hentry, and content-inner class
|
||||
function showContentBlock()
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
|
||||
$this->showPageTitle();
|
||||
$this->showPageNoticeBlock();
|
||||
$this->elementStart('div', array('id' => 'content_inner',
|
||||
'class' => 'entry-content'));
|
||||
// show the actual content (forms, lists, whatever)
|
||||
$this->showContent();
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
|
||||
$this->showPageTitle();
|
||||
$this->showPageNoticeBlock();
|
||||
$this->elementStart('div', array('id' => 'content_inner',
|
||||
'class' => 'entry-content'));
|
||||
// show the actual content (forms, lists, whatever)
|
||||
$this->showContent();
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions or a notice for the page
|
||||
@ -362,82 +403,85 @@ class RegisterAction extends Action
|
||||
$this->element('legend', null, 'Account settings');
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
if ($code) {
|
||||
$this->hidden('code', $code);
|
||||
if ($this->code) {
|
||||
$this->hidden('code', $this->code);
|
||||
}
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Nickname'), $this->trimmed('nickname'),
|
||||
_('1-64 lowercase letters or numbers, '.
|
||||
'no punctuation or spaces. Required.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('password', _('Password'),
|
||||
_('6 or more characters. Required.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('confirm', _('Confirm'),
|
||||
_('Same as password above. Required.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
if (!empty($invite) && $invite->address_type == 'email') {
|
||||
$this->input('email', _('Email'), $invite->address,
|
||||
_('Used only for updates, announcements, '.
|
||||
'and password recovery'));
|
||||
} else {
|
||||
$this->input('email', _('Email'), $this->trimmed('email'),
|
||||
_('Used only for updates, announcements, '.
|
||||
'and password recovery'));
|
||||
if (Event::handle('StartRegistrationFormData', array($this))) {
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Nickname'), $this->trimmed('nickname'),
|
||||
_('1-64 lowercase letters or numbers, '.
|
||||
'no punctuation or spaces. Required.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('password', _('Password'),
|
||||
_('6 or more characters. Required.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('confirm', _('Confirm'),
|
||||
_('Same as password above. Required.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
if ($this->invite && $this->invite->address_type == 'email') {
|
||||
$this->input('email', _('Email'), $this->invite->address,
|
||||
_('Used only for updates, announcements, '.
|
||||
'and password recovery'));
|
||||
} else {
|
||||
$this->input('email', _('Email'), $this->trimmed('email'),
|
||||
_('Used only for updates, announcements, '.
|
||||
'and password recovery'));
|
||||
}
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('fullname', _('Full name'),
|
||||
$this->trimmed('fullname'),
|
||||
_('Longer name, preferably your "real" name'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('homepage', _('Homepage'),
|
||||
$this->trimmed('homepage'),
|
||||
_('URL of your homepage, blog, '.
|
||||
'or profile on another site'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->textarea('bio', _('Bio'),
|
||||
$this->trimmed('bio'),
|
||||
_('Describe yourself and your '.
|
||||
'interests in 140 chars'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('location', _('Location'),
|
||||
$this->trimmed('location'),
|
||||
_('Where you are, like "City, '.
|
||||
'State (or Region), Country"'));
|
||||
$this->elementEnd('li');
|
||||
Event::handle('EndRegistrationFormData', array($this));
|
||||
$this->elementStart('li', array('id' => 'settings_rememberme'));
|
||||
$this->checkbox('rememberme', _('Remember me'),
|
||||
$this->boolean('rememberme'),
|
||||
_('Automatically login in the future; '.
|
||||
'not for shared computers!'));
|
||||
$this->elementEnd('li');
|
||||
$attrs = array('type' => 'checkbox',
|
||||
'id' => 'license',
|
||||
'class' => 'checkbox',
|
||||
'name' => 'license',
|
||||
'value' => 'true');
|
||||
if ($this->boolean('license')) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
$this->elementStart('li');
|
||||
$this->element('input', $attrs);
|
||||
$this->elementStart('label', array('class' => 'checkbox', 'for' => 'license'));
|
||||
$this->text(_('My text and files are available under '));
|
||||
$this->element('a', array('href' => common_config('license', 'url')),
|
||||
common_config('license', 'title'), _("Creative Commons Attribution 3.0"));
|
||||
$this->text(_(' except this private data: password, '.
|
||||
'email address, IM address, and phone number.'));
|
||||
$this->elementEnd('label');
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('fullname', _('Full name'),
|
||||
$this->trimmed('fullname'),
|
||||
_('Longer name, preferably your "real" name'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('homepage', _('Homepage'),
|
||||
$this->trimmed('homepage'),
|
||||
_('URL of your homepage, blog, '.
|
||||
'or profile on another site'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->textarea('bio', _('Bio'),
|
||||
$this->trimmed('bio'),
|
||||
_('Describe yourself and your '.
|
||||
'interests in 140 chars'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('location', _('Location'),
|
||||
$this->trimmed('location'),
|
||||
_('Where you are, like "City, '.
|
||||
'State (or Region), Country"'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li', array('id' => 'settings_rememberme'));
|
||||
$this->checkbox('rememberme', _('Remember me'),
|
||||
$this->boolean('rememberme'),
|
||||
_('Automatically login in the future; '.
|
||||
'not for shared computers!'));
|
||||
$this->elementEnd('li');
|
||||
$attrs = array('type' => 'checkbox',
|
||||
'id' => 'license',
|
||||
'class' => 'checkbox',
|
||||
'name' => 'license',
|
||||
'value' => 'true');
|
||||
if ($this->boolean('license')) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
$this->elementStart('li');
|
||||
$this->element('input', $attrs);
|
||||
$this->elementStart('label', array('class' => 'checkbox', 'for' => 'license'));
|
||||
$this->text(_('My text and files are available under '));
|
||||
$this->element('a', array('href' => common_config('license', 'url')),
|
||||
common_config('license', 'title'), _("Creative Commons Attribution 3.0"));
|
||||
$this->text(_(' except this private data: password, '.
|
||||
'email address, IM address, and phone number.'));
|
||||
$this->elementEnd('label');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('submit', _('Register'));
|
||||
$this->elementEnd('fieldset');
|
||||
@ -519,3 +563,4 @@ class RegisterAction extends Action
|
||||
$nav->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,9 +74,9 @@ class ShowfavoritesAction extends Action
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
return sprintf(_("%s favorite notices"), $this->user->nickname);
|
||||
return sprintf(_("%s's favorite notices"), $this->user->nickname);
|
||||
} else {
|
||||
return sprintf(_("%s favorite notices, page %d"),
|
||||
return sprintf(_("%s's favorite notices, page %d"),
|
||||
$this->user->nickname,
|
||||
$this->page);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ if (!defined('LACONICA')) {
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
|
||||
define('MEMBERS_PER_SECTION', 81);
|
||||
define('MEMBERS_PER_SECTION', 27);
|
||||
|
||||
/**
|
||||
* Group main page
|
||||
@ -361,7 +361,7 @@ class ShowgroupAction extends Action
|
||||
$this->element('p', null, _('(None)'));
|
||||
}
|
||||
|
||||
if ($cnt == MEMBERS_PER_SECTION) {
|
||||
if ($cnt > MEMBERS_PER_SECTION) {
|
||||
$this->element('a', array('href' => common_local_url('groupmembers',
|
||||
array('nickname' => $this->group->nickname))),
|
||||
_('All members'));
|
||||
|
@ -68,6 +68,9 @@ class ShowstreamAction extends ProfileAction
|
||||
} else {
|
||||
$base = $this->user->nickname;
|
||||
}
|
||||
if (!empty($this->tag)) {
|
||||
$base .= sprintf(_(' tagged %s'), $this->tag);
|
||||
}
|
||||
|
||||
if ($this->page == 1) {
|
||||
return $base;
|
||||
@ -110,6 +113,15 @@ class ShowstreamAction extends ProfileAction
|
||||
|
||||
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,
|
||||
common_local_url('userrss',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
@ -363,7 +375,9 @@ class ShowstreamAction extends ProfileAction
|
||||
|
||||
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);
|
||||
$cnt = $pnl->show();
|
||||
|
@ -118,6 +118,16 @@ class SubscribersAction extends GalleryAction
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
parent::showSections();
|
||||
$cloud = new SubscribersPeopleTagCloudSection($this);
|
||||
$cloud->show();
|
||||
|
||||
$cloud2 = new SubscribersPeopleSelfTagCloudSection($this);
|
||||
$cloud2->show();
|
||||
}
|
||||
}
|
||||
|
||||
class SubscribersList extends ProfileList
|
||||
|
@ -125,6 +125,16 @@ class SubscriptionsAction extends GalleryAction
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
parent::showSections();
|
||||
$cloud = new SubscriptionsPeopleTagCloudSection($this);
|
||||
$cloud->show();
|
||||
|
||||
$cloud2 = new SubscriptionsPeopleSelfTagCloudSection($this);
|
||||
$cloud2->show();
|
||||
}
|
||||
}
|
||||
|
||||
class SubscriptionsList extends ProfileList
|
||||
|
@ -49,9 +49,10 @@ class TagAction extends Action
|
||||
{
|
||||
$pop = new PopularNoticeSection($this);
|
||||
$pop->show();
|
||||
$freqatt = new FrequentAttachmentSection($this);
|
||||
$freqatt->show();
|
||||
}
|
||||
|
||||
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
|
@ -133,11 +133,7 @@ class TwitapifriendshipsAction extends TwitterapiAction
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user_a->isSubscribed($user_b)) {
|
||||
$result = 'true';
|
||||
} else {
|
||||
$result = 'false';
|
||||
}
|
||||
$result = $user_a->isSubscribed($user_b);
|
||||
|
||||
switch ($apidata['content-type']) {
|
||||
case 'xml':
|
||||
|
@ -144,10 +144,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
break;
|
||||
case 'atom':
|
||||
if (isset($apidata['api_arg'])) {
|
||||
$selfuri = $selfuri = common_root_url() .
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/friends_timeline/' . $apidata['api_arg'] . '.atom';
|
||||
} else {
|
||||
$selfuri = $selfuri = common_root_url() .
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/friends_timeline.atom';
|
||||
}
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri);
|
||||
@ -231,10 +231,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
break;
|
||||
case 'atom':
|
||||
if (isset($apidata['api_arg'])) {
|
||||
$selfuri = $selfuri = common_root_url() .
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/user_timeline/' . $apidata['api_arg'] . '.atom';
|
||||
} else {
|
||||
$selfuri = $selfuri = common_root_url() .
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/user_timeline.atom';
|
||||
}
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink, $selfuri);
|
||||
@ -344,7 +344,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$this->show($args, $apidata);
|
||||
}
|
||||
|
||||
function replies($args, $apidata)
|
||||
function mentions($args, $apidata)
|
||||
{
|
||||
|
||||
parent::handle($args);
|
||||
@ -360,11 +360,13 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$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');
|
||||
$id = "tag:$taguribase:Replies:".$user->id;
|
||||
$id = "tag:$taguribase:Mentions:".$user->id;
|
||||
$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) {
|
||||
$page = 1;
|
||||
@ -385,7 +387,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
|
||||
$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();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
@ -400,14 +403,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$this->show_rss_timeline($notices, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
if (isset($apidata['api_arg'])) {
|
||||
$selfuri = $selfuri = common_root_url() .
|
||||
'api/statuses/replies/' . $apidata['api_arg'] . '.atom';
|
||||
} else {
|
||||
$selfuri = $selfuri = common_root_url() .
|
||||
'api/statuses/replies.atom';
|
||||
}
|
||||
$this->show_atom_timeline($notices, $title, $id, $link, $subtitle, null, $selfuri);
|
||||
$selfuri = common_root_url() .
|
||||
ltrim($_SERVER['QUERY_STRING'], 'p=');
|
||||
$this->show_atom_timeline($notices, $title, $id, $link, $subtitle,
|
||||
null, $selfuri);
|
||||
break;
|
||||
case 'json':
|
||||
$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)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
@ -82,8 +82,8 @@ class TwitapiusersAction extends TwitterapiAction
|
||||
$twitter_user['profile_text_color'] = '';
|
||||
$twitter_user['profile_link_color'] = '';
|
||||
$twitter_user['profile_sidebar_fill_color'] = '';
|
||||
$twitter_user['profile_sidebar_border_color'] = '';
|
||||
$twitter_user['profile_background_tile'] = 'false';
|
||||
$twitter_user['profile_sidebar_border_color'] = '';
|
||||
$twitter_user['profile_background_tile'] = false;
|
||||
|
||||
$faves = DB_DataObject::factory('fave');
|
||||
$faves->user_id = $user->id;
|
||||
@ -103,24 +103,16 @@ class TwitapiusersAction extends TwitterapiAction
|
||||
|
||||
if (isset($apidata['user'])) {
|
||||
|
||||
if ($apidata['user']->isSubscribed($profile)) {
|
||||
$twitter_user['following'] = 'true';
|
||||
} else {
|
||||
$twitter_user['following'] = 'false';
|
||||
$twitter_user['following'] = $apidata['user']->isSubscribed($profile);
|
||||
|
||||
// Notifications on?
|
||||
$sub = Subscription::pkeyGet(array('subscriber' =>
|
||||
$apidata['user']->id, 'subscribed' => $profile->id));
|
||||
|
||||
if ($sub) {
|
||||
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
|
||||
}
|
||||
|
||||
// Notifications on?
|
||||
$sub = Subscription::pkeyGet(array('subscriber' =>
|
||||
$apidata['user']->id, 'subscribed' => $profile->id));
|
||||
|
||||
if ($sub) {
|
||||
if ($sub->jabber || $sub->sms) {
|
||||
$twitter_user['notifications'] = 'true';
|
||||
} else {
|
||||
$twitter_user['notifications'] = 'false';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($apidata['content-type'] == 'xml') {
|
||||
$this->init_document('xml');
|
||||
|
@ -138,7 +138,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('noticesync',
|
||||
$this->checkbox('noticesend',
|
||||
_('Automatically send my notices to Twitter.'),
|
||||
($flink) ?
|
||||
($flink->noticesync & FOREIGN_NOTICE_SEND) :
|
||||
@ -158,6 +158,22 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
($flink->friendsync & FOREIGN_FRIEND_RECV) :
|
||||
false);
|
||||
$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');
|
||||
|
||||
if ($flink) {
|
||||
@ -261,7 +277,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
'alt' => ($other->fullname) ?
|
||||
$other->fullname :
|
||||
$other->nickname));
|
||||
|
||||
|
||||
$this->element('span', 'fn nickname', $other->nickname);
|
||||
$this->elementEnd('a');
|
||||
$this->elementEnd('li');
|
||||
@ -320,7 +336,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
{
|
||||
$screen_name = $this->trimmed('twitter_username');
|
||||
$password = $this->trimmed('twitter_password');
|
||||
$noticesync = $this->boolean('noticesync');
|
||||
$noticesend = $this->boolean('noticesend');
|
||||
$noticerecv = $this->boolean('noticerecv');
|
||||
$replysync = $this->boolean('replysync');
|
||||
$friendsync = $this->boolean('friendsync');
|
||||
|
||||
@ -363,7 +380,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
$flink->credentials = $password;
|
||||
$flink->created = common_sql_now();
|
||||
|
||||
$flink->set_flags($noticesync, $replysync, $friendsync);
|
||||
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
|
||||
|
||||
$flink_id = $flink->insert();
|
||||
|
||||
@ -375,6 +392,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
if ($friendsync) {
|
||||
save_twitter_friends($user, $twit_user->id, $screen_name, $password);
|
||||
$flink->last_friendsync = common_sql_now();
|
||||
$flink->update();
|
||||
}
|
||||
|
||||
$this->showForm(_('Twitter settings saved.'), true);
|
||||
@ -419,7 +438,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
function savePreferences()
|
||||
{
|
||||
$noticesync = $this->boolean('noticesync');
|
||||
$noticesend = $this->boolean('noticesend');
|
||||
$noticerecv = $this->boolean('noticerecv');
|
||||
$friendsync = $this->boolean('friendsync');
|
||||
$replysync = $this->boolean('replysync');
|
||||
|
||||
@ -448,7 +468,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
$original = clone($flink);
|
||||
|
||||
$flink->set_flags($noticesync, $replysync, $friendsync);
|
||||
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
|
||||
|
||||
$result = $flink->update($original);
|
||||
|
||||
|
@ -25,14 +25,15 @@ require_once(INSTALLDIR.'/lib/rssaction.php');
|
||||
|
||||
class UserrssAction extends Rss10Action
|
||||
{
|
||||
|
||||
var $user = null;
|
||||
var $tag = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$this->user = User::staticGet('nickname', $nickname);
|
||||
$this->tag = $this->trimmed('tag');
|
||||
|
||||
if (!$this->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)
|
||||
{
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Fave extends Memcached_DataObject
|
||||
class Fave extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
@ -31,9 +31,58 @@ class Fave extends Memcached_DataObject
|
||||
}
|
||||
return $fave;
|
||||
}
|
||||
|
||||
|
||||
function &pkeyGet($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 $friendsync; // tinyint(1) not_null default_2
|
||||
public $profilesync; // tinyint(1) not_null default_1
|
||||
public $last_noticesync; // datetime()
|
||||
public $last_friendsync; // datetime()
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
@ -57,13 +59,19 @@ class Foreign_link extends Memcached_DataObject
|
||||
return null;
|
||||
}
|
||||
|
||||
function set_flags($noticesync, $replysync, $friendsync)
|
||||
function set_flags($noticesend, $noticerecv, $replysync, $friendsync)
|
||||
{
|
||||
if ($noticesync) {
|
||||
if ($noticesend) {
|
||||
$this->noticesync |= FOREIGN_NOTICE_SEND;
|
||||
} else {
|
||||
$this->noticesync &= ~FOREIGN_NOTICE_SEND;
|
||||
}
|
||||
|
||||
if ($noticerecv) {
|
||||
$this->noticesync |= FOREIGN_NOTICE_RECV;
|
||||
} else {
|
||||
$this->noticesync &= ~FOREIGN_NOTICE_RECV;
|
||||
}
|
||||
|
||||
if ($replysync) {
|
||||
$this->noticesync |= FOREIGN_NOTICE_SEND_REPLY;
|
||||
|
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);
|
||||
|
||||
$final = common_shorten_links($content);
|
||||
|
||||
if (!$profile) {
|
||||
common_log(LOG_ERR, '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.');
|
||||
}
|
||||
|
||||
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.');
|
||||
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->created = common_sql_now();
|
||||
$notice->content = $final;
|
||||
$notice->rendered = common_render_content($final, $notice);
|
||||
$notice->content = $content;
|
||||
$notice->rendered = common_render_content($content, $notice);
|
||||
$notice->source = $source;
|
||||
$notice->uri = $uri;
|
||||
|
||||
@ -206,7 +204,12 @@ class Notice extends Memcached_DataObject
|
||||
$notice->saveTags();
|
||||
$notice->saveGroups();
|
||||
|
||||
$notice->addToInboxes();
|
||||
if (common_config('queue', 'enabled')) {
|
||||
$notice->addToAuthorInbox();
|
||||
} else {
|
||||
$notice->addToInboxes();
|
||||
}
|
||||
|
||||
$notice->query('COMMIT');
|
||||
|
||||
Event::handle('EndNoticeSave', array($notice));
|
||||
@ -216,7 +219,11 @@ class Notice extends Memcached_DataObject
|
||||
# XXX: someone clever could prepend instead of clearing the cache
|
||||
|
||||
if (common_config('memcached', 'enabled')) {
|
||||
$notice->blowCaches();
|
||||
if (common_config('queue', 'enabled')) {
|
||||
$notice->blowAuthorCaches();
|
||||
} else {
|
||||
$notice->blowCaches();
|
||||
}
|
||||
}
|
||||
|
||||
return $notice;
|
||||
@ -270,6 +277,16 @@ class Notice extends Memcached_DataObject
|
||||
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)
|
||||
{
|
||||
$this->blowSubsCache($blowLast);
|
||||
@ -280,6 +297,17 @@ class Notice extends Memcached_DataObject
|
||||
$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)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
@ -288,17 +316,17 @@ class Notice extends Memcached_DataObject
|
||||
$group_inbox->notice_id = $this->id;
|
||||
if ($group_inbox->find()) {
|
||||
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) {
|
||||
$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->group_id = $group_inbox->group_id;
|
||||
if ($member->find()) {
|
||||
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) {
|
||||
$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;
|
||||
if ($tag->find()) {
|
||||
while ($tag->fetch()) {
|
||||
$cache->delete(common_cache_key('notice_tag:notice_stream:' . $tag->tag));
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('notice_tag:notice_stream:' . $tag->tag . ';last'));
|
||||
}
|
||||
$tag->blowCache($blowLast);
|
||||
}
|
||||
}
|
||||
$tag->free();
|
||||
@ -341,9 +366,9 @@ class Notice extends Memcached_DataObject
|
||||
'WHERE subscription.subscribed = ' . $this->profile_id);
|
||||
|
||||
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) {
|
||||
$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();
|
||||
@ -355,10 +380,10 @@ class Notice extends Memcached_DataObject
|
||||
{
|
||||
if ($this->is_local) {
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$cache->delete(common_cache_key('profile:notices:'.$this->profile_id));
|
||||
if (!empty($cache)) {
|
||||
$cache->delete(common_cache_key('profile:notice_ids:'.$this->profile_id));
|
||||
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;
|
||||
if ($reply->find()) {
|
||||
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) {
|
||||
$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;
|
||||
if ($fave->find()) {
|
||||
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) {
|
||||
$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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
$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')) {
|
||||
$parts[] = 'is_local = 1';
|
||||
$notice->whereAdd('is_local = 1');
|
||||
} else {
|
||||
# -1 == blacklisted
|
||||
$parts[] = 'is_local != -1';
|
||||
$notice->whereAdd('is_local != -1');
|
||||
}
|
||||
|
||||
if ($parts) {
|
||||
$qry .= ' WHERE ' . implode(' AND ', $parts);
|
||||
if ($since_id != 0) {
|
||||
$notice->whereAdd('id > ' . $since_id);
|
||||
}
|
||||
|
||||
return Notice::getStream($qry,
|
||||
'public',
|
||||
$offset, $limit, $since_id, $before_id, null, $since);
|
||||
if ($before_id != 0) {
|
||||
$notice->whereAdd('id < ' . $before_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$notice->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($notice->find()) {
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function addToInboxes()
|
||||
@ -648,6 +726,33 @@ class Notice extends Memcached_DataObject
|
||||
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()
|
||||
{
|
||||
$enabled = common_config('inboxes', 'enabled');
|
||||
@ -700,24 +805,29 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
// FIXME: do this in an offline daemon
|
||||
|
||||
$inbox = new Notice_inbox();
|
||||
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
||||
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' .
|
||||
"SELECT $UT.id, " . $this->id . ", '" . $this->created . "', 2 " .
|
||||
"FROM $UT JOIN group_member ON $UT.id = group_member.profile_id " .
|
||||
'WHERE group_member.group_id = ' . $group->id . ' ' .
|
||||
'AND NOT EXISTS (SELECT user_id, notice_id ' .
|
||||
'FROM notice_inbox ' .
|
||||
"WHERE user_id = $UT.id " .
|
||||
'AND notice_id = ' . $this->id . ' )';
|
||||
if ($enabled === 'transitional') {
|
||||
$qry .= " AND $UT.inboxed = 1";
|
||||
}
|
||||
$result = $inbox->query($qry);
|
||||
$this->addToGroupInboxes($group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addToGroupInboxes($group)
|
||||
{
|
||||
$inbox = new Notice_inbox();
|
||||
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
||||
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' .
|
||||
"SELECT $UT.id, " . $this->id . ", '" . $this->created . "', 2 " .
|
||||
"FROM $UT JOIN group_member ON $UT.id = group_member.profile_id " .
|
||||
'WHERE group_member.group_id = ' . $group->id . ' ' .
|
||||
'AND NOT EXISTS (SELECT user_id, notice_id ' .
|
||||
'FROM notice_inbox ' .
|
||||
"WHERE user_id = $UT.id " .
|
||||
'AND notice_id = ' . $this->id . ' )';
|
||||
if ($enabled === 'transitional') {
|
||||
$qry .= " AND $UT.inboxed = 1";
|
||||
}
|
||||
$result = $inbox->query($qry);
|
||||
}
|
||||
|
||||
function saveReplies()
|
||||
{
|
||||
// Alternative reply format
|
||||
@ -913,4 +1023,59 @@ class Notice extends Memcached_DataObject
|
||||
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
|
||||
/*
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
@ -21,7 +21,11 @@ if (!defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Notice_inbox extends Memcached_DataObject
|
||||
// We keep 5 pages of inbox notices in memcache, +1 for pagination check
|
||||
|
||||
define('INBOX_CACHE_WINDOW', 101);
|
||||
|
||||
class Notice_inbox extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
@ -38,4 +42,47 @@ class Notice_inbox extends Memcached_DataObject
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###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
|
||||
|
||||
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),
|
||||
'notice_tag:notice_stream:' . common_keyize($tag),
|
||||
$offset, $limit);
|
||||
$ids = Notice::stream(array('Notice_tag', '_streamDirect'),
|
||||
array($tag),
|
||||
'notice_tag:notice_ids:' . common_keyize($tag),
|
||||
$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();
|
||||
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;
|
||||
}
|
||||
|
||||
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 =
|
||||
'SELECT * ' .
|
||||
'FROM notice ' .
|
||||
'WHERE profile_id = %d ';
|
||||
// XXX: I'm not sure this is going to be any faster. It probably isn't.
|
||||
$ids = Notice::stream(array($this, '_streamTaggedDirect'),
|
||||
array(),
|
||||
'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),
|
||||
'profile:notices:'.$this->id,
|
||||
$offset, $limit, $since_id, $before_id);
|
||||
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||
{
|
||||
// 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)
|
||||
|
0
classes/Related_group.php
Executable file → Normal file
0
classes/Related_group.php
Executable file → Normal file
@ -4,7 +4,7 @@
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Reply extends Memcached_DataObject
|
||||
class Reply extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
@ -13,7 +13,7 @@ class Reply extends Memcached_DataObject
|
||||
public $notice_id; // int(4) primary_key not_null
|
||||
public $profile_id; // int(4) primary_key not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
public $replied_id; // int(4)
|
||||
public $replied_id; // int(4)
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
@ -21,4 +21,47 @@ class Reply extends Memcached_DataObject
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###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();
|
||||
|
||||
// XXX: Kind of a hack.
|
||||
|
||||
if ($cache) {
|
||||
// This is the stream of favorite notices, in rev chron
|
||||
// order. This forces it into cache.
|
||||
$faves = $this->favoriteNotices(0, NOTICE_CACHE_WINDOW);
|
||||
$cnt = 0;
|
||||
while ($faves->fetch()) {
|
||||
if ($faves->id < $notice->id) {
|
||||
// If we passed it, it's not a fave
|
||||
return false;
|
||||
} else if ($faves->id == $notice->id) {
|
||||
// If it matches a cached notice, then it's a fave
|
||||
return true;
|
||||
}
|
||||
$cnt++;
|
||||
|
||||
$ids = Fave::stream($this->id, 0, NOTICE_CACHE_WINDOW);
|
||||
|
||||
// If it's in the list, then it's a fave
|
||||
|
||||
if (in_array($notice->id, $ids)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we're not past the end of the cache window,
|
||||
// then the cache has all available faves, so this one
|
||||
// is not a fave.
|
||||
if ($cnt < NOTICE_CACHE_WINDOW) {
|
||||
|
||||
if (count($ids) < NOTICE_CACHE_WINDOW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, cache doesn't have all faves;
|
||||
// fall through to the default
|
||||
}
|
||||
|
||||
$fave = Fave::pkeyGet(array('user_id' => $this->id,
|
||||
'notice_id' => $notice->id));
|
||||
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)
|
||||
{
|
||||
$qry =
|
||||
'SELECT notice.* ' .
|
||||
'FROM notice JOIN reply ON notice.id = reply.notice_id ' .
|
||||
'WHERE reply.profile_id = %d ';
|
||||
return Notice::getStream(sprintf($qry, $this->id),
|
||||
'user:replies:'.$this->id,
|
||||
$offset, $limit, $since_id, $before_id, null, $since);
|
||||
$ids = Reply::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
|
||||
common_debug("Ids = " . implode(',', $ids));
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) {
|
||||
$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)
|
||||
@ -416,19 +422,14 @@ class User extends Memcached_DataObject
|
||||
if (!$profile) {
|
||||
return null;
|
||||
} 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)
|
||||
{
|
||||
$qry =
|
||||
'SELECT notice.* ' .
|
||||
'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);
|
||||
$ids = Fave::stream($this->id, $offset, $limit);
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
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.* ' .
|
||||
'FROM notice JOIN subscription ON notice.profile_id = subscription.subscribed ' .
|
||||
'WHERE subscription.subscriber = %d ';
|
||||
$order = null;
|
||||
return Notice::getStream(sprintf($qry, $this->id),
|
||||
'user:notices_with_friends:' . $this->id,
|
||||
$offset, $limit, $since_id, $before_id,
|
||||
$order, $since);
|
||||
} 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;
|
||||
$ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
return Notice::getStream(sprintf($qry, $this->id),
|
||||
'user:notices_with_friends:' . $this->id,
|
||||
$offset, $limit, $since_id, $before_id,
|
||||
$order, $since);
|
||||
}
|
||||
|
||||
function blowFavesCache()
|
||||
@ -467,8 +464,8 @@ class User extends Memcached_DataObject
|
||||
if ($cache) {
|
||||
// Faves don't happen chronologically, so we need to blow
|
||||
// ;last cache, too
|
||||
$cache->delete(common_cache_key('user:faves:'.$this->id));
|
||||
$cache->delete(common_cache_key('user:faves:'.$this->id).';last');
|
||||
$cache->delete(common_cache_key('fave:ids_by_user:'.$this->id));
|
||||
$cache->delete(common_cache_key('fave:ids_by_user:'.$this->id.';last'));
|
||||
}
|
||||
}
|
||||
|
||||
|
53
classes/User_group.php
Executable file → Normal file
53
classes/User_group.php
Executable file → Normal file
@ -50,13 +50,50 @@ class User_group extends Memcached_DataObject
|
||||
|
||||
function getNotices($offset, $limit)
|
||||
{
|
||||
$qry =
|
||||
'SELECT notice.* ' .
|
||||
'FROM notice JOIN group_inbox ON notice.id = group_inbox.notice_id ' .
|
||||
'WHERE group_inbox.group_id = %d ';
|
||||
return Notice::getStream(sprintf($qry, $this->id),
|
||||
'group:notices:'.$this->id,
|
||||
$offset, $limit);
|
||||
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||
array(),
|
||||
'user_group:notice_ids:' . $this->id,
|
||||
$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)
|
||||
@ -91,7 +128,7 @@ class User_group extends Memcached_DataObject
|
||||
function setOriginal($filename)
|
||||
{
|
||||
$imagefile = new ImageFile($this->id, Avatar::path($filename));
|
||||
|
||||
|
||||
$orig = clone($this);
|
||||
$this->original_logo = Avatar::url($filename);
|
||||
$this->homepage_logo = Avatar::url($imagefile->resize(AVATAR_PROFILE_SIZE));
|
||||
|
61
classes/laconica.ini
Executable file → Normal file
61
classes/laconica.ini
Executable file → Normal file
@ -1,4 +1,3 @@
|
||||
|
||||
[avatar]
|
||||
profile_id = 129
|
||||
original = 17
|
||||
@ -47,6 +46,64 @@ modified = 384
|
||||
notice_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]
|
||||
user_id = 129
|
||||
foreign_id = 129
|
||||
@ -55,6 +112,8 @@ credentials = 2
|
||||
noticesync = 145
|
||||
friendsync = 145
|
||||
profilesync = 145
|
||||
last_noticesync = 14
|
||||
last_friendsync = 14
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
|
@ -41,3 +41,17 @@ subscribed = profile:id
|
||||
[fave]
|
||||
notice_id = notice: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)
|
||||
values
|
||||
('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_conversation_idx (conversation),
|
||||
index notice_created_idx (created),
|
||||
index notice_replyto_idx (reply_to),
|
||||
FULLTEXT(content)
|
||||
) 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',
|
||||
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',
|
||||
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',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
||||
@ -422,3 +425,60 @@ create table group_inbox (
|
||||
|
||||
) 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' */,
|
||||
friendsync int not null default 2 /* comment 'friend synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming */,
|
||||
profilesync int not null default 1 /* comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming' */,
|
||||
last_noticesync timestamp default null /* comment 'last time notices were imported' */,
|
||||
last_friendsync timestamp default null /* comment 'last time friends were imported' */,
|
||||
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
|
||||
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);
|
||||
|
||||
|
||||
/*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 */
|
||||
|
||||
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()),
|
||||
('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', 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()),
|
||||
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
||||
('identicatools','Laconica Tools','http://bitbucketlabs.net/laconica-tools/', now()),
|
||||
@ -23,6 +24,7 @@ VALUES
|
||||
('peoplebrowsr', 'PeopleBrowsr', 'http://www.peoplebrowsr.com/', now()),
|
||||
('Pikchur','Pikchur','http://www.pikchur.com/', now()),
|
||||
('Ping.fm','Ping.fm','http://ping.fm/', now()),
|
||||
('pingvine','PingVine','http://pingvine.com/', now()),
|
||||
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
||||
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
||||
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
||||
@ -42,6 +44,7 @@ VALUES
|
||||
('twidge','Twidge','http://software.complete.org/twidge', now()),
|
||||
('twidroid','twidroid','http://www.twidroid.com/', now()),
|
||||
('twittelator','Twittelator','http://www.stone.com/iPhone/Twittelator/', now()),
|
||||
('twitter','Twitter','http://twitter.com/', now()),
|
||||
('twitterfeed','twitterfeed','http://twitterfeed.com/', now()),
|
||||
('twitterphoto','TwitterPhoto','http://richfish.org/twitterphoto/', now()),
|
||||
('twitterpm','Net::Twitter','http://search.cpan.org/dist/Net-Twitter/', now()),
|
||||
|
@ -2357,6 +2357,8 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
$t= explode(' ',microtime());
|
||||
$_DB_DATAOBJECT['QUERYENDTIME'] = $time = $t[0]+$t[1];
|
||||
|
||||
|
||||
do {
|
||||
|
||||
if ($_DB_driver == 'DB') {
|
||||
$result = $DB->query($string);
|
||||
@ -2374,8 +2376,19 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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 (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright 2004-2008 Facebook. All Rights Reserved.
|
||||
// Copyright 2004-2009 Facebook. All Rights Reserved.
|
||||
//
|
||||
// +---------------------------------------------------------------------------+
|
||||
// | Facebook Platform PHP5 client |
|
||||
@ -30,13 +30,12 @@
|
||||
// +---------------------------------------------------------------------------+
|
||||
// | For help with this library, contact developers-help@facebook.com |
|
||||
// +---------------------------------------------------------------------------+
|
||||
//
|
||||
|
||||
include_once 'facebookapi_php5_restlib.php';
|
||||
|
||||
define('FACEBOOK_API_VALIDATION_ERROR', 1);
|
||||
class Facebook {
|
||||
public $api_client;
|
||||
|
||||
public $api_key;
|
||||
public $secret;
|
||||
public $generate_session_secret;
|
||||
@ -213,28 +212,55 @@ 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() {
|
||||
if ($this->api_client->auth_expireSession()) {
|
||||
if (!$this->in_fb_canvas() && isset($_COOKIE[$this->api_key . '_user'])) {
|
||||
$cookies = array('user', 'session_key', 'expires', 'ss');
|
||||
foreach ($cookies as $name) {
|
||||
setcookie($this->api_key . '_' . $name, false, time() - 3600);
|
||||
unset($_COOKIE[$this->api_key . '_' . $name]);
|
||||
}
|
||||
setcookie($this->api_key, false, time() - 3600);
|
||||
unset($_COOKIE[$this->api_key]);
|
||||
}
|
||||
|
||||
// now, clear the rest of the stored state
|
||||
$this->user = 0;
|
||||
$this->api_client->session_key = 0;
|
||||
$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'])) {
|
||||
$cookies = array('user', 'session_key', 'expires', 'ss');
|
||||
foreach ($cookies as $name) {
|
||||
setcookie($this->api_key . '_' . $name, false, time() - 3600);
|
||||
unset($_COOKIE[$this->api_key . '_' . $name]);
|
||||
}
|
||||
setcookie($this->api_key, false, time() - 3600);
|
||||
unset($_COOKIE[$this->api_key]);
|
||||
}
|
||||
|
||||
// now, clear the rest of the stored state
|
||||
$this->user = 0;
|
||||
$this->api_client->session_key = 0;
|
||||
}
|
||||
|
||||
public function redirect($url) {
|
||||
if ($this->in_fb_canvas()) {
|
||||
echo '<fb:redirect url="' . $url . '"/>';
|
||||
@ -249,7 +275,8 @@ class Facebook {
|
||||
}
|
||||
|
||||
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() {
|
||||
return isset($this->fb_params['in_canvas']);
|
||||
@ -296,14 +323,42 @@ class Facebook {
|
||||
}
|
||||
|
||||
public function get_add_url($next=null) {
|
||||
return self::get_facebook_url().'/add.php?api_key='.$this->api_key .
|
||||
($next ? '&next=' . urlencode($next) : '');
|
||||
$page = self::get_facebook_url().'/add.php';
|
||||
$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) {
|
||||
return self::get_facebook_url().'/login.php?v=1.0&api_key=' . $this->api_key .
|
||||
($next ? '&next=' . urlencode($next) : '') .
|
||||
($canvas ? '&canvas' : '');
|
||||
$page = self::get_facebook_url().'/login.php';
|
||||
$params = array('api_key' => $this->api_key,
|
||||
'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) {
|
||||
@ -410,7 +465,20 @@ class Facebook {
|
||||
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.
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright 2004-2008 Facebook. All Rights Reserved.
|
||||
// Copyright 2004-2009 Facebook. All Rights Reserved.
|
||||
//
|
||||
// +---------------------------------------------------------------------------+
|
||||
// | Facebook Platform PHP5 client |
|
||||
|
1026
extlib/facebook/facebookapi_php5_restlib.php
Normal file → Executable file
1026
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()
|
||||
{
|
||||
// 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;
|
||||
|
||||
Snapshot::check();
|
||||
@ -103,6 +107,8 @@ function main()
|
||||
|
||||
$args = array_merge($args, $_REQUEST);
|
||||
|
||||
Event::handle('ArgsInitialize', array(&$args));
|
||||
|
||||
$action = $args['action'];
|
||||
|
||||
if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) {
|
||||
|
229
install.php
229
install.php
@ -35,15 +35,17 @@ function main()
|
||||
|
||||
function checkPrereqs()
|
||||
{
|
||||
$pass = true;
|
||||
|
||||
if (file_exists(INSTALLDIR.'/config.php')) {
|
||||
?><p class="error">Config file "config.php" already exists.</p>
|
||||
<?php
|
||||
return false;
|
||||
$pass = false;
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
|
||||
?><p class="error">Require PHP version 5 or greater.</p><?php
|
||||
return false;
|
||||
$pass = false;
|
||||
}
|
||||
|
||||
$reqs = array('gd', 'mysql', 'curl',
|
||||
@ -52,28 +54,26 @@ function checkPrereqs()
|
||||
|
||||
foreach ($reqs as $req) {
|
||||
if (!checkExtension($req)) {
|
||||
?><p class="error">Cannot load required extension "<?php echo $req; ?>".</p><?php
|
||||
return false;
|
||||
?><p class="error">Cannot load required extension: <code><?php echo $req; ?></code></p><?php
|
||||
$pass = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_writable(INSTALLDIR)) {
|
||||
?><p class="error">Cannot write config file to "<?php echo INSTALLDIR; ?>".</p>
|
||||
<p>On your server, try this command:</p>
|
||||
<blockquote>chmod a+w <?php echo INSTALLDIR; ?></blockquote>
|
||||
?><p class="error">Cannot write config file to: <code><?php echo INSTALLDIR; ?></code></p>
|
||||
<p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?></code>
|
||||
<?php
|
||||
return false;
|
||||
$pass = false;
|
||||
}
|
||||
|
||||
if (!is_writable(INSTALLDIR.'/avatar/')) {
|
||||
?><p class="error">Cannot write avatar directory "<?php echo INSTALLDIR; ?>/avatar/".</p>
|
||||
<p>On your server, try this command:</p>
|
||||
<blockquote>chmod a+w <?php echo INSTALLDIR; ?>/avatar/</blockquote>
|
||||
?><p class="error">Cannot write avatar directory: <code><?php echo INSTALLDIR; ?>/avatar/</code></p>
|
||||
<p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?>/avatar/</code></p>
|
||||
<?
|
||||
return false;
|
||||
$pass = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $pass;
|
||||
}
|
||||
|
||||
function checkExtension($name)
|
||||
@ -88,96 +88,125 @@ function checkExtension($name)
|
||||
|
||||
function showForm()
|
||||
{
|
||||
?>
|
||||
<p>Enter your database connection information below to initialize the database.</p>
|
||||
<form method='post' action='install.php'>
|
||||
<fieldset>
|
||||
<ul class='form_data'>
|
||||
<li>
|
||||
<label for='sitename'>Site name</label>
|
||||
<input type='text' id='sitename' name='sitename' />
|
||||
<p>The name of your site</p>
|
||||
</li>
|
||||
<li>
|
||||
<li>
|
||||
<label for='host'>Hostname</label>
|
||||
<input type='text' id='host' name='host' />
|
||||
<p>Database hostname</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for='host'>Database</label>
|
||||
<input type='text' id='database' name='database' />
|
||||
<p>Database name</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for='username'>Username</label>
|
||||
<input type='text' id='username' name='username' />
|
||||
<p>Database username</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for='password'>Password</label>
|
||||
<input type='password' id='password' name='password' />
|
||||
<p>Database password</p>
|
||||
</li>
|
||||
</ul>
|
||||
<input type='submit' name='submit' value='Submit'>
|
||||
</fieldset>
|
||||
$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>
|
||||
</div>
|
||||
</dd>
|
||||
</dl>
|
||||
<form method="post" action="install.php" class="form_settings" id="form_install">
|
||||
<fieldset>
|
||||
<legend>Connection settings</legend>
|
||||
<ul class="form_data">
|
||||
<li>
|
||||
<label for="sitename">Site name</label>
|
||||
<input type="text" id="sitename" name="sitename" />
|
||||
<p class="form_guide">The name of your site</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="fancy-enable">Fancy URLs</label>
|
||||
<input type="radio" name="fancy" id="fancy-enable" value="enable" checked='checked' /> enable<br />
|
||||
<input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
|
||||
<p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="host">Hostname</label>
|
||||
<input type="text" id="host" name="host" />
|
||||
<p class="form_guide">Database hostname</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="host">Site path</label>
|
||||
<input type="text" id="path" name="path" value="$config_path" />
|
||||
<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>
|
||||
<label for="host">Database</label>
|
||||
<input type="text" id="database" name="database" />
|
||||
<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>
|
||||
</ul>
|
||||
<input type="submit" name="submit" class="submit" value="Submit" />
|
||||
</fieldset>
|
||||
</form>
|
||||
<?
|
||||
|
||||
E_O_T;
|
||||
}
|
||||
|
||||
function updateStatus($status, $error=false)
|
||||
{
|
||||
?>
|
||||
<li>
|
||||
<?
|
||||
print $status;
|
||||
?>
|
||||
</li>
|
||||
<?
|
||||
<li <?php echo ($error) ? 'class="error"': ''; ?>><?print $status;?></li>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
?>
|
||||
<ul>
|
||||
<?
|
||||
$host = $_POST['host'];
|
||||
|
||||
<?php
|
||||
$host = $_POST['host'];
|
||||
$database = $_POST['database'];
|
||||
$username = $_POST['username'];
|
||||
$password = $_POST['password'];
|
||||
$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)) {
|
||||
updateStatus("No hostname specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if (empty($database)) {
|
||||
updateStatus("No database specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if (empty($username)) {
|
||||
updateStatus("No username specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if (empty($password)) {
|
||||
updateStatus("No password specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if (empty($sitename)) {
|
||||
updateStatus("No sitename specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if($fail){
|
||||
showForm();
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus("Starting installation...");
|
||||
updateStatus("Checking database...");
|
||||
$conn = mysql_connect($host, $username, $password);
|
||||
@ -214,24 +243,30 @@ function handlePost()
|
||||
}
|
||||
updateStatus("Writing config file...");
|
||||
$sqlUrl = "mysqli://$username:$password@$host/$database";
|
||||
$res = writeConf($sitename, $sqlUrl);
|
||||
$res = writeConf($sitename, $sqlUrl, $fancy, $path);
|
||||
if (!$res) {
|
||||
updateStatus("Can't write config file.", true);
|
||||
showForm();
|
||||
return;
|
||||
}
|
||||
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',
|
||||
"<?php\n".
|
||||
"if (!defined('LACONICA')) { exit(1); }\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;
|
||||
}
|
||||
|
||||
@ -253,21 +288,37 @@ function runDbScript($filename, $conn)
|
||||
}
|
||||
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<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/modal.css?version=0.7.1" media="screen, projection, tv"/>
|
||||
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.7.1" media="screen, projection, tv"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div id="core">
|
||||
<div id="content">
|
||||
<h1>Install Laconica</h1>
|
||||
<?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>
|
||||
<title>Install Laconica</title>
|
||||
<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/default/css/display.css?version=0.8" 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>
|
||||
<body id="install">
|
||||
<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="content">
|
||||
<h1>Install Laconica</h1>
|
||||
<?php main(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -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() {
|
||||
var f = $.farbtastic('#color-picker');
|
||||
var colors = $('#settings_design_color input');
|
||||
function UpdateColors(S) {
|
||||
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
|
||||
.each(function () { f.linkTo(this); })
|
||||
.focus(function() {
|
||||
f.linkTo(this);
|
||||
});
|
||||
function UpdateFarbtastic(e) {
|
||||
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() {
|
||||
$('#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');
|
||||
a.innerHTML = 'get this';
|
||||
a.target = '_blank';
|
||||
a.href = 'http://identica/doc/badge';
|
||||
a.href = 'http://identi.ca/doc/badge';
|
||||
$.s.f.appendChild(a);
|
||||
$.s.appendChild($.s.f);
|
||||
$.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,39 +1,48 @@
|
||||
$(function(){
|
||||
var x = ($('#avatar_crop_x').val()) ? $('#avatar_crop_x').val() : 0;
|
||||
var y = ($('#avatar_crop_y').val()) ? $('#avatar_crop_y').val() : 0;
|
||||
var w = ($('#avatar_crop_w').val()) ? $('#avatar_crop_w').val() : $("#avatar_original img").attr("width");
|
||||
var h = ($('#avatar_crop_h').val()) ? $('#avatar_crop_h').val() : $("#avatar_original img").attr("height");
|
||||
/** 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/
|
||||
*/
|
||||
|
||||
jQuery("#avatar_original img").Jcrop({
|
||||
onChange: showPreview,
|
||||
setSelect: [ x, y, w, h ],
|
||||
onSelect: updateCoords,
|
||||
aspectRatio: 1,
|
||||
boxWidth: 480,
|
||||
boxHeight: 480,
|
||||
bgColor: '#000',
|
||||
bgOpacity: .4
|
||||
});
|
||||
});
|
||||
$(function(){
|
||||
var x = ($('#avatar_crop_x').val()) ? $('#avatar_crop_x').val() : 0;
|
||||
var y = ($('#avatar_crop_y').val()) ? $('#avatar_crop_y').val() : 0;
|
||||
var w = ($('#avatar_crop_w').val()) ? $('#avatar_crop_w').val() : $("#avatar_original img").attr("width");
|
||||
var h = ($('#avatar_crop_h').val()) ? $('#avatar_crop_h').val() : $("#avatar_original img").attr("height");
|
||||
|
||||
function showPreview(coords) {
|
||||
var rx = 96 / coords.w;
|
||||
var ry = 96 / coords.h;
|
||||
jQuery("#avatar_original img").Jcrop({
|
||||
onChange: showPreview,
|
||||
setSelect: [ x, y, w, h ],
|
||||
onSelect: updateCoords,
|
||||
aspectRatio: 1,
|
||||
boxWidth: 480,
|
||||
boxHeight: 480,
|
||||
bgColor: '#000',
|
||||
bgOpacity: .4
|
||||
});
|
||||
});
|
||||
|
||||
var img_width = $("#avatar_original img").attr("width");
|
||||
var img_height = $("#avatar_original img").attr("height");
|
||||
function showPreview(coords) {
|
||||
var rx = 96 / coords.w;
|
||||
var ry = 96 / coords.h;
|
||||
|
||||
$('#avatar_preview img').css({
|
||||
width: Math.round(rx *img_width) + 'px',
|
||||
height: Math.round(ry * img_height) + 'px',
|
||||
marginLeft: '-' + Math.round(rx * coords.x) + 'px',
|
||||
marginTop: '-' + Math.round(ry * coords.y) + 'px'
|
||||
});
|
||||
};
|
||||
var img_width = $("#avatar_original img").attr("width");
|
||||
var img_height = $("#avatar_original img").attr("height");
|
||||
|
||||
function updateCoords(c) {
|
||||
$('#avatar_crop_x').val(c.x);
|
||||
$('#avatar_crop_y').val(c.y);
|
||||
$('#avatar_crop_w').val(c.w);
|
||||
$('#avatar_crop_h').val(c.h);
|
||||
};
|
||||
$('#avatar_preview img').css({
|
||||
width: Math.round(rx *img_width) + 'px',
|
||||
height: Math.round(ry * img_height) + 'px',
|
||||
marginLeft: '-' + Math.round(rx * coords.x) + 'px',
|
||||
marginTop: '-' + Math.round(ry * coords.y) + 'px'
|
||||
});
|
||||
};
|
||||
|
||||
function updateCoords(c) {
|
||||
$('#avatar_crop_x').val(c.x);
|
||||
$('#avatar_crop_y').val(c.y);
|
||||
$('#avatar_crop_w').val(c.w);
|
||||
$('#avatar_crop_h').val(c.h);
|
||||
};
|
||||
|
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);
|
45
js/util.js
45
js/util.js
@ -17,6 +17,10 @@
|
||||
*/
|
||||
|
||||
$(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
|
||||
function counter(event){
|
||||
var maxLength = 140;
|
||||
@ -166,19 +170,45 @@ $(document).ready(function(){
|
||||
$("#notice_action-submit").addClass("disabled");
|
||||
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);
|
||||
result = result.textContent || result.innerHTML;
|
||||
alert(result);
|
||||
}
|
||||
else {
|
||||
$("#notices_primary .notices").prepend(document._importNode($("li", xml).get(0), true));
|
||||
if ($("#command_result", xml).length > 0) {
|
||||
var result = document._importNode($("p", xml).get(0), true);
|
||||
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").fadeIn(2500);
|
||||
NoticeHover();
|
||||
NoticeReply();
|
||||
}
|
||||
}
|
||||
$("#notice_data-text").val("");
|
||||
counter();
|
||||
$("#notices_primary .notice:first").css({display:"none"});
|
||||
$("#notices_primary .notice:first").fadeIn(2500);
|
||||
NoticeHover();
|
||||
NoticeReply();
|
||||
counter();
|
||||
}
|
||||
$("#form_notice").removeClass("processing");
|
||||
$("#notice_action-submit").removeAttr("disabled");
|
||||
@ -187,7 +217,6 @@ $(document).ready(function(){
|
||||
};
|
||||
$("#form_notice").ajaxForm(PostNotice);
|
||||
$("#form_notice").each(addAjaxHidden);
|
||||
|
||||
NoticeHover();
|
||||
NoticeReply();
|
||||
});
|
||||
|
@ -22,6 +22,7 @@ if (!defined('LACONICA')) { exit(1); }
|
||||
class ShortUrlApi
|
||||
{
|
||||
protected $service_url;
|
||||
protected $long_limit = 27;
|
||||
|
||||
function __construct($service_url)
|
||||
{
|
||||
@ -39,7 +40,7 @@ class ShortUrlApi
|
||||
}
|
||||
|
||||
private function is_long($url) {
|
||||
return strlen($url) >= 30;
|
||||
return strlen($url) >= $this->long_limit;
|
||||
}
|
||||
|
||||
protected function http_post($data) {
|
||||
|
@ -98,15 +98,15 @@ class Action extends HTMLOutputter // lawsuit
|
||||
Event::handle('EndShowHTML', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowHead', array($this))) {
|
||||
$this->showHead();
|
||||
$this->showHead();
|
||||
Event::handle('EndShowHead', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowBody', array($this))) {
|
||||
$this->showBody();
|
||||
$this->showBody();
|
||||
Event::handle('EndShowBody', array($this));
|
||||
}
|
||||
if (Event::handle('StartEndHTML', array($this))) {
|
||||
$this->endHTML();
|
||||
$this->endHTML();
|
||||
Event::handle('EndEndHTML', array($this));
|
||||
}
|
||||
}
|
||||
@ -243,6 +243,12 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'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));
|
||||
}
|
||||
if (Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||
@ -347,7 +353,7 @@ class Action extends HTMLOutputter // lawsuit
|
||||
{
|
||||
$this->elementStart('body', (common_current_user()) ? array('id' => $this->trimmed('action'),
|
||||
'class' => 'user_in')
|
||||
: array('id' => $this->trimmed('action')));
|
||||
: array('id' => $this->trimmed('action')));
|
||||
$this->elementStart('div', array('id' => 'wrap'));
|
||||
if (Event::handle('StartShowHeader', array($this))) {
|
||||
$this->showHeader();
|
||||
@ -431,10 +437,10 @@ class Action extends HTMLOutputter // lawsuit
|
||||
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
||||
}
|
||||
$this->menuItem(common_local_url('invite'),
|
||||
_('Invite'),
|
||||
sprintf(_('Invite friends and colleagues to join you on %s'),
|
||||
common_config('site', 'name')),
|
||||
false, 'nav_invitecontact');
|
||||
_('Invite'),
|
||||
sprintf(_('Invite friends and colleagues to join you on %s'),
|
||||
common_config('site', 'name')),
|
||||
false, 'nav_invitecontact');
|
||||
$this->menuItem(common_local_url('logout'),
|
||||
_('Logout'), _('Logout from the site'), false, 'nav_logout');
|
||||
}
|
||||
@ -591,7 +597,10 @@ class Action extends HTMLOutputter // lawsuit
|
||||
'class' => 'system_notice'));
|
||||
$this->element('dt', null, _('Page notice'));
|
||||
$this->elementStart('dd');
|
||||
$this->showPageNotice();
|
||||
if (Event::handle('StartShowPageNotice', array($this))) {
|
||||
$this->showPageNotice();
|
||||
Event::handle('EndShowPageNotice', array($this));
|
||||
}
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
@ -629,7 +638,7 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->elementStart('div', array('id' => 'aside_primary',
|
||||
'class' => 'aside'));
|
||||
if (Event::handle('StartShowExportData', array($this))) {
|
||||
$this->showExportData();
|
||||
$this->showExportData();
|
||||
Event::handle('EndShowExportData', array($this));
|
||||
}
|
||||
if (Event::handle('StartShowSections', array($this))) {
|
||||
|
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',
|
||||
'user' => false,
|
||||
'group' => false),
|
||||
'twitterbridge' =>
|
||||
array('enabled' => false),
|
||||
'integration' =>
|
||||
array('source' => 'Laconica', # source attribute for Twitter
|
||||
'taguri' => $_server.',2009'), # base for tag URIs
|
||||
@ -197,7 +199,7 @@ $_config_files[] = INSTALLDIR.'/config.php';
|
||||
$_have_a_config = false;
|
||||
|
||||
foreach ($_config_files as $_config_file) {
|
||||
if (file_exists($_config_file)) {
|
||||
if (@file_exists($_config_file)) {
|
||||
include_once($_config_file);
|
||||
$_have_a_config = true;
|
||||
}
|
||||
|
@ -27,9 +27,21 @@ define("FACEBOOK_PROMPTED_UPDATE_PREF", 2);
|
||||
|
||||
function getFacebook()
|
||||
{
|
||||
static $facebook = null;
|
||||
|
||||
$apikey = common_config('facebook', 'apikey');
|
||||
$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) {
|
||||
@ -92,7 +104,6 @@ function isFacebookBound($notice, $flink) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function facebookBroadcastNotice($notice)
|
||||
{
|
||||
$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('form', array('name' => 'bytag',
|
||||
'id' => 'bytag',
|
||||
'action' => common_path('?action=' . $this->trimmed('action')),
|
||||
'method' => 'post'));
|
||||
$this->dropdown('tag', _('Tag'), $content,
|
||||
_('Choose a tag to narrow list'), false, $tag);
|
||||
$this->hidden('nickname', $this->user->nickname);
|
||||
$this->submit('submit', _('Go'));
|
||||
$this->elementEnd('form');
|
||||
$this->elementEnd('li');
|
||||
@ -169,4 +171,4 @@ class GalleryAction extends Action
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +179,7 @@ class NoticeListItem extends Widget
|
||||
{
|
||||
$this->showStart();
|
||||
$this->showNotice();
|
||||
$this->showNoticeAttachments();
|
||||
$this->showNoticeInfo();
|
||||
$this->showNoticeOptions();
|
||||
$this->showEnd();
|
||||
@ -192,6 +193,48 @@ class NoticeListItem extends Widget
|
||||
$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()
|
||||
{
|
||||
$this->out->elementStart('div', 'entry-content');
|
||||
|
@ -51,17 +51,13 @@ class NoticeSection extends Section
|
||||
function showContent()
|
||||
{
|
||||
$notices = $this->getNotices();
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
$this->out->elementStart('ul', 'notices');
|
||||
|
||||
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
||||
$this->showNotice($notices);
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
|
||||
return ($cnt > NOTICES_PER_SECTION);
|
||||
}
|
||||
|
||||
@ -100,6 +96,37 @@ class NoticeSection extends Section
|
||||
|
||||
$this->out->elementStart('p', 'entry-content');
|
||||
$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');
|
||||
if (!empty($notice->value)) {
|
||||
$this->out->elementStart('p');
|
||||
|
@ -93,43 +93,45 @@ class PersonalGroupNav extends Widget
|
||||
|
||||
$this->out->elementStart('ul', array('class' => 'nav'));
|
||||
|
||||
$this->out->menuItem(common_local_url('all', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Personal'),
|
||||
sprintf(_('%s and friends'), (($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
|
||||
$action == 'all', 'nav_timeline_personal');
|
||||
$this->out->menuItem(common_local_url('replies', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Replies'),
|
||||
sprintf(_('Replies to %s'), (($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
|
||||
$action == 'replies', 'nav_timeline_replies');
|
||||
$this->out->menuItem(common_local_url('showstream', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Profile'),
|
||||
($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname,
|
||||
$action == 'showstream', 'nav_profile');
|
||||
$this->out->menuItem(common_local_url('showfavorites', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Favorites'),
|
||||
sprintf(_('%s\'s favorite notices'), ($user_profile) ? $user_profile->getBestName() : _('User')),
|
||||
$action == 'showfavorites', 'nav_timeline_favorites');
|
||||
if (Event::handle('StartPersonalGroupNav', array($this))) {
|
||||
$this->out->menuItem(common_local_url('all', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Personal'),
|
||||
sprintf(_('%s and friends'), (($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
|
||||
$action == 'all', 'nav_timeline_personal');
|
||||
$this->out->menuItem(common_local_url('replies', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Replies'),
|
||||
sprintf(_('Replies to %s'), (($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname)),
|
||||
$action == 'replies', 'nav_timeline_replies');
|
||||
$this->out->menuItem(common_local_url('showstream', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Profile'),
|
||||
($user_profile && $user_profile->fullname) ? $user_profile->fullname : $nickname,
|
||||
$action == 'showstream', 'nav_profile');
|
||||
$this->out->menuItem(common_local_url('showfavorites', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Favorites'),
|
||||
sprintf(_('%s\'s favorite notices'), ($user_profile) ? $user_profile->getBestName() : _('User')),
|
||||
$action == 'showfavorites', 'nav_timeline_favorites');
|
||||
|
||||
$cur = common_current_user();
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($cur && $cur->id == $user->id) {
|
||||
if ($cur && $cur->id == $user->id) {
|
||||
|
||||
$this->out->menuItem(common_local_url('inbox', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Inbox'),
|
||||
_('Your incoming messages'),
|
||||
$action == 'inbox');
|
||||
$this->out->menuItem(common_local_url('outbox', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Outbox'),
|
||||
_('Your sent messages'),
|
||||
$action == 'outbox');
|
||||
$this->out->menuItem(common_local_url('inbox', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Inbox'),
|
||||
_('Your incoming messages'),
|
||||
$action == 'inbox');
|
||||
$this->out->menuItem(common_local_url('outbox', array('nickname' =>
|
||||
$nickname)),
|
||||
_('Outbox'),
|
||||
_('Your sent messages'),
|
||||
$action == 'outbox');
|
||||
}
|
||||
Event::handle('EndPersonalGroupNav', array($this));
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class PopularNoticeSection extends NoticeSection
|
||||
if (common_config('db', 'type') == 'pgsql') {
|
||||
$weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))';
|
||||
if (!empty($this->out->tag)) {
|
||||
$tag = pg_escape_string($this->tag);
|
||||
$tag = pg_escape_string($this->out->tag);
|
||||
}
|
||||
} else {
|
||||
$weightexpr='sum(exp(-(now() - fave.modified) / %s))';
|
||||
|
@ -49,16 +49,17 @@ require_once INSTALLDIR.'/lib/groupminilist.php';
|
||||
|
||||
class ProfileAction extends Action
|
||||
{
|
||||
var $user = null;
|
||||
var $page = null;
|
||||
var $user = null;
|
||||
var $page = null;
|
||||
var $profile = null;
|
||||
var $tag = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$nickname_arg = $this->arg('nickname');
|
||||
$nickname = common_canonical_nickname($nickname_arg);
|
||||
$nickname = common_canonical_nickname($nickname_arg);
|
||||
|
||||
// Permanent redirect on non-canonical nickname
|
||||
|
||||
@ -85,10 +86,9 @@ class ProfileAction extends Action
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->tag = $this->trimmed('tag');
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -244,4 +244,5 @@ class ProfileAction extends Action
|
||||
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,12 +151,26 @@ class Router
|
||||
$m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'),
|
||||
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
|
||||
|
||||
$m->connect('notice/new', array('action' => 'newnotice'));
|
||||
$m->connect('notice/new?replyto=:replyto',
|
||||
array('action' => 'newnotice'),
|
||||
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',
|
||||
array('action' => 'shownotice'),
|
||||
array('notice' => '[0-9]+'));
|
||||
@ -237,12 +251,12 @@ class Router
|
||||
$m->connect('api/statuses/:method',
|
||||
array('action' => 'api',
|
||||
'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',
|
||||
array('action' => 'api',
|
||||
'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
|
||||
|
||||
@ -412,6 +426,16 @@ class Router
|
||||
array('size' => '(original|96|48|24)',
|
||||
'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',
|
||||
array('action' => 'showstream'),
|
||||
array('nickname' => '[a-zA-Z0-9]{1,64}'));
|
||||
|
@ -97,7 +97,11 @@ class Rss10Action extends Action
|
||||
// Parent handling, including cache check
|
||||
parent::handle($args);
|
||||
// Get the list of notices
|
||||
$this->notices = $this->getNotices($this->limit);
|
||||
if (empty($this->tag)) {
|
||||
$this->notices = $this->getNotices($this->limit);
|
||||
} else {
|
||||
$this->notices = $this->getTaggedNotices($this->tag, $this->limit);
|
||||
}
|
||||
$this->showRss();
|
||||
}
|
||||
|
||||
|
@ -74,38 +74,44 @@ class SubGroupNav extends Widget
|
||||
|
||||
$this->out->elementStart('ul', array('class' => 'nav'));
|
||||
|
||||
$this->out->menuItem(common_local_url('subscriptions',
|
||||
array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
_('Subscriptions'),
|
||||
sprintf(_('People %s subscribes to'),
|
||||
$this->user->nickname),
|
||||
$action == 'subscriptions',
|
||||
'nav_subscriptions');
|
||||
$this->out->menuItem(common_local_url('subscribers',
|
||||
array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
_('Subscribers'),
|
||||
sprintf(_('People subscribed to %s'),
|
||||
$this->user->nickname),
|
||||
$action == 'subscribers',
|
||||
'nav_subscribers');
|
||||
$this->out->menuItem(common_local_url('usergroups',
|
||||
array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
_('Groups'),
|
||||
sprintf(_('Groups %s is a member of'),
|
||||
$this->user->nickname),
|
||||
$action == 'usergroups',
|
||||
'nav_usergroups');
|
||||
if (!is_null($cur) && $this->user->id === $cur->id) {
|
||||
$this->out->menuItem(common_local_url('invite'),
|
||||
_('Invite'),
|
||||
sprintf(_('Invite friends and colleagues to join you on %s'),
|
||||
common_config('site', 'name')),
|
||||
$action == 'invite',
|
||||
'nav_invite');
|
||||
if (Event::handle('StartSubGroupNav', array($this))) {
|
||||
|
||||
$this->out->menuItem(common_local_url('subscriptions',
|
||||
array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
_('Subscriptions'),
|
||||
sprintf(_('People %s subscribes to'),
|
||||
$this->user->nickname),
|
||||
$action == 'subscriptions',
|
||||
'nav_subscriptions');
|
||||
$this->out->menuItem(common_local_url('subscribers',
|
||||
array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
_('Subscribers'),
|
||||
sprintf(_('People subscribed to %s'),
|
||||
$this->user->nickname),
|
||||
$action == 'subscribers',
|
||||
'nav_subscribers');
|
||||
$this->out->menuItem(common_local_url('usergroups',
|
||||
array('nickname' =>
|
||||
$this->user->nickname)),
|
||||
_('Groups'),
|
||||
sprintf(_('Groups %s is a member of'),
|
||||
$this->user->nickname),
|
||||
$action == 'usergroups',
|
||||
'nav_usergroups');
|
||||
if (!is_null($cur) && $this->user->id === $cur->id) {
|
||||
$this->out->menuItem(common_local_url('invite'),
|
||||
_('Invite'),
|
||||
sprintf(_('Invite friends and colleagues to join you on %s'),
|
||||
common_config('site', 'name')),
|
||||
$action == 'invite',
|
||||
'nav_invite');
|
||||
}
|
||||
|
||||
Event::handle('EndSubGroupNav', array($this));
|
||||
}
|
||||
|
||||
$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,7 +114,11 @@ class TagCloudSection extends Section
|
||||
|
||||
function tagUrl($tag)
|
||||
{
|
||||
return common_local_url('tag', array('tag' => $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));
|
||||
}
|
||||
}
|
||||
|
||||
function divId()
|
||||
|
@ -51,6 +51,26 @@ class TwitterapiAction extends Action
|
||||
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)
|
||||
{
|
||||
|
||||
@ -66,7 +86,7 @@ class TwitterapiAction extends Action
|
||||
$avatar = $profile->getAvatar(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;
|
||||
|
||||
if ($get_notice) {
|
||||
@ -86,7 +106,7 @@ class TwitterapiAction extends Action
|
||||
|
||||
$twitter_status = array();
|
||||
$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['in_reply_to_status_id'] = ($notice->reply_to) ?
|
||||
intval($notice->reply_to) : null;
|
||||
@ -108,10 +128,9 @@ class TwitterapiAction extends Action
|
||||
($replier_profile) ? $replier_profile->nickname : null;
|
||||
|
||||
if (isset($this->auth_user)) {
|
||||
$twitter_status['favorited'] =
|
||||
($this->auth_user->hasFave($notice)) ? 'true' : 'false';
|
||||
$twitter_status['favorited'] = $this->auth_user->hasFave($notice);
|
||||
} else {
|
||||
$twitter_status['favorited'] = 'false';
|
||||
$twitter_status['favorited'] = false;
|
||||
}
|
||||
|
||||
if ($include_user) {
|
||||
@ -418,7 +437,7 @@ class TwitterapiAction extends Action
|
||||
function date_twitter($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?
|
||||
|
110
lib/util.php
110
lib/util.php
@ -395,7 +395,7 @@ function common_render_text($text)
|
||||
return $r;
|
||||
}
|
||||
|
||||
function common_replace_urls_callback($text, $callback) {
|
||||
function common_replace_urls_callback($text, $callback, $notice_id = null) {
|
||||
// Start off with a regex
|
||||
$regex = '#'.
|
||||
'(?:'.
|
||||
@ -466,7 +466,11 @@ function common_replace_urls_callback($text, $callback) {
|
||||
$url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url);
|
||||
|
||||
// Call user specified func
|
||||
$modified_url = call_user_func($callback, $url);
|
||||
if (empty($notice_id)) {
|
||||
$modified_url = call_user_func($callback, $url);
|
||||
} else {
|
||||
$modified_url = call_user_func($callback, array($url, $notice_id));
|
||||
}
|
||||
|
||||
// Replace it!
|
||||
$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
|
||||
// functions
|
||||
$url = htmlspecialchars_decode($url);
|
||||
$display = $url;
|
||||
$url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url : $url;
|
||||
|
||||
$attrs = array('href' => $url, 'rel' => 'external');
|
||||
|
||||
if ($longurl = common_longurl($url)) {
|
||||
$attrs['title'] = $longurl;
|
||||
$display = File_redirection::_canonUrl($url);
|
||||
$longurl_data = File_redirection::where($url);
|
||||
if (is_array($longurl_data)) {
|
||||
$longurl = $longurl_data['url'];
|
||||
} elseif (is_string($longurl_data)) {
|
||||
$longurl = $longurl_data;
|
||||
} else {
|
||||
die('impossible to linkify');
|
||||
}
|
||||
|
||||
$attrs = array('href' => $longurl, 'rel' => 'external');
|
||||
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)
|
||||
{
|
||||
if (mb_strlen($text) <= 140) return $text;
|
||||
static $cache = array();
|
||||
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;
|
||||
return common_replace_urls_callback($text, array('File_redirection', 'makeShort'));
|
||||
}
|
||||
|
||||
function common_xml_safe_str($str)
|
||||
@ -1019,7 +945,7 @@ function common_root_url($ssl=false)
|
||||
function common_good_rand($bytes)
|
||||
{
|
||||
// XXX: use random.org...?
|
||||
if (file_exists('/dev/urandom')) {
|
||||
if (@file_exists('/dev/urandom')) {
|
||||
return common_urandom($bytes);
|
||||
} else { // FIXME: this is probably not good enough
|
||||
return common_mtrand($bytes);
|
||||
@ -1385,7 +1311,7 @@ function common_compatible_license($from, $to)
|
||||
*/
|
||||
function common_database_tablename($tablename)
|
||||
{
|
||||
|
||||
|
||||
if(common_config('db','quote_identifiers')) {
|
||||
$tablename = '"'. $tablename .'"';
|
||||
}
|
||||
|
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
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user