forked from GNUsocial/gnu-social
Merge branch '0.8.x' of git://gitorious.org/laconica/dev into dev/0.8.x
This commit is contained in:
commit
4110838cb4
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
avatar/*
|
avatar/*
|
||||||
files/*
|
files/*
|
||||||
|
file/*
|
||||||
_darcs/*
|
_darcs/*
|
||||||
logs/*
|
logs/*
|
||||||
config.php
|
config.php
|
||||||
@ -16,3 +17,8 @@ dataobject.ini
|
|||||||
.buildpath
|
.buildpath
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
|
TODO.rym
|
||||||
|
config-*.php
|
||||||
|
good-config.php
|
||||||
|
lac08.log
|
||||||
|
php.log
|
||||||
|
91
README
91
README
@ -694,6 +694,13 @@ to users on a remote site. (Or not... it's not well tested.) The
|
|||||||
Upgrading
|
Upgrading
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
IMPORTANT NOTE: Laconica 0.7.4 introduced a fix for some
|
||||||
|
incorrectly-stored international characters ("UTF-8"). For new
|
||||||
|
installations, it will now store non-ASCII characters correctly.
|
||||||
|
However, older installations will have the incorrect storage, and will
|
||||||
|
consequently show up "wrong" in browsers. See below for how to deal
|
||||||
|
with this situation.
|
||||||
|
|
||||||
If you've been using Laconica 0.6, 0.5 or lower, or if you've been
|
If you've been using Laconica 0.6, 0.5 or lower, or if you've been
|
||||||
tracking the "git" version of the software, you will probably want
|
tracking the "git" version of the software, you will probably want
|
||||||
to upgrade and keep your existing data. There is no automated upgrade
|
to upgrade and keep your existing data. There is no automated upgrade
|
||||||
@ -783,6 +790,29 @@ problem.
|
|||||||
3. When fixup_inboxes is finished, you can set the enabled flag to
|
3. When fixup_inboxes is finished, you can set the enabled flag to
|
||||||
'true'.
|
'true'.
|
||||||
|
|
||||||
|
UTF-8 Database
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Laconica 0.7.4 introduced a fix for some incorrectly-stored
|
||||||
|
international characters ("UTF-8"). This fix is not
|
||||||
|
backwards-compatible; installations from before 0.7.4 will show
|
||||||
|
non-ASCII characters of old notices incorrectly. This section explains
|
||||||
|
what to do.
|
||||||
|
|
||||||
|
0. You can disable the new behaviour by setting the 'db''utf8' config
|
||||||
|
option to "false". You should only do this until you're ready to
|
||||||
|
convert your DB to the new format.
|
||||||
|
1. When you're ready to convert, you can run the fixup_utf8.php script
|
||||||
|
in the scripts/ subdirectory. If you've had the "new behaviour"
|
||||||
|
enabled (probably a good idea), you can give the ID of the first
|
||||||
|
"new" notice as a parameter, and only notices before that one will
|
||||||
|
be converted. Notices are converted in reverse chronological order,
|
||||||
|
so the most recent (and visible) ones will be converted first. The
|
||||||
|
script should work whether or not you have the 'db''utf8' config
|
||||||
|
option enabled.
|
||||||
|
2. When you're ready, set $config['db']['utf8'] to true, so that
|
||||||
|
new notices will be stored correctly.
|
||||||
|
|
||||||
Configuration options
|
Configuration options
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
@ -910,6 +940,10 @@ mirror: you can set this to an array of DSNs, like the above
|
|||||||
and adding the slaves to this array. Note that if you want some
|
and adding the slaves to this array. Note that if you want some
|
||||||
requests to go to the 'database' (master) server, you'll need
|
requests to go to the 'database' (master) server, you'll need
|
||||||
to include it in this array, too.
|
to include it in this array, too.
|
||||||
|
utf8: whether to talk to the database in UTF-8 mode. This is the default
|
||||||
|
with new installations, but older sites may want to turn it off
|
||||||
|
until they get their databases fixed up. See "UTF-8 database"
|
||||||
|
above for details.
|
||||||
|
|
||||||
syslog
|
syslog
|
||||||
------
|
------
|
||||||
@ -1136,6 +1170,63 @@ welcome: nickname of a user account that sends welcome messages to new
|
|||||||
If either of these special user accounts are specified, the users should
|
If either of these special user accounts are specified, the users should
|
||||||
be created before the configuration is updated.
|
be created before the configuration is updated.
|
||||||
|
|
||||||
|
snapshot
|
||||||
|
--------
|
||||||
|
|
||||||
|
The software will, by default, send statistical snapshots about the
|
||||||
|
local installation to a stats server on the laconi.ca Web site. This
|
||||||
|
data is used by the developers to prioritize development decisions. No
|
||||||
|
identifying data about users or organizations is collected. The data
|
||||||
|
is available to the public for review. Participating in this survey
|
||||||
|
helps Laconica developers take your needs into account when updating
|
||||||
|
the software.
|
||||||
|
|
||||||
|
run: string indicating when to run the statistics. Values can be 'web'
|
||||||
|
(run occasionally at Web time), 'cron' (run from a cron script),
|
||||||
|
or 'never' (don't ever run). If you set it to 'cron', remember to
|
||||||
|
schedule the script to run on a regular basis.
|
||||||
|
frequency: if run value is 'web', how often to report statistics.
|
||||||
|
Measured in Web hits; depends on how active your site is.
|
||||||
|
Default is 10000 -- that is, one report every 10000 Web hits,
|
||||||
|
on average.
|
||||||
|
reporturl: URL to post statistics to. Defaults to Laconica developers'
|
||||||
|
report system, but if they go evil or disappear you may
|
||||||
|
need to update this to another value. Note: if you
|
||||||
|
don't want to report stats, it's much better to
|
||||||
|
set 'run' to 'never' than to set this value to something
|
||||||
|
nonsensical.
|
||||||
|
|
||||||
|
|
||||||
|
attachments
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The software lets users upload files with their notices. You can configure
|
||||||
|
the types of accepted files by mime types and a trio of quota options:
|
||||||
|
per file, per user (total), per user per month.
|
||||||
|
|
||||||
|
We suggest the use of the pecl file_info extension to handle mime type
|
||||||
|
detection.
|
||||||
|
|
||||||
|
supported: an array of mime types you accept to store and distribute,
|
||||||
|
like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
|
||||||
|
setup your server to properly reckognize the types you want to
|
||||||
|
support.
|
||||||
|
|
||||||
|
For quotas, be sure you've set the upload_max_filesize and post_max_size
|
||||||
|
in php.ini to be large enough to handle your upload. In httpd.conf
|
||||||
|
(if you're using apache), check that the LimitRequestBody directive isn't
|
||||||
|
set too low (it's optional, so it may not be there at all).
|
||||||
|
|
||||||
|
file_quota: maximum size for a single file upload in bytes. A user can send
|
||||||
|
any amount of notices with attachments as long as each attachment
|
||||||
|
is smaller than file_quota.
|
||||||
|
user_quota: total size in bytes a user can store on this server. Each user
|
||||||
|
can store any number of files as long as their total size does
|
||||||
|
not exceed the user_quota.
|
||||||
|
monthly_quota: total size permitted in the current month. This is the total
|
||||||
|
size in bytes that a user can upload each month.
|
||||||
|
|
||||||
|
|
||||||
Troubleshooting
|
Troubleshooting
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ class ApiAction extends Action
|
|||||||
$this->process_command();
|
$this->process_command();
|
||||||
} else {
|
} else {
|
||||||
# basic authentication failed
|
# basic authentication failed
|
||||||
|
common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname.");
|
||||||
$this->show_basic_auth_error();
|
$this->show_basic_auth_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,6 @@ if (!defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
|
||||||
//require_once INSTALLDIR.'/lib/feedlist.php';
|
|
||||||
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,11 +65,11 @@ class AttachmentAction extends Action
|
|||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
$id = $this->arg('attachment');
|
if ($id = $this->trimmed('attachment')) {
|
||||||
|
$this->attachment = File::staticGet($id);
|
||||||
|
}
|
||||||
|
|
||||||
$this->attachment = File::staticGet($id);
|
if (empty($this->attachment)) {
|
||||||
|
|
||||||
if (!$this->attachment) {
|
|
||||||
$this->clientError(_('No such attachment.'), 404);
|
$this->clientError(_('No such attachment.'), 404);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -178,10 +176,8 @@ class AttachmentAction extends Action
|
|||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$this->elementStart('ul', array('class' => 'attachments'));
|
|
||||||
$ali = new Attachment($this->attachment, $this);
|
$ali = new Attachment($this->attachment, $this);
|
||||||
$cnt = $ali->show();
|
$cnt = $ali->show();
|
||||||
$this->elementEnd('ul');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,26 +45,6 @@ require_once INSTALLDIR.'/actions/attachment.php';
|
|||||||
|
|
||||||
class Attachment_ajaxAction extends AttachmentAction
|
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.
|
* Show page, a template method.
|
||||||
*
|
*
|
||||||
@ -95,8 +75,6 @@ class Attachment_ajaxAction extends AttachmentAction
|
|||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last-modified date for page
|
* Last-modified date for page
|
||||||
*
|
*
|
||||||
|
@ -31,9 +31,7 @@ if (!defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
require_once INSTALLDIR.'/actions/attachment.php';
|
||||||
//require_once INSTALLDIR.'/lib/feedlist.php';
|
|
||||||
require_once INSTALLDIR.'/actions/attachments.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show notice attachments
|
* Show notice attachments
|
||||||
@ -45,39 +43,8 @@ require_once INSTALLDIR.'/actions/attachments.php';
|
|||||||
* @link http://laconi.ca/
|
* @link http://laconi.ca/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Attachments_ajaxAction extends AttachmentsAction
|
class Attachment_thumbnailAction extends AttachmentAction
|
||||||
{
|
{
|
||||||
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.
|
* Show page, a template method.
|
||||||
*
|
*
|
||||||
@ -100,16 +67,52 @@ class Attachments_ajaxAction extends AttachmentsAction
|
|||||||
*/
|
*/
|
||||||
function showCore()
|
function showCore()
|
||||||
{
|
{
|
||||||
$this->elementStart('div', array('id' => 'core'));
|
$file_thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
|
||||||
if (Event::handle('StartShowContentBlock', array($this))) {
|
if (empty($file_thumbnail->url)) {
|
||||||
$this->showContentBlock();
|
return;
|
||||||
Event::handle('EndShowContentBlock', array($this));
|
|
||||||
}
|
}
|
||||||
$this->elementEnd('div');
|
$this->element('img', array('src' => $file_thumbnail->url, 'alt' => 'Thumbnail'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)) . '"';
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
@ -1,292 +0,0 @@
|
|||||||
<?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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
|||||||
* @link http://laconi.ca/
|
* @link http://laconi.ca/
|
||||||
*
|
*
|
||||||
* Laconica - a distributed open-source microblogging tool
|
* Laconica - a distributed open-source microblogging tool
|
||||||
* Copyright (C) 2008, Controlez-Vous, Inc.
|
* Copyright (C) 2009, Control Yourself, Inc.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -31,7 +31,7 @@ if (!defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/noticelist.php');
|
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversation tree in the browser
|
* Conversation tree in the browser
|
||||||
@ -42,9 +42,10 @@ require_once(INSTALLDIR.'/lib/noticelist.php');
|
|||||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
* @link http://laconi.ca/
|
* @link http://laconi.ca/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ConversationAction extends Action
|
class ConversationAction extends Action
|
||||||
{
|
{
|
||||||
var $id = null;
|
var $id = null;
|
||||||
var $page = null;
|
var $page = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,24 +70,47 @@ class ConversationAction extends Action
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the action
|
||||||
|
*
|
||||||
|
* @param array $args Web and URL arguments
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the page title
|
||||||
|
*
|
||||||
|
* @return string page title
|
||||||
|
*/
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
return _("Conversation");
|
return _("Conversation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show content.
|
||||||
|
*
|
||||||
|
* Display a hierarchical unordered list in the content area.
|
||||||
|
* Uses ConversationTree to do most of the heavy lifting.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
// FIXME this needs to be a tree, not a list
|
// FIXME this needs to be a tree, not a list
|
||||||
|
|
||||||
$qry = 'SELECT * FROM notice WHERE conversation = %s ';
|
$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;
|
$limit = NOTICES_PER_PAGE + 1;
|
||||||
|
|
||||||
$txt = sprintf($qry, $this->id);
|
$txt = sprintf($qry, $this->id);
|
||||||
@ -95,9 +119,9 @@ class ConversationAction extends Action
|
|||||||
'notice:conversation:'.$this->id,
|
'notice:conversation:'.$this->id,
|
||||||
$offset, $limit);
|
$offset, $limit);
|
||||||
|
|
||||||
$nl = new NoticeList($notices, $this);
|
$ct = new ConversationTree($notices, $this);
|
||||||
|
|
||||||
$cnt = $nl->show();
|
$cnt = $ct->show();
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||||
$this->page, 'conversation', array('id' => $this->id));
|
$this->page, 'conversation', array('id' => $this->id));
|
||||||
@ -105,3 +129,170 @@ class ConversationAction extends Action
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation tree
|
||||||
|
*
|
||||||
|
* The widget class for displaying a hierarchical list of notices.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ConversationTree extends NoticeList
|
||||||
|
{
|
||||||
|
var $tree = null;
|
||||||
|
var $table = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the tree of notices
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$cnt = 0;
|
||||||
|
|
||||||
|
$this->tree = array();
|
||||||
|
$this->table = array();
|
||||||
|
|
||||||
|
while ($this->notice->fetch()) {
|
||||||
|
|
||||||
|
$cnt++;
|
||||||
|
|
||||||
|
$id = $this->notice->id;
|
||||||
|
$notice = clone($this->notice);
|
||||||
|
|
||||||
|
$this->table[$id] = $notice;
|
||||||
|
|
||||||
|
if (is_null($notice->reply_to)) {
|
||||||
|
$this->tree['root'] = array($notice->id);
|
||||||
|
} else if (array_key_exists($notice->reply_to, $this->tree)) {
|
||||||
|
$this->tree[$notice->reply_to][] = $notice->id;
|
||||||
|
} else {
|
||||||
|
$this->tree[$notice->reply_to] = array($notice->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||||
|
$this->out->element('h2', null, _('Notices'));
|
||||||
|
$this->out->elementStart('ol', array('class' => 'notices xoxo'));
|
||||||
|
|
||||||
|
if (array_key_exists('root', $this->tree)) {
|
||||||
|
$rootid = $this->tree['root'][0];
|
||||||
|
$this->showNoticePlus($rootid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ol');
|
||||||
|
$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('ol', array('class' => 'notices'));
|
||||||
|
|
||||||
|
foreach ($children as $child) {
|
||||||
|
$this->showNoticePlus($child);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ol');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override parent class to return our preferred item.
|
||||||
|
*
|
||||||
|
* @param Notice $notice Notice to display
|
||||||
|
*
|
||||||
|
* @return NoticeListItem a list item to show
|
||||||
|
*/
|
||||||
|
|
||||||
|
function newListItem($notice)
|
||||||
|
{
|
||||||
|
return new ConversationTreeItem($notice, $this->out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation tree list item
|
||||||
|
*
|
||||||
|
* Special class of NoticeListItem for use inside conversation trees.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ConversationTreeItem extends NoticeListItem
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* start a single notice.
|
||||||
|
*
|
||||||
|
* The default creates the <li>; we skip, since the ConversationTree
|
||||||
|
* takes care of that.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showStart()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finish the notice
|
||||||
|
*
|
||||||
|
* The default closes the <li>; we skip, since the ConversationTree
|
||||||
|
* takes care of that.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showEnd()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show link to notice conversation page
|
||||||
|
*
|
||||||
|
* Since we're only used on the conversation page, we skip this
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContext()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -112,8 +112,8 @@ class DeletenoticeAction extends DeleteAction
|
|||||||
$this->hidden('token', common_session_token());
|
$this->hidden('token', common_session_token());
|
||||||
$this->hidden('notice', $this->trimmed('notice'));
|
$this->hidden('notice', $this->trimmed('notice'));
|
||||||
$this->element('p', null, _('Are you sure you want to delete this notice?'));
|
$this->element('p', null, _('Are you sure you want to delete this notice?'));
|
||||||
$this->submit('form_action-yes', _('Yes'), 'submit form_action-primary', 'yes');
|
$this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not delete this notice"));
|
||||||
$this->submit('form_action-no', _('No'), 'submit form_action-secondary', 'no');
|
$this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Delete this notice'));
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
$this->elementStart('form', array('method' => 'POST',
|
$this->elementStart('form', array('method' => 'post',
|
||||||
'id' => 'form_settings_design',
|
'id' => 'form_settings_design',
|
||||||
'class' => 'form_settings',
|
'class' => 'form_settings',
|
||||||
'action' =>
|
'action' =>
|
||||||
@ -82,7 +82,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
$this->element('legend', null, _('Change background image'));
|
$this->element('legend', null, _('Change background image'));
|
||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li');
|
$this->elementStart('li');
|
||||||
$this->element('label', array('for' => 'design_ background-image_file'),
|
$this->element('label', array('for' => 'design_background-image_file'),
|
||||||
_('Upload file'));
|
_('Upload file'));
|
||||||
$this->element('input', array('name' => 'design_background-image_file',
|
$this->element('input', array('name' => 'design_background-image_file',
|
||||||
'type' => 'file',
|
'type' => 'file',
|
||||||
@ -140,10 +140,12 @@ class DesignsettingsAction extends AccountSettingsAction
|
|||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
|
|
||||||
$this->submit('save', _('Save'));
|
$this->element('input', array('id' => 'settings_design_reset',
|
||||||
$this->element('input', array('type' => 'reset',
|
'type' => 'reset',
|
||||||
'value' => 'Reset',
|
'value' => 'Reset',
|
||||||
'class' => 'form_action-secondary'));
|
'class' => 'submit form_action-primary',
|
||||||
|
'title' => _('Reset back to default')));
|
||||||
|
$this->submit('save', _('Save'), 'submit form_action-secondary', 'save', _('Save design'));
|
||||||
|
|
||||||
/*TODO: Check submitted form values:
|
/*TODO: Check submitted form values:
|
||||||
json_encode(form values)
|
json_encode(form values)
|
||||||
|
@ -115,7 +115,7 @@ class FacebookhomeAction extends FacebookAction
|
|||||||
$flink->foreign_id = $this->fbuid;
|
$flink->foreign_id = $this->fbuid;
|
||||||
$flink->service = FACEBOOK_SERVICE;
|
$flink->service = FACEBOOK_SERVICE;
|
||||||
$flink->created = common_sql_now();
|
$flink->created = common_sql_now();
|
||||||
$flink->set_flags(true, false, false);
|
$flink->set_flags(true, false, false, false);
|
||||||
|
|
||||||
$flink_id = $flink->insert();
|
$flink_id = $flink->insert();
|
||||||
|
|
||||||
@ -138,9 +138,6 @@ class FacebookhomeAction extends FacebookAction
|
|||||||
|
|
||||||
function setDefaults()
|
function setDefaults()
|
||||||
{
|
{
|
||||||
// A default prefix string for notices
|
|
||||||
$this->facebook->api_client->data_setUserPreference(
|
|
||||||
FACEBOOK_NOTICE_PREFIX, 'dented: ');
|
|
||||||
$this->facebook->api_client->data_setUserPreference(
|
$this->facebook->api_client->data_setUserPreference(
|
||||||
FACEBOOK_PROMPTED_UPDATE_PREF, 'false');
|
FACEBOOK_PROMPTED_UPDATE_PREF, 'false');
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('LACONICA')) { exit(1); }
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/facebookaction.php');
|
require_once(INSTALLDIR.'/lib/facebookaction.php');
|
||||||
|
|
||||||
@ -89,16 +91,6 @@ class FacebookinviteAction extends FacebookAction
|
|||||||
|
|
||||||
function showFormContent()
|
function showFormContent()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Get a list of users who are already using the app for exclusion
|
|
||||||
$exclude_ids = $this->facebook->api_client->friends_getAppUsers();
|
|
||||||
$exclude_ids_csv = null;
|
|
||||||
|
|
||||||
// fbml needs these as a csv string, not an array
|
|
||||||
if ($exclude_ids) {
|
|
||||||
$exclude_ids_csv = implode(',', $exclude_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) .
|
$content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) .
|
||||||
htmlentities('<fb:req-choice url="' . $this->app_uri . '" label="Add"/>');
|
htmlentities('<fb:req-choice url="' . $this->app_uri . '" label="Add"/>');
|
||||||
|
|
||||||
@ -112,30 +104,37 @@ class FacebookinviteAction extends FacebookAction
|
|||||||
|
|
||||||
$multi_params = array('showborder' => 'false');
|
$multi_params = array('showborder' => 'false');
|
||||||
$multi_params['actiontext'] = $actiontext;
|
$multi_params['actiontext'] = $actiontext;
|
||||||
|
$multi_params['bypass'] = 'cancel';
|
||||||
|
|
||||||
if ($exclude_ids_csv) {
|
// Get a list of users who are already using the app for exclusion
|
||||||
|
$exclude_ids = $this->facebook->api_client->friends_getAppUsers();
|
||||||
|
$exclude_ids_csv = null;
|
||||||
|
|
||||||
|
// fbml needs these as a csv string, not an array
|
||||||
|
if ($exclude_ids) {
|
||||||
|
$exclude_ids_csv = implode(',', $exclude_ids);
|
||||||
$multi_params['exclude_ids'] = $exclude_ids_csv;
|
$multi_params['exclude_ids'] = $exclude_ids_csv;
|
||||||
}
|
}
|
||||||
|
|
||||||
$multi_params['bypass'] = 'cancel';
|
|
||||||
|
|
||||||
$this->element('fb:multi-friend-selector', $multi_params);
|
$this->element('fb:multi-friend-selector', $multi_params);
|
||||||
|
|
||||||
$this->elementEnd('fb:request-form');
|
$this->elementEnd('fb:request-form');
|
||||||
|
|
||||||
$this->element('h2', null, sprintf(_('Friends already using %s:'),
|
if ($exclude_ids) {
|
||||||
common_config('site', 'name')));
|
|
||||||
$this->elementStart('ul', array('id' => 'facebook-friends'));
|
|
||||||
|
|
||||||
foreach ($exclude_ids as $friend) {
|
$this->element('h2', null, sprintf(_('Friends already using %s:'),
|
||||||
$this->elementStart('li');
|
common_config('site', 'name')));
|
||||||
$this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square'));
|
$this->elementStart('ul', array('id' => 'facebook-friends'));
|
||||||
$this->element('fb:name', array('uid' => $friend,
|
|
||||||
'capitalize' => 'true'));
|
foreach ($exclude_ids as $friend) {
|
||||||
$this->elementEnd('li');
|
$this->elementStart('li');
|
||||||
|
$this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square'));
|
||||||
|
$this->element('fb:name', array('uid' => $friend,
|
||||||
|
'capitalize' => 'true'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd("ul");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->elementEnd("ul");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
|
@ -55,7 +55,7 @@ class FacebooksettingsAction extends FacebookAction
|
|||||||
$prefix = $this->trimmed('prefix');
|
$prefix = $this->trimmed('prefix');
|
||||||
|
|
||||||
$original = clone($this->flink);
|
$original = clone($this->flink);
|
||||||
$this->flink->set_flags($noticesync, $replysync, false);
|
$this->flink->set_flags($noticesync, $replysync, false, false);
|
||||||
$result = $this->flink->update($original);
|
$result = $this->flink->update($original);
|
||||||
|
|
||||||
$this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX,
|
$this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX,
|
||||||
|
40
actions/file.php
Normal file
40
actions/file.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?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.'/actions/shownotice.php');
|
||||||
|
|
||||||
|
class FileAction extends ShowNoticeAction
|
||||||
|
{
|
||||||
|
function showPage() {
|
||||||
|
$source_url = common_local_url('file', array('notice' => $this->notice->id));
|
||||||
|
$query = "select file_redirection.url as url from file join file_redirection on file.id = file_redirection.file_id where file.url = '$source_url'";
|
||||||
|
$file = new File_redirection;
|
||||||
|
$file->query($query);
|
||||||
|
$file->fetch();
|
||||||
|
if (empty($file->url)) {
|
||||||
|
die('nothing attached here');
|
||||||
|
} else {
|
||||||
|
header("Location: {$file->url}");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -84,20 +84,24 @@ class NewnoticeAction extends Action
|
|||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
|
||||||
|
|
||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
$this->clientError(_('Not logged in.'));
|
$this->clientError(_('Not logged in.'));
|
||||||
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
// check for this before token since all POST and FILES data
|
||||||
|
// is losts when size is exceeded
|
||||||
|
if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) {
|
||||||
|
$this->clientError(sprintf(_('The server was unable to handle ' .
|
||||||
|
'that much POST data (%s bytes) due to its current configuration.'),
|
||||||
|
$_SERVER['CONTENT_LENGTH']));
|
||||||
|
}
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
// CSRF protection
|
// CSRF protection
|
||||||
$token = $this->trimmed('token');
|
$token = $this->trimmed('token');
|
||||||
if (!$token || $token != common_session_token()) {
|
if (!$token || $token != common_session_token()) {
|
||||||
$this->clientError(_('There was a problem with your session token. '.
|
$this->clientError(_('There was a problem with your session token. '.
|
||||||
'Try again, please.'));
|
'Try again, please.'));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->saveNewNotice();
|
$this->saveNewNotice();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@ -109,6 +113,30 @@ class NewnoticeAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUploadedFileType() {
|
||||||
|
require_once 'MIME/Type.php';
|
||||||
|
|
||||||
|
$filetype = MIME_Type::autoDetect($_FILES['attach']['tmp_name']);
|
||||||
|
if (in_array($filetype, common_config('attachments', 'supported'))) {
|
||||||
|
return $filetype;
|
||||||
|
}
|
||||||
|
$media = MIME_Type::getMedia($filetype);
|
||||||
|
if ('application' !== $media) {
|
||||||
|
$hint = sprintf(_(' Try using another %s format.'), $media);
|
||||||
|
} else {
|
||||||
|
$hint = '';
|
||||||
|
}
|
||||||
|
$this->clientError(sprintf(
|
||||||
|
_('%s is not a supported filetype on this server.'), $filetype) . $hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRespectsQuota($user) {
|
||||||
|
$file = new File;
|
||||||
|
$ret = $file->isRespectsQuota($user);
|
||||||
|
if (true === $ret) return true;
|
||||||
|
$this->clientError($ret);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a new notice, based on arguments
|
* Save a new notice, based on arguments
|
||||||
*
|
*
|
||||||
@ -131,7 +159,6 @@ class NewnoticeAction extends Action
|
|||||||
$this->clientError(_('No content!'));
|
$this->clientError(_('No content!'));
|
||||||
} else {
|
} else {
|
||||||
$content_shortened = common_shorten_links($content);
|
$content_shortened = common_shorten_links($content);
|
||||||
|
|
||||||
if (mb_strlen($content_shortened) > 140) {
|
if (mb_strlen($content_shortened) > 140) {
|
||||||
$this->clientError(_('That\'s too long. '.
|
$this->clientError(_('That\'s too long. '.
|
||||||
'Max notice size is 140 chars.'));
|
'Max notice size is 140 chars.'));
|
||||||
@ -158,17 +185,53 @@ class NewnoticeAction extends Action
|
|||||||
$replyto = 'false';
|
$replyto = 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
// $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
if (isset($_FILES['attach']['error'])) {
|
||||||
|
switch ($_FILES['attach']['error']) {
|
||||||
|
case UPLOAD_ERR_NO_FILE:
|
||||||
|
// no file uploaded, nothing to do
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UPLOAD_ERR_OK:
|
||||||
|
$mimetype = $this->getUploadedFileType();
|
||||||
|
if (!$this->isRespectsQuota($user)) {
|
||||||
|
die('clientError() should trigger an exception before reaching here.');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UPLOAD_ERR_INI_SIZE:
|
||||||
|
$this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_FORM_SIZE:
|
||||||
|
$this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_PARTIAL:
|
||||||
|
$this->clientError(_('The uploaded file was only partially uploaded.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_NO_TMP_DIR:
|
||||||
|
$this->clientError(_('Missing a temporary folder.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_CANT_WRITE:
|
||||||
|
$this->clientError(_('Failed to write file to disk.'));
|
||||||
|
|
||||||
|
case UPLOAD_ERR_EXTENSION:
|
||||||
|
$this->clientError(_('File upload stopped by extension.'));
|
||||||
|
|
||||||
|
default:
|
||||||
|
die('Should never reach here.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
||||||
($replyto == 'false') ? null : $replyto);
|
($replyto == 'false') ? null : $replyto);
|
||||||
|
|
||||||
if (is_string($notice)) {
|
if (is_string($notice)) {
|
||||||
$this->clientError($notice);
|
$this->clientError($notice);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($mimetype)) {
|
||||||
|
$this->storeFile($notice, $mimetype);
|
||||||
|
}
|
||||||
$this->saveUrls($notice);
|
$this->saveUrls($notice);
|
||||||
|
|
||||||
common_broadcast_notice($notice);
|
common_broadcast_notice($notice);
|
||||||
|
|
||||||
if ($this->boolean('ajax')) {
|
if ($this->boolean('ajax')) {
|
||||||
@ -194,6 +257,33 @@ class NewnoticeAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function storeFile($notice, $mimetype) {
|
||||||
|
$filename = basename($_FILES['attach']['name']);
|
||||||
|
$destination = "file/{$notice->id}-$filename";
|
||||||
|
if (move_uploaded_file($_FILES['attach']['tmp_name'], INSTALLDIR . "/$destination")) {
|
||||||
|
$file = new File;
|
||||||
|
$file->url = common_local_url('file', array('notice' => $notice->id));
|
||||||
|
$file->size = filesize(INSTALLDIR . "/$destination");
|
||||||
|
$file->date = time();
|
||||||
|
$file->mimetype = $mimetype;
|
||||||
|
if ($file_id = $file->insert()) {
|
||||||
|
$file_redir = new File_redirection;
|
||||||
|
$file_redir->url = common_path($destination);
|
||||||
|
$file_redir->file_id = $file_id;
|
||||||
|
$file_redir->insert();
|
||||||
|
|
||||||
|
$f2p = new File_to_post;
|
||||||
|
$f2p->file_id = $file_id;
|
||||||
|
$f2p->post_id = $notice->id;
|
||||||
|
$f2p->insert();
|
||||||
|
} else {
|
||||||
|
$this->clientError(_('There was a database error while saving your file. Please try again.'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->clientError(_('File could not be moved to destination directory.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** save all urls in the notice to the db
|
/** save all urls in the notice to the db
|
||||||
*
|
*
|
||||||
* follow redirects and save all available file information
|
* follow redirects and save all available file information
|
||||||
@ -203,7 +293,7 @@ class NewnoticeAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function saveUrls($notice) {
|
function saveUrls($notice, $uploaded = null) {
|
||||||
common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id);
|
common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,3 +406,4 @@ class NewnoticeAction extends Action
|
|||||||
$nli->show();
|
$nli->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,10 +208,10 @@ class ShownoticeAction extends Action
|
|||||||
|
|
||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$this->elementStart('ul', array('class' => 'notices'));
|
$this->elementStart('ol', array('class' => 'notices xoxo'));
|
||||||
$nli = new NoticeListItem($this->notice, $this);
|
$nli = new NoticeListItem($this->notice, $this);
|
||||||
$nli->show();
|
$nli->show();
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ol');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,8 +49,6 @@ class TagAction extends Action
|
|||||||
{
|
{
|
||||||
$pop = new PopularNoticeSection($this);
|
$pop = new PopularNoticeSection($this);
|
||||||
$pop->show();
|
$pop->show();
|
||||||
$freqatt = new FrequentAttachmentSection($this);
|
|
||||||
$freqatt->show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
|
@ -120,4 +120,30 @@ class File extends Memcached_DataObject
|
|||||||
File_to_post::processNew($file_id, $notice_id);
|
File_to_post::processNew($file_id, $notice_id);
|
||||||
return $x;
|
return $x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isRespectsQuota($user) {
|
||||||
|
if ($_FILES['attach']['size'] > common_config('attachments', 'file_quota')) {
|
||||||
|
return sprintf(_('No file may be larger than %d bytes ' .
|
||||||
|
'and the file you sent was %d bytes. Try to upload a smaller version.'),
|
||||||
|
common_config('attachments', 'file_quota'), $_FILES['attach']['size']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "select sum(size) as total from file join file_to_post on file_to_post.file_id = file.id join notice on file_to_post.post_id = notice.id where profile_id = {$user->id} and file.url like '%/notice/%/file'";
|
||||||
|
$this->query($query);
|
||||||
|
$this->fetch();
|
||||||
|
$total = $this->total + $_FILES['attach']['size'];
|
||||||
|
if ($total > common_config('attachments', 'user_quota')) {
|
||||||
|
return sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= ' month(modified) = month(now()) and year(modified) = year(now())';
|
||||||
|
$this->query($query);
|
||||||
|
$this->fetch();
|
||||||
|
$total = $this->total + $_FILES['attach']['size'];
|
||||||
|
if ($total > common_config('attachments', 'monthly_quota')) {
|
||||||
|
return sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota'));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ class File_redirection extends Memcached_DataObject
|
|||||||
$file->limit(1);
|
$file->limit(1);
|
||||||
$file->orderBy('len');
|
$file->orderBy('len');
|
||||||
$file->find(true);
|
$file->find(true);
|
||||||
if (!empty($file->id)) {
|
if (!empty($file->url) && (strlen($file->url) < strlen($long_url))) {
|
||||||
return $file->url;
|
return $file->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class Foreign_link extends Memcached_DataObject
|
|||||||
|
|
||||||
public $__table = 'foreign_link'; // table name
|
public $__table = 'foreign_link'; // table name
|
||||||
public $user_id; // int(4) primary_key not_null
|
public $user_id; // int(4) primary_key not_null
|
||||||
public $foreign_id; // int(4) primary_key not_null
|
public $foreign_id; // bigint(8) primary_key not_null unsigned
|
||||||
public $service; // int(4) primary_key not_null
|
public $service; // int(4) primary_key not_null
|
||||||
public $credentials; // varchar(255)
|
public $credentials; // varchar(255)
|
||||||
public $noticesync; // tinyint(1) not_null default_1
|
public $noticesync; // tinyint(1) not_null default_1
|
||||||
|
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
@ -227,4 +227,22 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
$c->set($ckey, $cached, MEMCACHE_COMPRESSED, $expiry);
|
$c->set($ckey, $cached, MEMCACHE_COMPRESSED, $expiry);
|
||||||
return new ArrayWrapper($cached);
|
return new ArrayWrapper($cached);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We overload so that 'SET NAMES "utf8"' is called for
|
||||||
|
// each connection
|
||||||
|
|
||||||
|
function _connect()
|
||||||
|
{
|
||||||
|
global $_DB_DATAOBJECT;
|
||||||
|
$exists = !empty($this->_database_dsn_md5) &&
|
||||||
|
isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]);
|
||||||
|
$result = parent::_connect();
|
||||||
|
if (!$exists) {
|
||||||
|
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
|
||||||
|
if (common_config('db', 'utf8')) {
|
||||||
|
$DB->query('SET NAMES "utf8"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,6 +277,18 @@ class Notice extends Memcached_DataObject
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUploadedAttachment() {
|
||||||
|
$post = clone $this;
|
||||||
|
$query = 'select file.url as uploaded from file join file_to_post on file.id = file_id where post_id=' . $post->escape($post->id) . ' and url like "%/notice/%/file"';
|
||||||
|
$post->query($query);
|
||||||
|
$post->fetch();
|
||||||
|
$ret = $post->uploaded;
|
||||||
|
// var_dump($post);
|
||||||
|
$post->free();
|
||||||
|
// die();
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
function hasAttachments() {
|
function hasAttachments() {
|
||||||
$post = clone $this;
|
$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);
|
$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);
|
||||||
|
0
classes/Related_group.php
Executable file → Normal file
0
classes/Related_group.php
Executable file → Normal file
0
classes/Status_network.php
Executable file → Normal file
0
classes/Status_network.php
Executable file → Normal file
0
classes/User_group.php
Executable file → Normal file
0
classes/User_group.php
Executable file → Normal file
@ -46,6 +46,64 @@ modified = 384
|
|||||||
notice_id = K
|
notice_id = K
|
||||||
user_id = K
|
user_id = K
|
||||||
|
|
||||||
|
[file]
|
||||||
|
id = 129
|
||||||
|
url = 2
|
||||||
|
mimetype = 2
|
||||||
|
size = 1
|
||||||
|
title = 2
|
||||||
|
date = 1
|
||||||
|
protected = 1
|
||||||
|
|
||||||
|
[file__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[file_oembed]
|
||||||
|
id = 129
|
||||||
|
file_id = 1
|
||||||
|
version = 2
|
||||||
|
type = 2
|
||||||
|
provider = 2
|
||||||
|
provider_url = 2
|
||||||
|
width = 1
|
||||||
|
height = 1
|
||||||
|
html = 34
|
||||||
|
title = 2
|
||||||
|
author_name = 2
|
||||||
|
author_url = 2
|
||||||
|
url = 2
|
||||||
|
|
||||||
|
[file_oembed__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[file_redirection]
|
||||||
|
id = 129
|
||||||
|
url = 2
|
||||||
|
file_id = 1
|
||||||
|
redirections = 1
|
||||||
|
httpcode = 1
|
||||||
|
|
||||||
|
[file_redirection__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[file_thumbnail]
|
||||||
|
id = 129
|
||||||
|
file_id = 1
|
||||||
|
url = 2
|
||||||
|
width = 1
|
||||||
|
height = 1
|
||||||
|
|
||||||
|
[file_thumbnail__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
|
[file_to_post]
|
||||||
|
id = 129
|
||||||
|
file_id = 1
|
||||||
|
post_id = 1
|
||||||
|
|
||||||
|
[file_to_post__keys]
|
||||||
|
id = N
|
||||||
|
|
||||||
[foreign_link]
|
[foreign_link]
|
||||||
user_id = 129
|
user_id = 129
|
||||||
foreign_id = 129
|
foreign_id = 129
|
||||||
@ -392,63 +450,3 @@ modified = 384
|
|||||||
[user_openid__keys]
|
[user_openid__keys]
|
||||||
canonical = K
|
canonical = K
|
||||||
display = U
|
display = U
|
||||||
|
|
||||||
[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 = 129
|
|
||||||
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 = 129
|
|
||||||
redirections = 1
|
|
||||||
httpcode = 1
|
|
||||||
|
|
||||||
[file_redirection__keys]
|
|
||||||
id = N
|
|
||||||
|
|
||||||
[file_thumbnail]
|
|
||||||
id = 129
|
|
||||||
file_id = 129
|
|
||||||
url = 2
|
|
||||||
width = 1
|
|
||||||
height = 1
|
|
||||||
|
|
||||||
[file_thumbnail__keys]
|
|
||||||
id = N
|
|
||||||
|
|
||||||
[file_to_post]
|
|
||||||
id = 129
|
|
||||||
file_id = 129
|
|
||||||
post_id = 129
|
|
||||||
|
|
||||||
[file_to_post__keys]
|
|
||||||
id = N
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,219 +3,223 @@
|
|||||||
|
|
||||||
if (!defined('LACONICA')) { exit(1); }
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
#If you have downloaded libraries in random little places, you
|
// If you have downloaded libraries in random little places, you
|
||||||
#can add the paths here
|
// can add the paths here
|
||||||
|
|
||||||
#$extra_path = array("/opt/php-openid-2.0.1", "/usr/local/share/php");
|
// $extra_path = array("/opt/php-openid-2.0.1", "/usr/local/share/php");
|
||||||
#set_include_path(implode(PATH_SEPARATOR, $extra_path) . PATH_SEPARATOR . get_include_path());
|
// set_include_path(implode(PATH_SEPARATOR, $extra_path) . PATH_SEPARATOR . get_include_path());
|
||||||
|
|
||||||
# We get called by common.php, $config is a tree with lots of config
|
// We get called by common.php, $config is a tree with lots of config
|
||||||
# options
|
// options
|
||||||
# These are for configuring your URLs
|
// These are for configuring your URLs
|
||||||
|
|
||||||
$config['site']['name'] = 'Just another Laconica microblog';
|
$config['site']['name'] = 'Just another Laconica microblog';
|
||||||
$config['site']['server'] = 'localhost';
|
$config['site']['server'] = 'localhost';
|
||||||
$config['site']['path'] = 'laconica';
|
$config['site']['path'] = 'laconica';
|
||||||
#$config['site']['fancy'] = false;
|
// $config['site']['fancy'] = false;
|
||||||
#$config['site']['theme'] = 'default';
|
// $config['site']['theme'] = 'default';
|
||||||
#To enable the built-in mobile style sheet, defaults to false.
|
// To enable the built-in mobile style sheet, defaults to false.
|
||||||
#$config['site']['mobile'] = true;
|
// $config['site']['mobile'] = true;
|
||||||
#For contact email, defaults to $_SERVER["SERVER_ADMIN"]
|
// For contact email, defaults to $_SERVER["SERVER_ADMIN"]
|
||||||
#$config['site']['email'] = 'admin@example.net';
|
// $config['site']['email'] = 'admin@example.net';
|
||||||
#Brought by...
|
// Brought by...
|
||||||
#$config['site']['broughtby'] = 'Individual or Company';
|
// $config['site']['broughtby'] = 'Individual or Company';
|
||||||
#$config['site']['broughtbyurl'] = 'http://example.net/';
|
// $config['site']['broughtbyurl'] = 'http://example.net/';
|
||||||
#If you don't want to let users register (say, for a one-person install)
|
// If you don't want to let users register (say, for a one-person install)
|
||||||
#Crude but effective -- register everybody, then lock down
|
// Crude but effective -- register everybody, then lock down
|
||||||
#$config['site']['closed'] = true;
|
// $config['site']['closed'] = true;
|
||||||
#Only allow registration for people invited by another user
|
// Only allow registration for people invited by another user
|
||||||
#$config['site']['inviteonly'] = true;
|
// $config['site']['inviteonly'] = true;
|
||||||
#Make the site invisible to non-logged-in users
|
// Make the site invisible to non-logged-in users
|
||||||
#$config['site']['private'] = true;
|
// $config['site']['private'] = true;
|
||||||
|
|
||||||
# 'direct' for direct notice links in sections
|
// If you want logging sent to a file instead of syslog
|
||||||
# 'attachment' for notice attachment links in sections
|
// $config['site']['logfile'] = '/tmp/laconica.log';
|
||||||
# left undefined, no link is showed
|
|
||||||
#$config['site']['notice_link'] = 'attachment';
|
|
||||||
#$config['site']['notice_link'] = 'direct';
|
|
||||||
|
|
||||||
# If you want logging sent to a file instead of syslog
|
// Enables extra log information, for example full details of PEAR DB errors
|
||||||
#$config['site']['logfile'] = '/tmp/laconica.log';
|
// $config['site']['logdebug'] = true;
|
||||||
|
|
||||||
# Enables extra log information, for example full details of PEAR DB errors
|
// To set your own logo, overriding the one in the theme
|
||||||
#$config['site']['logdebug'] = true;
|
// $config['site']['logo'] = '/mylogo.png';
|
||||||
|
|
||||||
#To set your own logo, overriding the one in the theme
|
// This is a PEAR DB DSN, see http://pear.php.net/manual/en/package.database.db.intro-dsn.php
|
||||||
#$config['site']['logo'] = '/mylogo.png';
|
// Set it to match your actual database
|
||||||
|
|
||||||
# This is a PEAR DB DSN, see http://pear.php.net/manual/en/package.database.db.intro-dsn.php
|
|
||||||
# Set it to match your actual database
|
|
||||||
|
|
||||||
$config['db']['database'] = 'mysql://laconica:microblog@localhost/laconica';
|
$config['db']['database'] = 'mysql://laconica:microblog@localhost/laconica';
|
||||||
#$config['db']['ini_your_db_name'] = $config['db']['schema_location'].'/laconica.ini';
|
// $config['db']['ini_your_db_name'] = $config['db']['schema_location'].'/laconica.ini';
|
||||||
# *** WARNING *** WARNING *** WARNING *** WARNING ***
|
// *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||||
# Setting debug to a non-zero value will expose your DATABASE PASSWORD to Web users.
|
// Setting debug to a non-zero value will expose your DATABASE PASSWORD to Web users.
|
||||||
# !!!!!! DO NOT SET THIS ON PRODUCTION SERVERS !!!!!! DB_DataObject's bug, btw, not
|
// !!!!!! DO NOT SET THIS ON PRODUCTION SERVERS !!!!!! DB_DataObject's bug, btw, not
|
||||||
# ours.
|
// ours.
|
||||||
# *** WARNING *** WARNING *** WARNING *** WARNING ***
|
// *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||||
#$config['db']['debug'] = 0;
|
// $config['db']['debug'] = 0;
|
||||||
#$config['db']['db_driver'] = 'MDB2';
|
// $config['db']['db_driver'] = 'MDB2';
|
||||||
|
|
||||||
#Database type. For mysql, these defaults are fine. For postgresql, set
|
// Database type. For mysql, these defaults are fine. For postgresql, set
|
||||||
#'quote_identifiers' to true and 'type' to 'pgsql':
|
// 'quote_identifiers' to true and 'type' to 'pgsql':
|
||||||
#$config['db']['quote_identifiers'] = false;
|
// $config['db']['quote_identifiers'] = false;
|
||||||
#$config['db']['type'] = 'mysql';
|
// $config['db']['type'] = 'mysql';
|
||||||
|
|
||||||
#session_set_cookie_params(0, '/'. $config['site']['path'] .'/');
|
// session_set_cookie_params(0, '/'. $config['site']['path'] .'/');
|
||||||
|
|
||||||
#Standard fancy-url clashes prevented by not allowing nicknames on a blacklist
|
// Standard fancy-url clashes prevented by not allowing nicknames on a blacklist
|
||||||
#Add your own here. Note: empty array by default
|
// Add your own here. Note: empty array by default
|
||||||
#$config['nickname']['blacklist'][] = 'scobleizer';
|
// $config['nickname']['blacklist'][] = 'scobleizer';
|
||||||
|
|
||||||
# sphinx search
|
// sphinx search
|
||||||
$config['sphinx']['enabled'] = false;
|
$config['sphinx']['enabled'] = false;
|
||||||
$config['sphinx']['server'] = 'localhost';
|
$config['sphinx']['server'] = 'localhost';
|
||||||
$config['sphinx']['port'] = 3312;
|
$config['sphinx']['port'] = 3312;
|
||||||
|
|
||||||
# Users to populate the 'Featured' tab
|
// Users to populate the 'Featured' tab
|
||||||
#$config['nickname']['featured'][] = 'scobleizer';
|
// $config['nickname']['featured'][] = 'scobleizer';
|
||||||
|
|
||||||
# xmpp
|
// xmpp
|
||||||
#$config['xmpp']['enabled'] = false;
|
// $config['xmpp']['enabled'] = false;
|
||||||
#$config['xmpp']['server'] = 'server.example.net';
|
// $config['xmpp']['server'] = 'server.example.net';
|
||||||
#$config['xmpp']['host'] = NULL; # Only set if different from server
|
// $config['xmpp']['host'] = NULL; // Only set if different from server
|
||||||
#$config['xmpp']['port'] = 5222;
|
// $config['xmpp']['port'] = 5222;
|
||||||
#$config['xmpp']['user'] = 'update';
|
// $config['xmpp']['user'] = 'update';
|
||||||
#$config['xmpp']['encryption'] = false;
|
// $config['xmpp']['encryption'] = false;
|
||||||
#$config['xmpp']['resource'] = 'uniquename';
|
// $config['xmpp']['resource'] = 'uniquename';
|
||||||
#$config['xmpp']['password'] = 'blahblahblah';
|
// $config['xmpp']['password'] = 'blahblahblah';
|
||||||
#$config['xmpp']['public'][] = 'someindexer@example.net';
|
// $config['xmpp']['public'][] = 'someindexer@example.net';
|
||||||
#$config['xmpp']['debug'] = false;
|
// $config['xmpp']['debug'] = false;
|
||||||
|
|
||||||
#Default locale info
|
// Default locale info
|
||||||
#$config['site']['timezone'] = 'Pacific/Auckland';
|
// $config['site']['timezone'] = 'Pacific/Auckland';
|
||||||
#$config['site']['language'] = 'en_NZ';
|
// $config['site']['language'] = 'en_NZ';
|
||||||
|
|
||||||
#Email info, used for all outbound email
|
// Email info, used for all outbound email
|
||||||
#$config['mail']['notifyfrom'] = 'microblog@example.net';
|
// $config['mail']['notifyfrom'] = 'microblog@example.net';
|
||||||
#$config['mail']['domain'] = 'microblog.example.net';
|
// $config['mail']['domain'] = 'microblog.example.net';
|
||||||
# See http://pear.php.net/manual/en/package.mail.mail.factory.php for options
|
// See http://pear.php.net/manual/en/package.mail.mail.factory.php for options
|
||||||
#$config['mail']['backend'] = 'smtp';
|
// $config['mail']['backend'] = 'smtp';
|
||||||
#$config['mail']['params'] = array(
|
// $config['mail']['params'] = array(
|
||||||
# 'host' => 'localhost',
|
// 'host' => 'localhost',
|
||||||
# 'port' => 25,
|
// 'port' => 25,
|
||||||
# );
|
// );
|
||||||
#For incoming email, if enabled. Defaults to site server name.
|
// For incoming email, if enabled. Defaults to site server name.
|
||||||
#$config['mail']['domain'] = 'incoming.example.net';
|
// $config['mail']['domain'] = 'incoming.example.net';
|
||||||
|
|
||||||
#exponential decay factor for tags, default 10 days
|
// exponential decay factor for tags, default 10 days
|
||||||
#raise this if traffic is slow, lower it if it's fast
|
// raise this if traffic is slow, lower it if it's fast
|
||||||
#$config['tag']['dropoff'] = 86400.0 * 10;
|
// $config['tag']['dropoff'] = 86400.0 * 10;
|
||||||
|
|
||||||
#exponential decay factor for popular (most favorited notices)
|
// exponential decay factor for popular (most favorited notices)
|
||||||
#default 10 days -- similar to tag dropoff
|
// default 10 days -- similar to tag dropoff
|
||||||
#$config['popular']['dropoff'] = 86400.0 * 10;
|
// $config['popular']['dropoff'] = 86400.0 * 10;
|
||||||
|
|
||||||
#optionally show non-local messages in public timeline
|
// optionally show non-local messages in public timeline
|
||||||
#$config['public']['localonly'] = false;
|
// $config['public']['localonly'] = false;
|
||||||
|
|
||||||
#hide certain users from public pages, by ID
|
// hide certain users from public pages, by ID
|
||||||
#$config['public']['blacklist'][] = 123;
|
// $config['public']['blacklist'][] = 123;
|
||||||
#$config['public']['blacklist'][] = 2307;
|
// $config['public']['blacklist'][] = 2307;
|
||||||
|
|
||||||
#Mark certain notice sources as automatic and thus not
|
// Mark certain notice sources as automatic and thus not
|
||||||
#appropriate for public feed
|
// appropriate for public feed
|
||||||
#$config['public]['autosource'][] = 'twitterfeed';
|
// $config['public]['autosource'][] = 'twitterfeed';
|
||||||
#$config['public]['autosource'][] = 'rssdent';
|
// $config['public]['autosource'][] = 'rssdent';
|
||||||
#$config['public]['autosource'][] = 'Ping.Fm';
|
// $config['public]['autosource'][] = 'Ping.Fm';
|
||||||
#$config['public]['autosource'][] = 'HelloTxt';
|
// $config['public]['autosource'][] = 'HelloTxt';
|
||||||
#$config['public]['autosource'][] = 'Updating.Me';
|
// $config['public]['autosource'][] = 'Updating.Me';
|
||||||
|
|
||||||
#Do notice broadcasts offline
|
// Do notice broadcasts offline
|
||||||
#If you use this, you must run the six offline daemons in the
|
// If you use this, you must run the six offline daemons in the
|
||||||
#background. See the README for details.
|
// background. See the README for details.
|
||||||
#$config['queue']['enabled'] = true;
|
// $config['queue']['enabled'] = true;
|
||||||
|
|
||||||
#Queue subsystem
|
// Queue subsystem
|
||||||
#subsystems: internal (default) or stomp
|
// subsystems: internal (default) or stomp
|
||||||
#using stomp requires an external message queue server
|
// using stomp requires an external message queue server
|
||||||
#$config['queue']['subsystem'] = 'stomp';
|
// $config['queue']['subsystem'] = 'stomp';
|
||||||
#$config['queue']['stomp_server'] = 'tcp://localhost:61613';
|
// $config['queue']['stomp_server'] = 'tcp://localhost:61613';
|
||||||
#use different queue_basename for each laconica instance managed by the server
|
// use different queue_basename for each laconica instance managed by the server
|
||||||
#$config['queue']['queue_basename'] = 'laconica';
|
// $config['queue']['queue_basename'] = 'laconica';
|
||||||
|
|
||||||
#The following customise the behaviour of the various daemons:
|
// The following customise the behaviour of the various daemons:
|
||||||
#$config['daemon']['piddir'] = '/var/run';
|
// $config['daemon']['piddir'] = '/var/run';
|
||||||
#$config['daemon']['user'] = false;
|
// $config['daemon']['user'] = false;
|
||||||
#$config['daemon']['group'] = false;
|
// $config['daemon']['group'] = false;
|
||||||
|
|
||||||
#For installations with high traffic, laconica can use MemCached to cache
|
// For installations with high traffic, laconica can use MemCached to cache
|
||||||
#frequently requested information. Only enable the following if you have
|
// frequently requested information. Only enable the following if you have
|
||||||
#MemCached up and running:
|
// MemCached up and running:
|
||||||
#$config['memcached']['enabled'] = false;
|
// $config['memcached']['enabled'] = false;
|
||||||
#$config['memcached']['server'] = 'localhost';
|
// $config['memcached']['server'] = 'localhost';
|
||||||
#$config['memcached']['port'] = 11211;
|
// $config['memcached']['port'] = 11211;
|
||||||
|
|
||||||
# Enable bidirectional Twitter bridge
|
// Twitter integration source attribute. Note: default is Laconica
|
||||||
#$config['twitterbridge']['enabled'] = true;
|
// $config['integration']['source'] = 'Laconica';
|
||||||
|
|
||||||
#Twitter integration source attribute. Note: default is Laconica
|
// Edit throttling. Off by default. If turned on, you can only post 20 notices
|
||||||
#$config['integration']['source'] = 'Laconica';
|
// every 10 minutes. Admins may want to play with the settings to minimize inconvenience for
|
||||||
|
// real users without getting uncontrollable floods from spammers or runaway bots.
|
||||||
|
|
||||||
# Edit throttling. Off by default. If turned on, you can only post 20 notices
|
// $config['throttle']['enabled'] = true;
|
||||||
# every 10 minutes. Admins may want to play with the settings to minimize inconvenience for
|
// $config['throttle']['count'] = 100;
|
||||||
# real users without getting uncontrollable floods from spammers or runaway bots.
|
// $config['throttle']['timespan'] = 3600;
|
||||||
|
|
||||||
#$config['throttle']['enabled'] = true;
|
// List of users banned from posting (nicknames and/or IDs)
|
||||||
#$config['throttle']['count'] = 100;
|
// $config['profile']['banned'][] = 'hacker';
|
||||||
#$config['throttle']['timespan'] = 3600;
|
// $config['profile']['banned'][] = 12345;
|
||||||
|
|
||||||
# List of users banned from posting (nicknames and/or IDs)
|
// Config section for the built-in Facebook application
|
||||||
#$config['profile']['banned'][] = 'hacker';
|
// $config['facebook']['apikey'] = 'APIKEY';
|
||||||
#$config['profile']['banned'][] = 12345;
|
// $config['facebook']['secret'] = 'SECRET';
|
||||||
|
|
||||||
# Config section for the built-in Facebook application
|
// Add Google Analytics
|
||||||
#$config['facebook']['apikey'] = 'APIKEY';
|
// require_once('plugins/GoogleAnalyticsPlugin.php');
|
||||||
#$config['facebook']['secret'] = 'SECRET';
|
// $ga = new GoogleAnalyticsPlugin('your secret code');
|
||||||
|
|
||||||
# Facebook Connect plugin (Needs valid APIKEY above)
|
// Use Templating (template: /tpl/index.php)
|
||||||
#require_once(INSTALLDIR.'/plugins/FBConnect/FBConnectPlugin.php');
|
// require_once('plugins/TemplatePlugin.php');
|
||||||
#$fbc = new FBConnectPlugin();
|
// $tpl = new TemplatePlugin();
|
||||||
|
|
||||||
# Add Google Analytics
|
// Don't allow saying the same thing more than once per hour
|
||||||
# require_once('plugins/GoogleAnalyticsPlugin.php');
|
// $config['site']['dupelimit'] = 3600;
|
||||||
# $ga = new GoogleAnalyticsPlugin('your secret code');
|
// Don't enforce the dupe limit
|
||||||
|
// $config['site']['dupelimit'] = -1;
|
||||||
|
|
||||||
# Use Templating (template: /tpl/index.php)
|
// Base string for minting Tag URIs in Atom feeds. Defaults to
|
||||||
# require_once('plugins/TemplatePlugin.php');
|
// "yourserver,2009". This needs to be configured properly for your Atom
|
||||||
# $tpl = new TemplatePlugin();
|
// feeds to validate. See: http://www.faqs.org/rfcs/rfc4151.html and
|
||||||
|
// http://taguri.org/ Examples:
|
||||||
|
// $config['integration']['taguri'] = 'example.net,2008';
|
||||||
|
// $config['integration']['taguri'] = 'admin@example.net,2009-03-09'
|
||||||
|
|
||||||
#Don't allow saying the same thing more than once per hour
|
// Don't use SSL
|
||||||
#$config['site']['dupelimit'] = 3600;
|
// $config['site']['ssl'] = 'never';
|
||||||
#Don't enforce the dupe limit
|
// Use SSL only for sensitive pages (like login, password change)
|
||||||
#$config['site']['dupelimit'] = -1;
|
// $config['site']['ssl'] = 'sometimes';
|
||||||
|
// Use SSL for all pages
|
||||||
|
// $config['site']['ssl'] = 'always';
|
||||||
|
|
||||||
#Base string for minting Tag URIs in Atom feeds. Defaults to
|
// Use a different hostname for SSL-encrypted pages
|
||||||
#"yourserver,2009". This needs to be configured properly for your Atom
|
// $config['site']['sslserver'] = 'secure.example.org';
|
||||||
#feeds to validate. See: http://www.faqs.org/rfcs/rfc4151.html and
|
|
||||||
#http://taguri.org/ Examples:
|
|
||||||
#$config['integration']['taguri'] = 'example.net,2008';
|
|
||||||
#$config['integration']['taguri'] = 'admin@example.net,2009-03-09'
|
|
||||||
|
|
||||||
#Don't use SSL
|
// If you have a lot of status networks on the same server, you can
|
||||||
#$config['site']['ssl'] = 'never';
|
// store the site data in a database and switch as follows
|
||||||
#Use SSL only for sensitive pages (like login, password change)
|
// Status_network::setupDB('localhost', 'statusnet', 'statuspass', 'statusnet');
|
||||||
#$config['site']['ssl'] = 'sometimes';
|
// if (!Status_network::setupSite($_server, $_path)) {
|
||||||
#Use SSL for all pages
|
// print "Error\n";
|
||||||
#$config['site']['ssl'] = 'always';
|
// exit(1);
|
||||||
|
// }
|
||||||
|
|
||||||
#Use a different hostname for SSL-encrypted pages
|
// How often to send snapshots; in # of web hits. Ideally,
|
||||||
#$config['site']['sslserver'] = 'secure.example.org';
|
// try to do this once per month (that is, make this equal to number
|
||||||
|
// of hits per month)
|
||||||
|
// $config['snapshot']['frequency'] = 10000;
|
||||||
|
// If you don't want to report statistics to the central server, uncomment.
|
||||||
|
// $config['snapshot']['run'] = 'never';
|
||||||
|
// If you want to report statistics in a cron job instead.
|
||||||
|
// $config['snapshot']['run'] = 'cron';
|
||||||
|
|
||||||
|
// Support for file uploads (attachments),
|
||||||
|
// select supported mimetypes and quotas (in bytes)
|
||||||
|
// $config['attachments']['supported'] = array('image/png', 'application/ogg');
|
||||||
|
// $config['attachments']['file_quota'] = 5000000;
|
||||||
|
// $config['attachments']['user_quota'] = 50000000;
|
||||||
|
// $config['attachments']['monthly_quota'] = 15000000;
|
||||||
|
|
||||||
#If you have a lot of status networks on the same server, you can
|
|
||||||
#store the site data in a database and switch as follows
|
|
||||||
#Status_network::setupDB('localhost', 'statusnet', 'statuspass', 'statusnet');
|
|
||||||
#if (!Status_network::setupSite($_server, $_path)) {
|
|
||||||
# print "Error\n";
|
|
||||||
# exit(1);
|
|
||||||
#}
|
|
||||||
|
@ -2,4 +2,5 @@ insert into foreign_service
|
|||||||
(id, name, description, created)
|
(id, name, description, created)
|
||||||
values
|
values
|
||||||
('1','Twitter', 'Twitter Micro-blogging service', now()),
|
('1','Twitter', 'Twitter Micro-blogging service', now()),
|
||||||
('2','Facebook', 'Facebook', now());
|
('2','Facebook', 'Facebook', now()),
|
||||||
|
('3','FacebookConnect', 'Facebook Connect', now());
|
||||||
|
@ -285,7 +285,7 @@ create table foreign_user (
|
|||||||
|
|
||||||
create table foreign_link (
|
create table foreign_link (
|
||||||
user_id int comment 'link to user on this system, if exists' references user (id),
|
user_id int comment 'link to user on this system, if exists' references user (id),
|
||||||
foreign_id int comment 'link ' references foreign_user(id),
|
foreign_id bigint unsigned comment 'link to user on foreign service, if exists' references foreign_user(id),
|
||||||
service int not null comment 'foreign key to service' references foreign_service(id),
|
service int not null comment 'foreign key to service' references foreign_service(id),
|
||||||
credentials varchar(255) comment 'authc credentials, typically a password',
|
credentials varchar(255) comment 'authc credentials, typically a password',
|
||||||
noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
|
noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
|
||||||
@ -482,5 +482,3 @@ create table file_to_post (
|
|||||||
|
|
||||||
unique(file_id, post_id)
|
unique(file_id, post_id)
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,13 +2,16 @@ INSERT INTO notice_source
|
|||||||
(code, name, url, created)
|
(code, name, url, created)
|
||||||
VALUES
|
VALUES
|
||||||
('adium', 'Adium', 'http://www.adiumx.com/', now()),
|
('adium', 'Adium', 'http://www.adiumx.com/', now()),
|
||||||
|
('AgentSolo.com','AgentSolo.com','http://www.agentsolo.com/', now()),
|
||||||
('betwittered','BeTwittered','http://www.32hours.com/betwitteredinfo/', now()),
|
('betwittered','BeTwittered','http://www.32hours.com/betwitteredinfo/', now()),
|
||||||
('bti','bti','http://gregkh.github.com/bti/', now()),
|
('bti','bti','http://gregkh.github.com/bti/', now()),
|
||||||
('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()),
|
('cliqset', 'Cliqset', 'http://www.cliqset.com/', now()),
|
||||||
('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()),
|
('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()),
|
||||||
('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()),
|
('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()),
|
||||||
|
('eventbox','EventBox','http://thecosmicmachine.com/eventbox/ ', now()),
|
||||||
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
|
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
|
||||||
('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
|
('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
|
||||||
|
('gravity', 'Gravity', 'http://mobileways.de/gravity', now()),
|
||||||
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
|
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
|
||||||
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
||||||
('identicatools','Laconica Tools','http://bitbucketlabs.net/laconica-tools/', now()),
|
('identicatools','Laconica Tools','http://bitbucketlabs.net/laconica-tools/', now()),
|
||||||
@ -27,6 +30,7 @@ VALUES
|
|||||||
('pingvine','PingVine','http://pingvine.com/', now()),
|
('pingvine','PingVine','http://pingvine.com/', now()),
|
||||||
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
||||||
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
||||||
|
('qtwitter','qTwitter','http://qtwitter.ayoy.net/', now()),
|
||||||
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
||||||
('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', now()),
|
('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', now()),
|
||||||
('rygh.no','rygh.no','http://rygh.no/', now()),
|
('rygh.no','rygh.no','http://rygh.no/', now()),
|
||||||
|
523
extlib/MIME/Type.php
Normal file
523
extlib/MIME/Type.php
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
<?php
|
||||||
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | PHP version 4 |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 1997-2002, 2008 The PHP Group |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | This source file is subject to version 3.0 of the PHP license, |
|
||||||
|
// | that is bundled with this package in the file LICENSE, and is |
|
||||||
|
// | available at through the world-wide-web at |
|
||||||
|
// | http://www.php.net/license/3_0.txt. |
|
||||||
|
// | If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
// | obtain it through the world-wide-web, please send a note to |
|
||||||
|
// | license@php.net so we can mail you a copy immediately. |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Authors: Ian Eure <ieure@php.net> |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Type.php,v 1.6 2009/01/16 11:49:45 cweiske Exp $
|
||||||
|
|
||||||
|
require_once 'PEAR.php';
|
||||||
|
|
||||||
|
$_fileCmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
|
||||||
|
$_fileCmd = 'file';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for working with MIME types
|
||||||
|
*
|
||||||
|
* @category MIME
|
||||||
|
* @package MIME_Type
|
||||||
|
* @license PHP License 3.0
|
||||||
|
* @version 1.2.0
|
||||||
|
* @link http://pear.php.net/package/MIME_Type
|
||||||
|
* @author Ian Eure <ieure@php.net>
|
||||||
|
*/
|
||||||
|
class MIME_Type
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The MIME media type
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $media = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MIME media sub-type
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $subType = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional MIME parameters
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
var $parameters = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of valid media types.
|
||||||
|
* A media type is the string in front of the slash.
|
||||||
|
* The media type of "text/xml" would be "text".
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
var $validMediaTypes = array(
|
||||||
|
'text',
|
||||||
|
'image',
|
||||||
|
'audio',
|
||||||
|
'video',
|
||||||
|
'application',
|
||||||
|
'multipart',
|
||||||
|
'message'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* If $type is set, if will be parsed and the appropriate class vars set.
|
||||||
|
* If not, you get an empty class.
|
||||||
|
* This is useful, but not quite as useful as parsing a type.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function MIME_Type($type = false)
|
||||||
|
{
|
||||||
|
if ($type) {
|
||||||
|
$this->parse($type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a mime-type and set the class variables.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to parse
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function parse($type)
|
||||||
|
{
|
||||||
|
$this->media = $this->getMedia($type);
|
||||||
|
$this->subType = $this->getSubType($type);
|
||||||
|
$this->parameters = array();
|
||||||
|
if (MIME_Type::hasParameters($type)) {
|
||||||
|
require_once 'MIME/Type/Parameter.php';
|
||||||
|
foreach (MIME_Type::getParameters($type) as $param) {
|
||||||
|
$param = new MIME_Type_Parameter($param);
|
||||||
|
$this->parameters[$param->name] = $param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this type have any parameters?
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if $type has parameters, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function hasParameters($type)
|
||||||
|
{
|
||||||
|
if (strstr($type, ';')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a MIME type's parameters
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to get parameters of
|
||||||
|
*
|
||||||
|
* @return array $type's parameters
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getParameters($type)
|
||||||
|
{
|
||||||
|
$params = array();
|
||||||
|
$tmp = explode(';', $type);
|
||||||
|
for ($i = 1; $i < count($tmp); $i++) {
|
||||||
|
$params[] = trim($tmp[$i]);
|
||||||
|
}
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip parameters from a MIME type string.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type string
|
||||||
|
*
|
||||||
|
* @return string MIME type with parameters removed
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function stripParameters($type)
|
||||||
|
{
|
||||||
|
if (strstr($type, ';')) {
|
||||||
|
return substr($type, 0, strpos($type, ';'));
|
||||||
|
}
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes comments from a media type, subtype or parameter.
|
||||||
|
*
|
||||||
|
* @param string $string String to strip comments from
|
||||||
|
* @param string &$comment Comment is stored in there.
|
||||||
|
*
|
||||||
|
* @return string String without comments
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function stripComments($string, &$comment)
|
||||||
|
{
|
||||||
|
if (strpos($string, '(') === false) {
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
$inquote = false;
|
||||||
|
$quoting = false;
|
||||||
|
$incomment = 0;
|
||||||
|
$newstring = '';
|
||||||
|
|
||||||
|
for ($n = 0; $n < strlen($string); $n++) {
|
||||||
|
if ($quoting) {
|
||||||
|
if ($incomment == 0) {
|
||||||
|
$newstring .= $string[$n];
|
||||||
|
} else if ($comment !== null) {
|
||||||
|
$comment .= $string[$n];
|
||||||
|
}
|
||||||
|
$quoting = false;
|
||||||
|
} else if ($string[$n] == '\\') {
|
||||||
|
$quoting = true;
|
||||||
|
} else if (!$inquote && $incomment > 0 && $string[$n] == ')') {
|
||||||
|
$incomment--;
|
||||||
|
if ($incomment == 0 && $comment !== null) {
|
||||||
|
$comment .= ' ';
|
||||||
|
}
|
||||||
|
} else if (!$inquote && $string[$n] == '(') {
|
||||||
|
$incomment++;
|
||||||
|
} else if ($string[$n] == '"') {
|
||||||
|
if ($inquote) {
|
||||||
|
$inquote = false;
|
||||||
|
} else {
|
||||||
|
$inquote = true;
|
||||||
|
}
|
||||||
|
} else if ($incomment == 0) {
|
||||||
|
$newstring .= $string[$n];
|
||||||
|
} else if ($comment !== null) {
|
||||||
|
$comment .= $string[$n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($comment !== null) {
|
||||||
|
$comment = trim($comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $newstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a MIME type's media
|
||||||
|
*
|
||||||
|
* @note 'media' refers to the portion before the first slash
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to get media of
|
||||||
|
*
|
||||||
|
* @return string $type's media
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getMedia($type)
|
||||||
|
{
|
||||||
|
$tmp = explode('/', $type);
|
||||||
|
return strtolower(trim(MIME_Type::stripComments($tmp[0], $null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a MIME type's subtype
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to get subtype of
|
||||||
|
*
|
||||||
|
* @return string $type's subtype, null if invalid mime type
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getSubType($type)
|
||||||
|
{
|
||||||
|
$tmp = explode('/', $type);
|
||||||
|
if (!isset($tmp[1])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$tmp = explode(';', $tmp[1]);
|
||||||
|
return strtolower(trim(MIME_Type::stripComments($tmp[0], $null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a textual MIME type from object values
|
||||||
|
*
|
||||||
|
* This function performs the opposite function of parse().
|
||||||
|
*
|
||||||
|
* @return string MIME type string
|
||||||
|
*/
|
||||||
|
function get()
|
||||||
|
{
|
||||||
|
$type = strtolower($this->media . '/' . $this->subType);
|
||||||
|
if (count($this->parameters)) {
|
||||||
|
foreach ($this->parameters as $key => $null) {
|
||||||
|
$type .= '; ' . $this->parameters[$key]->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this type experimental?
|
||||||
|
*
|
||||||
|
* @note Experimental types are denoted by a leading 'x-' in the media or
|
||||||
|
* subtype, e.g. text/x-vcard or x-world/x-vrml.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if $type is experimental, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function isExperimental($type)
|
||||||
|
{
|
||||||
|
if (substr(MIME_Type::getMedia($type), 0, 2) == 'x-' ||
|
||||||
|
substr(MIME_Type::getSubType($type), 0, 2) == 'x-') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a vendor MIME type?
|
||||||
|
*
|
||||||
|
* @note Vendor types are denoted with a leading 'vnd. in the subtype.
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if $type is a vendor type, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function isVendor($type)
|
||||||
|
{
|
||||||
|
if (substr(MIME_Type::getSubType($type), 0, 4) == 'vnd.') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a wildcard type?
|
||||||
|
*
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if $type is a wildcard, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function isWildcard($type)
|
||||||
|
{
|
||||||
|
if ($type == '*/*' || MIME_Type::getSubtype($type) == '*') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a wildcard match on a MIME type
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* MIME_Type::wildcardMatch('image/*', 'image/png')
|
||||||
|
*
|
||||||
|
* @param string $card Wildcard to check against
|
||||||
|
* @param string $type MIME type to check
|
||||||
|
*
|
||||||
|
* @return boolean true if there was a match, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function wildcardMatch($card, $type)
|
||||||
|
{
|
||||||
|
if (!MIME_Type::isWildcard($card)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($card == '*/*') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MIME_Type::getMedia($card) == MIME_Type::getMedia($type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a parameter to this type
|
||||||
|
*
|
||||||
|
* @param string $name Attribute name
|
||||||
|
* @param string $value Attribute value
|
||||||
|
* @param string $comment Comment for this parameter
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function addParameter($name, $value, $comment = false)
|
||||||
|
{
|
||||||
|
$tmp = new MIME_Type_Parameter();
|
||||||
|
|
||||||
|
$tmp->name = $name;
|
||||||
|
$tmp->value = $value;
|
||||||
|
$tmp->comment = $comment;
|
||||||
|
$this->parameters[$name] = $tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a parameter from this type
|
||||||
|
*
|
||||||
|
* @param string $name Parameter name
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function removeParameter($name)
|
||||||
|
{
|
||||||
|
unset($this->parameters[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autodetect a file's MIME-type
|
||||||
|
*
|
||||||
|
* This function may be called staticly.
|
||||||
|
*
|
||||||
|
* @internal Tries to use fileinfo extension at first. If that
|
||||||
|
* does not work, mime_magic is used. If this is also not available
|
||||||
|
* or does not succeed, "file" command is tried to be executed with
|
||||||
|
* System_Command. When that fails, too, then we use our in-built
|
||||||
|
* extension-to-mimetype-mapping list.
|
||||||
|
*
|
||||||
|
* @param string $file Path to the file to get the type of
|
||||||
|
* @param bool $params Append MIME parameters if true
|
||||||
|
*
|
||||||
|
* @return string $file's MIME-type on success, PEAR_Error otherwise
|
||||||
|
*
|
||||||
|
* @since 1.0.0beta1
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function autoDetect($file, $params = false)
|
||||||
|
{
|
||||||
|
// Sanity checks
|
||||||
|
if (!file_exists($file)) {
|
||||||
|
return PEAR::raiseError("File \"$file\" doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_readable($file)) {
|
||||||
|
return PEAR::raiseError("File \"$file\" is not readable");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('finfo_file')) {
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME);
|
||||||
|
$type = finfo_file($finfo, $file);
|
||||||
|
finfo_close($finfo);
|
||||||
|
if ($type !== false && $type !== '') {
|
||||||
|
return MIME_Type::_handleDetection($type, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('mime_content_type')) {
|
||||||
|
$type = mime_content_type($file);
|
||||||
|
if ($type !== false && $type !== '') {
|
||||||
|
return MIME_Type::_handleDetection($type, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include_once 'System/Command.php';
|
||||||
|
if (class_exists('System_Command')) {
|
||||||
|
return MIME_Type::_handleDetection(
|
||||||
|
MIME_Type::_fileAutoDetect($file),
|
||||||
|
$params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once 'MIME/Type/Extension.php';
|
||||||
|
$mte = new MIME_Type_Extension();
|
||||||
|
return $mte->getMIMEType($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a detected MIME type and modifies it if necessary.
|
||||||
|
*
|
||||||
|
* @param string $type MIME Type of a file
|
||||||
|
* @param bool $params Append MIME parameters if true
|
||||||
|
*
|
||||||
|
* @return string $file's MIME-type on success, PEAR_Error otherwise
|
||||||
|
*/
|
||||||
|
function _handleDetection($type, $params)
|
||||||
|
{
|
||||||
|
// _fileAutoDetect() may have returned an error.
|
||||||
|
if (PEAR::isError($type)) {
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't return an empty string
|
||||||
|
if (!$type || !strlen($type)) {
|
||||||
|
return PEAR::raiseError("Sorry, couldn't determine file type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip parameters if present & requested
|
||||||
|
if (MIME_Type::hasParameters($type) && !$params) {
|
||||||
|
$type = MIME_Type::stripParameters($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autodetect a file's MIME-type with 'file' and System_Command
|
||||||
|
*
|
||||||
|
* This function may be called staticly.
|
||||||
|
*
|
||||||
|
* @param string $file Path to the file to get the type of
|
||||||
|
*
|
||||||
|
* @return string $file's MIME-type
|
||||||
|
*
|
||||||
|
* @since 1.0.0beta1
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function _fileAutoDetect($file)
|
||||||
|
{
|
||||||
|
$cmd = new System_Command();
|
||||||
|
|
||||||
|
// Make sure we have the 'file' command.
|
||||||
|
$fileCmd = PEAR::getStaticProperty('MIME_Type', 'fileCmd');
|
||||||
|
if (!$cmd->which($fileCmd)) {
|
||||||
|
unset($cmd);
|
||||||
|
return PEAR::raiseError("Can't find file command \"{$fileCmd}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
$cmd->pushCommand($fileCmd, "-bi " . escapeshellarg($file));
|
||||||
|
$res = $cmd->execute();
|
||||||
|
unset($cmd);
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
298
extlib/MIME/Type/Extension.php
Normal file
298
extlib/MIME/Type/Extension.php
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
<?php
|
||||||
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | PHP versions 4 and 5 |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 1997-2009 The PHP Group |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | This source file is subject to version 3.0 of the PHP license, |
|
||||||
|
// | that is bundled with this package in the file LICENSE, and is |
|
||||||
|
// | available at through the world-wide-web at |
|
||||||
|
// | http://www.php.net/license/3_0.txt. |
|
||||||
|
// | If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
// | obtain it through the world-wide-web, please send a note to |
|
||||||
|
// | license@php.net so we can mail you a copy immediately. |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Authors: Christian Schmidt <schmidt@php.net> |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Extension.php,v 1.1 2009/01/16 11:49:45 cweiske Exp $
|
||||||
|
|
||||||
|
require_once 'PEAR.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for mapping file extensions to MIME types.
|
||||||
|
*
|
||||||
|
* @category MIME
|
||||||
|
* @package MIME_Type
|
||||||
|
* @author Christian Schmidt <schmidt@php.net>
|
||||||
|
* @license PHP License 3.0
|
||||||
|
* @version 1.2.0
|
||||||
|
* @link http://pear.php.net/package/MIME_Type
|
||||||
|
*/
|
||||||
|
class MIME_Type_Extension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Mapping between file extension and MIME type.
|
||||||
|
*
|
||||||
|
* @internal The array is sorted alphabetically by value and with primary
|
||||||
|
* extension first. Be careful about not adding duplicate keys - PHP
|
||||||
|
* silently ignores duplicates. The following command can be used for
|
||||||
|
* checking for duplicates:
|
||||||
|
* grep "=> '" Extension.php | cut -d\' -f2 | sort | uniq -d
|
||||||
|
* application/octet-stream is generally used as fallback when no other
|
||||||
|
* MIME-type can be found, but the array does not contain a lot of such
|
||||||
|
* unknown extension. One entry exists, though, to allow detection of
|
||||||
|
* file extension for this MIME-type.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
var $extensionToType = array (
|
||||||
|
'ez' => 'application/andrew-inset',
|
||||||
|
'atom' => 'application/atom+xml',
|
||||||
|
'jar' => 'application/java-archive',
|
||||||
|
'hqx' => 'application/mac-binhex40',
|
||||||
|
'cpt' => 'application/mac-compactpro',
|
||||||
|
'mathml' => 'application/mathml+xml',
|
||||||
|
'doc' => 'application/msword',
|
||||||
|
'dat' => 'application/octet-stream',
|
||||||
|
'oda' => 'application/oda',
|
||||||
|
'ogg' => 'application/ogg',
|
||||||
|
'pdf' => 'application/pdf',
|
||||||
|
'ai' => 'application/postscript',
|
||||||
|
'eps' => 'application/postscript',
|
||||||
|
'ps' => 'application/postscript',
|
||||||
|
'rdf' => 'application/rdf+xml',
|
||||||
|
'rss' => 'application/rss+xml',
|
||||||
|
'smi' => 'application/smil',
|
||||||
|
'smil' => 'application/smil',
|
||||||
|
'gram' => 'application/srgs',
|
||||||
|
'grxml' => 'application/srgs+xml',
|
||||||
|
'kml' => 'application/vnd.google-earth.kml+xml',
|
||||||
|
'kmz' => 'application/vnd.google-earth.kmz',
|
||||||
|
'mif' => 'application/vnd.mif',
|
||||||
|
'xul' => 'application/vnd.mozilla.xul+xml',
|
||||||
|
'xls' => 'application/vnd.ms-excel',
|
||||||
|
'xlb' => 'application/vnd.ms-excel',
|
||||||
|
'xlt' => 'application/vnd.ms-excel',
|
||||||
|
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
|
||||||
|
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
|
||||||
|
'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
|
||||||
|
'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
|
||||||
|
'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
|
||||||
|
'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
|
||||||
|
'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
|
||||||
|
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
|
||||||
|
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
|
||||||
|
'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
|
||||||
|
'ppt' => 'application/vnd.ms-powerpoint',
|
||||||
|
'pps' => 'application/vnd.ms-powerpoint',
|
||||||
|
'odc' => 'application/vnd.oasis.opendocument.chart',
|
||||||
|
'odb' => 'application/vnd.oasis.opendocument.database',
|
||||||
|
'odf' => 'application/vnd.oasis.opendocument.formula',
|
||||||
|
'odg' => 'application/vnd.oasis.opendocument.graphics',
|
||||||
|
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
|
||||||
|
'odi' => 'application/vnd.oasis.opendocument.image',
|
||||||
|
'odp' => 'application/vnd.oasis.opendocument.presentation',
|
||||||
|
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
|
||||||
|
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||||
|
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
|
||||||
|
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||||
|
'odm' => 'application/vnd.oasis.opendocument.text-master',
|
||||||
|
'ott' => 'application/vnd.oasis.opendocument.text-template',
|
||||||
|
'oth' => 'application/vnd.oasis.opendocument.text-web',
|
||||||
|
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
|
||||||
|
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||||
|
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||||
|
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||||
|
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||||
|
'vsd' => 'application/vnd.visio',
|
||||||
|
'wbxml' => 'application/vnd.wap.wbxml',
|
||||||
|
'wmlc' => 'application/vnd.wap.wmlc',
|
||||||
|
'wmlsc' => 'application/vnd.wap.wmlscriptc',
|
||||||
|
'vxml' => 'application/voicexml+xml',
|
||||||
|
'bcpio' => 'application/x-bcpio',
|
||||||
|
'vcd' => 'application/x-cdlink',
|
||||||
|
'pgn' => 'application/x-chess-pgn',
|
||||||
|
'cpio' => 'application/x-cpio',
|
||||||
|
'csh' => 'application/x-csh',
|
||||||
|
'dcr' => 'application/x-director',
|
||||||
|
'dir' => 'application/x-director',
|
||||||
|
'dxr' => 'application/x-director',
|
||||||
|
'dvi' => 'application/x-dvi',
|
||||||
|
'spl' => 'application/x-futuresplash',
|
||||||
|
'tgz' => 'application/x-gtar',
|
||||||
|
'gtar' => 'application/x-gtar',
|
||||||
|
'hdf' => 'application/x-hdf',
|
||||||
|
'js' => 'application/x-javascript',
|
||||||
|
'skp' => 'application/x-koan',
|
||||||
|
'skd' => 'application/x-koan',
|
||||||
|
'skt' => 'application/x-koan',
|
||||||
|
'skm' => 'application/x-koan',
|
||||||
|
'latex' => 'application/x-latex',
|
||||||
|
'nc' => 'application/x-netcdf',
|
||||||
|
'cdf' => 'application/x-netcdf',
|
||||||
|
'sh' => 'application/x-sh',
|
||||||
|
'shar' => 'application/x-shar',
|
||||||
|
'swf' => 'application/x-shockwave-flash',
|
||||||
|
'sit' => 'application/x-stuffit',
|
||||||
|
'sv4cpio' => 'application/x-sv4cpio',
|
||||||
|
'sv4crc' => 'application/x-sv4crc',
|
||||||
|
'tar' => 'application/x-tar',
|
||||||
|
'tcl' => 'application/x-tcl',
|
||||||
|
'tex' => 'application/x-tex',
|
||||||
|
'texinfo' => 'application/x-texinfo',
|
||||||
|
'texi' => 'application/x-texinfo',
|
||||||
|
't' => 'application/x-troff',
|
||||||
|
'tr' => 'application/x-troff',
|
||||||
|
'roff' => 'application/x-troff',
|
||||||
|
'man' => 'application/x-troff-man',
|
||||||
|
'me' => 'application/x-troff-me',
|
||||||
|
'ms' => 'application/x-troff-ms',
|
||||||
|
'ustar' => 'application/x-ustar',
|
||||||
|
'src' => 'application/x-wais-source',
|
||||||
|
'xhtml' => 'application/xhtml+xml',
|
||||||
|
'xht' => 'application/xhtml+xml',
|
||||||
|
'xslt' => 'application/xslt+xml',
|
||||||
|
'xml' => 'application/xml',
|
||||||
|
'xsl' => 'application/xml',
|
||||||
|
'dtd' => 'application/xml-dtd',
|
||||||
|
'zip' => 'application/zip',
|
||||||
|
'au' => 'audio/basic',
|
||||||
|
'snd' => 'audio/basic',
|
||||||
|
'mid' => 'audio/midi',
|
||||||
|
'midi' => 'audio/midi',
|
||||||
|
'kar' => 'audio/midi',
|
||||||
|
'mpga' => 'audio/mpeg',
|
||||||
|
'mp2' => 'audio/mpeg',
|
||||||
|
'mp3' => 'audio/mpeg',
|
||||||
|
'aif' => 'audio/x-aiff',
|
||||||
|
'aiff' => 'audio/x-aiff',
|
||||||
|
'aifc' => 'audio/x-aiff',
|
||||||
|
'm3u' => 'audio/x-mpegurl',
|
||||||
|
'wma' => 'audio/x-ms-wma',
|
||||||
|
'wax' => 'audio/x-ms-wax',
|
||||||
|
'ram' => 'audio/x-pn-realaudio',
|
||||||
|
'ra' => 'audio/x-pn-realaudio',
|
||||||
|
'rm' => 'application/vnd.rn-realmedia',
|
||||||
|
'wav' => 'audio/x-wav',
|
||||||
|
'pdb' => 'chemical/x-pdb',
|
||||||
|
'xyz' => 'chemical/x-xyz',
|
||||||
|
'bmp' => 'image/bmp',
|
||||||
|
'cgm' => 'image/cgm',
|
||||||
|
'gif' => 'image/gif',
|
||||||
|
'ief' => 'image/ief',
|
||||||
|
'jpeg' => 'image/jpeg',
|
||||||
|
'jpg' => 'image/jpeg',
|
||||||
|
'jpe' => 'image/jpeg',
|
||||||
|
'png' => 'image/png',
|
||||||
|
'svg' => 'image/svg+xml',
|
||||||
|
'tiff' => 'image/tiff',
|
||||||
|
'tif' => 'image/tiff',
|
||||||
|
'djvu' => 'image/vnd.djvu',
|
||||||
|
'djv' => 'image/vnd.djvu',
|
||||||
|
'wbmp' => 'image/vnd.wap.wbmp',
|
||||||
|
'ras' => 'image/x-cmu-raster',
|
||||||
|
'ico' => 'image/x-icon',
|
||||||
|
'pnm' => 'image/x-portable-anymap',
|
||||||
|
'pbm' => 'image/x-portable-bitmap',
|
||||||
|
'pgm' => 'image/x-portable-graymap',
|
||||||
|
'ppm' => 'image/x-portable-pixmap',
|
||||||
|
'rgb' => 'image/x-rgb',
|
||||||
|
'xbm' => 'image/x-xbitmap',
|
||||||
|
'psd' => 'image/x-photoshop',
|
||||||
|
'xpm' => 'image/x-xpixmap',
|
||||||
|
'xwd' => 'image/x-xwindowdump',
|
||||||
|
'eml' => 'message/rfc822',
|
||||||
|
'igs' => 'model/iges',
|
||||||
|
'iges' => 'model/iges',
|
||||||
|
'msh' => 'model/mesh',
|
||||||
|
'mesh' => 'model/mesh',
|
||||||
|
'silo' => 'model/mesh',
|
||||||
|
'wrl' => 'model/vrml',
|
||||||
|
'vrml' => 'model/vrml',
|
||||||
|
'ics' => 'text/calendar',
|
||||||
|
'ifb' => 'text/calendar',
|
||||||
|
'css' => 'text/css',
|
||||||
|
'csv' => 'text/csv',
|
||||||
|
'html' => 'text/html',
|
||||||
|
'htm' => 'text/html',
|
||||||
|
'txt' => 'text/plain',
|
||||||
|
'asc' => 'text/plain',
|
||||||
|
'rtx' => 'text/richtext',
|
||||||
|
'rtf' => 'text/rtf',
|
||||||
|
'sgml' => 'text/sgml',
|
||||||
|
'sgm' => 'text/sgml',
|
||||||
|
'tsv' => 'text/tab-separated-values',
|
||||||
|
'wml' => 'text/vnd.wap.wml',
|
||||||
|
'wmls' => 'text/vnd.wap.wmlscript',
|
||||||
|
'etx' => 'text/x-setext',
|
||||||
|
'mpeg' => 'video/mpeg',
|
||||||
|
'mpg' => 'video/mpeg',
|
||||||
|
'mpe' => 'video/mpeg',
|
||||||
|
'qt' => 'video/quicktime',
|
||||||
|
'mov' => 'video/quicktime',
|
||||||
|
'mxu' => 'video/vnd.mpegurl',
|
||||||
|
'm4u' => 'video/vnd.mpegurl',
|
||||||
|
'flv' => 'video/x-flv',
|
||||||
|
'asf' => 'video/x-ms-asf',
|
||||||
|
'asx' => 'video/x-ms-asf',
|
||||||
|
'wmv' => 'video/x-ms-wmv',
|
||||||
|
'wm' => 'video/x-ms-wm',
|
||||||
|
'wmx' => 'video/x-ms-wmx',
|
||||||
|
'avi' => 'video/x-msvideo',
|
||||||
|
'ogv' => 'video/ogg',
|
||||||
|
'movie' => 'video/x-sgi-movie',
|
||||||
|
'ice' => 'x-conference/x-cooltalk',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autodetect a file's MIME-type.
|
||||||
|
*
|
||||||
|
* @param string $file Path to the file to get the type of
|
||||||
|
*
|
||||||
|
* @return string $file's MIME-type on success, PEAR_Error otherwise
|
||||||
|
*/
|
||||||
|
function getMIMEType($file)
|
||||||
|
{
|
||||||
|
$extension = substr(strrchr($file, '.'), 1);
|
||||||
|
if ($extension === false) {
|
||||||
|
return PEAR::raiseError("File has no extension.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->extensionToType[$extension])) {
|
||||||
|
return PEAR::raiseError("Sorry, couldn't determine file type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->extensionToType[$extension];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return default MIME-type for the specified extension.
|
||||||
|
*
|
||||||
|
* @param string $type MIME-type
|
||||||
|
*
|
||||||
|
* @return string A file extension without leading period.
|
||||||
|
*/
|
||||||
|
function getExtension($type)
|
||||||
|
{
|
||||||
|
require_once 'MIME/Type.php';
|
||||||
|
// Strip parameters and comments.
|
||||||
|
$type = MIME_Type::getMedia($type) . '/' . MIME_Type::getSubType($type);
|
||||||
|
|
||||||
|
$extension = array_search($type, $this->extensionToType);
|
||||||
|
if ($extension === false) {
|
||||||
|
return PEAR::raiseError("Sorry, couldn't determine extension.");
|
||||||
|
}
|
||||||
|
return $extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
163
extlib/MIME/Type/Parameter.php
Normal file
163
extlib/MIME/Type/Parameter.php
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<?php
|
||||||
|
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | PHP version 4 |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 1997-2002 The PHP Group |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | This source file is subject to version 3.0 of the PHP license, |
|
||||||
|
// | that is bundled with this package in the file LICENSE, and is |
|
||||||
|
// | available at through the world-wide-web at |
|
||||||
|
// | http://www.php.net/license/3_0.txt. |
|
||||||
|
// | If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
// | obtain it through the world-wide-web, please send a note to |
|
||||||
|
// | license@php.net so we can mail you a copy immediately. |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
// | Authors: Ian Eure <ieure@php.net> |
|
||||||
|
// +----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Parameter.php,v 1.1 2007/03/25 10:10:21 cweiske Exp $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for working with MIME type parameters
|
||||||
|
*
|
||||||
|
* @version 1.2.0
|
||||||
|
* @package MIME_Type
|
||||||
|
* @author Ian Eure <ieure@php.net>
|
||||||
|
*/
|
||||||
|
class MIME_Type_Parameter {
|
||||||
|
/**
|
||||||
|
* Parameter name
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter value
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter comment
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
var $comment;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param string $param MIME parameter to parse, if set.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function MIME_Type_Parameter($param = false)
|
||||||
|
{
|
||||||
|
if ($param) {
|
||||||
|
$this->parse($param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a MIME type parameter and set object fields
|
||||||
|
*
|
||||||
|
* @param string $param MIME type parameter to parse
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function parse($param)
|
||||||
|
{
|
||||||
|
$comment = '';
|
||||||
|
$param = MIME_Type::stripComments($param, $comment);
|
||||||
|
$this->name = $this->getAttribute($param);
|
||||||
|
$this->value = $this->getValue($param);
|
||||||
|
$this->comment = $comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a parameter attribute (e.g. name)
|
||||||
|
*
|
||||||
|
* @param string MIME type parameter
|
||||||
|
* @return string Attribute name
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getAttribute($param)
|
||||||
|
{
|
||||||
|
$tmp = explode('=', $param);
|
||||||
|
return trim($tmp[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a parameter value
|
||||||
|
*
|
||||||
|
* @param string $param MIME type parameter
|
||||||
|
* @return string Value
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getValue($param)
|
||||||
|
{
|
||||||
|
$tmp = explode('=', $param, 2);
|
||||||
|
$value = $tmp[1];
|
||||||
|
$value = trim($value);
|
||||||
|
if ($value[0] == '"' && $value[strlen($value)-1] == '"') {
|
||||||
|
$value = substr($value, 1, -1);
|
||||||
|
}
|
||||||
|
$value = str_replace('\\"', '"', $value);
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a parameter comment
|
||||||
|
*
|
||||||
|
* @param string $param MIME type parameter
|
||||||
|
* @return string Parameter comment
|
||||||
|
* @see getComment()
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function getComment($param)
|
||||||
|
{
|
||||||
|
$cs = strpos($param, '(');
|
||||||
|
$comment = substr($param, $cs);
|
||||||
|
return trim($comment, '() ');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this parameter have a comment?
|
||||||
|
*
|
||||||
|
* @param string $param MIME type parameter
|
||||||
|
* @return boolean true if $param has a comment, false otherwise
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
function hasComment($param)
|
||||||
|
{
|
||||||
|
if (strstr($param, '(')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a string representation of this parameter
|
||||||
|
*
|
||||||
|
* This function performs the oppsite of parse()
|
||||||
|
*
|
||||||
|
* @return string String representation of parameter
|
||||||
|
*/
|
||||||
|
function get()
|
||||||
|
{
|
||||||
|
$val = $this->name . '="' . str_replace('"', '\\"', $this->value) . '"';
|
||||||
|
if ($this->comment) {
|
||||||
|
$val .= ' (' . $this->comment . ')';
|
||||||
|
}
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -64,11 +64,13 @@ function handleError($error)
|
|||||||
function main()
|
function main()
|
||||||
{
|
{
|
||||||
// quick check for fancy URL auto-detection support in installer.
|
// quick check for fancy URL auto-detection support in installer.
|
||||||
if (isset($_SERVER['REDIRECT_URL']) && ('/check-fancy' === $_SERVER['REDIRECT_URL'])) {
|
if (isset($_SERVER['REDIRECT_URL']) && ((dirname($_SERVER['REQUEST_URI']) . '/check-fancy') === $_SERVER['REDIRECT_URL'])) {
|
||||||
die("Fancy URL support detection succeeded. We suggest you enable this to get fancy (pretty) URLs.");
|
die("Fancy URL support detection succeeded. We suggest you enable this to get fancy (pretty) URLs.");
|
||||||
}
|
}
|
||||||
global $user, $action, $config;
|
global $user, $action, $config;
|
||||||
|
|
||||||
|
Snapshot::check();
|
||||||
|
|
||||||
if (!_have_config()) {
|
if (!_have_config()) {
|
||||||
$msg = sprintf(_("No configuration file found. Try running ".
|
$msg = sprintf(_("No configuration file found. Try running ".
|
||||||
"the installation program first."));
|
"the installation program first."));
|
||||||
|
61
install.php
61
install.php
@ -35,15 +35,17 @@ function main()
|
|||||||
|
|
||||||
function checkPrereqs()
|
function checkPrereqs()
|
||||||
{
|
{
|
||||||
|
$pass = true;
|
||||||
|
|
||||||
if (file_exists(INSTALLDIR.'/config.php')) {
|
if (file_exists(INSTALLDIR.'/config.php')) {
|
||||||
?><p class="error">Config file "config.php" already exists.</p>
|
?><p class="error">Config file "config.php" already exists.</p>
|
||||||
<?php
|
<?php
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
|
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
|
||||||
?><p class="error">Require PHP version 5 or greater.</p><?php
|
?><p class="error">Require PHP version 5 or greater.</p><?php
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$reqs = array('gd', 'mysql', 'curl',
|
$reqs = array('gd', 'mysql', 'curl',
|
||||||
@ -53,7 +55,7 @@ function checkPrereqs()
|
|||||||
foreach ($reqs as $req) {
|
foreach ($reqs as $req) {
|
||||||
if (!checkExtension($req)) {
|
if (!checkExtension($req)) {
|
||||||
?><p class="error">Cannot load required extension: <code><?php echo $req; ?></code></p><?php
|
?><p class="error">Cannot load required extension: <code><?php echo $req; ?></code></p><?php
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,17 +63,17 @@ function checkPrereqs()
|
|||||||
?><p class="error">Cannot write config file to: <code><?php echo INSTALLDIR; ?></code></p>
|
?><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>
|
<p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?></code>
|
||||||
<?php
|
<?php
|
||||||
return false;
|
$pass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_writable(INSTALLDIR.'/avatar/')) {
|
if (!is_writable(INSTALLDIR.'/avatar/')) {
|
||||||
?><p class="error">Cannot write avatar directory: <code><?php echo INSTALLDIR; ?>/avatar/</code></p>
|
?><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>
|
<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)
|
function checkExtension($name)
|
||||||
@ -114,16 +116,16 @@ function showForm()
|
|||||||
<input type="radio" name="fancy" id="fancy-disable" value="" /> disable<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>
|
<p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<label for="host">Hostname</label>
|
|
||||||
<input type="text" id="host" name="host" />
|
|
||||||
<p class="form_guide">Database hostname</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<label for="host">Site path</label>
|
<label for="host">Site path</label>
|
||||||
<input type="text" id="path" name="path" value="$config_path" />
|
<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>
|
<p class="form_guide">Site path, following the "/" after the domain name in the URL. Empty is fine. Field should be filled automatically.</p>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<label for="host">Hostname</label>
|
||||||
|
<input type="text" id="host" name="host" />
|
||||||
|
<p class="form_guide">Database hostname</p>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<label for="host">Database</label>
|
<label for="host">Database</label>
|
||||||
<input type="text" id="database" name="database" />
|
<input type="text" id="database" name="database" />
|
||||||
@ -173,36 +175,38 @@ function handlePost()
|
|||||||
<dd>
|
<dd>
|
||||||
<ul>
|
<ul>
|
||||||
<?php
|
<?php
|
||||||
|
$fail = false;
|
||||||
|
|
||||||
if (empty($host)) {
|
if (empty($host)) {
|
||||||
updateStatus("No hostname specified.", true);
|
updateStatus("No hostname specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($database)) {
|
if (empty($database)) {
|
||||||
updateStatus("No database specified.", true);
|
updateStatus("No database specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($username)) {
|
if (empty($username)) {
|
||||||
updateStatus("No username specified.", true);
|
updateStatus("No username specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($password)) {
|
if (empty($password)) {
|
||||||
updateStatus("No password specified.", true);
|
updateStatus("No password specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($sitename)) {
|
if (empty($sitename)) {
|
||||||
updateStatus("No sitename specified.", true);
|
updateStatus("No sitename specified.", true);
|
||||||
showForm();
|
$fail = true;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($fail){
|
||||||
|
showForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateStatus("Starting installation...");
|
updateStatus("Starting installation...");
|
||||||
updateStatus("Checking database...");
|
updateStatus("Checking database...");
|
||||||
$conn = mysql_connect($host, $username, $password);
|
$conn = mysql_connect($host, $username, $password);
|
||||||
@ -247,7 +251,7 @@ function handlePost()
|
|||||||
}
|
}
|
||||||
updateStatus("Done!");
|
updateStatus("Done!");
|
||||||
if ($path) $path .= '/';
|
if ($path) $path .= '/';
|
||||||
updateStatus("You can visit your <a href='/$path'>new Laconica site</a).");
|
updateStatus("You can visit your <a href='/$path'>new Laconica site</a>.");
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
@ -257,16 +261,17 @@ function writeConf($sitename, $sqlUrl, $fancy, $path)
|
|||||||
{
|
{
|
||||||
$res = file_put_contents(INSTALLDIR.'/config.php',
|
$res = file_put_contents(INSTALLDIR.'/config.php',
|
||||||
"<?php\n".
|
"<?php\n".
|
||||||
|
"if (!defined('LACONICA')) { exit(1); }\n\n".
|
||||||
"\$config['site']['name'] = \"$sitename\";\n\n".
|
"\$config['site']['name'] = \"$sitename\";\n\n".
|
||||||
($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
|
($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
|
||||||
"\$config['site']['path'] = \"$path\";\n\n".
|
"\$config['site']['path'] = \"$path\";\n\n".
|
||||||
"\$config['db']['database'] = \"$sqlUrl\";\n\n");
|
"\$config['db']['database'] = \"$sqlUrl\";\n\n".
|
||||||
|
"?>");
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function runDbScript($filename, $conn)
|
function runDbScript($filename, $conn)
|
||||||
{
|
{
|
||||||
return true;
|
|
||||||
$sql = trim(file_get_contents($filename));
|
$sql = trim(file_get_contents($filename));
|
||||||
$stmts = explode(';', $sql);
|
$stmts = explode(';', $sql);
|
||||||
foreach ($stmts as $stmt) {
|
foreach ($stmts as $stmt) {
|
||||||
@ -290,13 +295,13 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
|
||||||
<head>
|
<head>
|
||||||
<title>Install Laconica</title>
|
<title>Install Laconica</title>
|
||||||
<link rel="stylesheet" type="text/css" href="theme/base/css/display.css?version=0.8" media="screen, projection, tv"/>
|
<link rel="shortcut icon" href="favicon.ico"/>
|
||||||
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
|
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
|
||||||
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
|
<!--[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 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]-->
|
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/default/css/ie.css?version=0.8" /><![endif]-->
|
||||||
<script src='js/jquery.min.js'></script>
|
<script src="js/jquery.min.js"></script>
|
||||||
<script src='js/install.js'></script>
|
<script src="js/install.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body id="install">
|
<body id="install">
|
||||||
<div id="wrap">
|
<div id="wrap">
|
||||||
|
@ -1,29 +1,30 @@
|
|||||||
|
/** Init for Farbtastic library and page setup
|
||||||
|
*
|
||||||
|
* @package Laconica
|
||||||
|
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||||
|
* @copyright 2009 Control Yourself, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://laconi.ca/
|
||||||
|
*/
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
function UpdateColors(e) {
|
function UpdateColors(S) {
|
||||||
var S = f.linked;
|
C = $(S).val();
|
||||||
var C = f.color;
|
switch (parseInt(S.id.slice(-1))) {
|
||||||
|
case 0: default:
|
||||||
if (S && S.value && S.value != C) {
|
$('body').css({'background-color':C});
|
||||||
UpdateSwatch(S);
|
break;
|
||||||
|
case 1:
|
||||||
switch (parseInt(f.linked.id.slice(-1))) {
|
$('#content').css({'background-color':C});
|
||||||
case 0: default:
|
break;
|
||||||
$('body').css({'background-color':C});
|
case 2:
|
||||||
break;
|
$('#aside_primary').css({'background-color':C});
|
||||||
case 1:
|
break;
|
||||||
$('#content').css({'background-color':C});
|
case 3:
|
||||||
break;
|
$('body').css({'color':C});
|
||||||
case 2:
|
break;
|
||||||
$('#aside_primary').css({'background-color':C});
|
case 4:
|
||||||
break;
|
$('a').css({'color':C});
|
||||||
case 3:
|
break;
|
||||||
$('body').css({'color':C});
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
$('a').css({'color':C});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
S.value = C;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,35 +34,52 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function UpdateSwatch(e) {
|
function UpdateSwatch(e) {
|
||||||
$(e).css({
|
$(e).css({"background-color": e.value,
|
||||||
"background-color": e.value,
|
"color": f.hsl[2] > 0.5 ? "#000": "#fff"});
|
||||||
"color": f.hsl[2] > 0.5 ? "#000": "#fff"
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#settings_design_color').append('<div id="color-picker"></div>');
|
function SynchColors(e) {
|
||||||
$('#color-picker').hide();
|
var S = f.linked;
|
||||||
|
var C = f.color;
|
||||||
|
|
||||||
var f = $.farbtastic('#color-picker', UpdateColors);
|
if (S && S.value && S.value != C) {
|
||||||
var swatches = $('#settings_design_color .swatch');
|
S.value = C;
|
||||||
|
UpdateSwatch(S);
|
||||||
|
UpdateColors(S);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
swatches
|
function Init() {
|
||||||
.each(UpdateColors)
|
$('#settings_design_color').append('<div id="color-picker"></div>');
|
||||||
|
$('#color-picker').hide();
|
||||||
|
|
||||||
.blur(function() {
|
f = $.farbtastic('#color-picker', SynchColors);
|
||||||
$(this).val($(this).val().toUpperCase());
|
swatches = $('#settings_design_color .swatch');
|
||||||
})
|
|
||||||
|
|
||||||
.focus(function() {
|
swatches
|
||||||
$('#color-picker').show();
|
.each(SynchColors)
|
||||||
UpdateFarbtastic(this);
|
.blur(function() {
|
||||||
})
|
$(this).val($(this).val().toUpperCase());
|
||||||
|
})
|
||||||
.change(function() {
|
.focus(function() {
|
||||||
UpdateFarbtastic(this);
|
$('#color-picker').show();
|
||||||
UpdateSwatch(this);
|
UpdateFarbtastic(this);
|
||||||
}).change()
|
})
|
||||||
|
.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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,39 +1,48 @@
|
|||||||
$(function(){
|
/** Init for Jcrop library and page setup
|
||||||
var x = ($('#avatar_crop_x').val()) ? $('#avatar_crop_x').val() : 0;
|
*
|
||||||
var y = ($('#avatar_crop_y').val()) ? $('#avatar_crop_y').val() : 0;
|
* @package Laconica
|
||||||
var w = ($('#avatar_crop_w').val()) ? $('#avatar_crop_w').val() : $("#avatar_original img").attr("width");
|
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||||
var h = ($('#avatar_crop_h').val()) ? $('#avatar_crop_h').val() : $("#avatar_original img").attr("height");
|
* @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({
|
$(function(){
|
||||||
onChange: showPreview,
|
var x = ($('#avatar_crop_x').val()) ? $('#avatar_crop_x').val() : 0;
|
||||||
setSelect: [ x, y, w, h ],
|
var y = ($('#avatar_crop_y').val()) ? $('#avatar_crop_y').val() : 0;
|
||||||
onSelect: updateCoords,
|
var w = ($('#avatar_crop_w').val()) ? $('#avatar_crop_w').val() : $("#avatar_original img").attr("width");
|
||||||
aspectRatio: 1,
|
var h = ($('#avatar_crop_h').val()) ? $('#avatar_crop_h').val() : $("#avatar_original img").attr("height");
|
||||||
boxWidth: 480,
|
|
||||||
boxHeight: 480,
|
|
||||||
bgColor: '#000',
|
|
||||||
bgOpacity: .4
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function showPreview(coords) {
|
jQuery("#avatar_original img").Jcrop({
|
||||||
var rx = 96 / coords.w;
|
onChange: showPreview,
|
||||||
var ry = 96 / coords.h;
|
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");
|
function showPreview(coords) {
|
||||||
var img_height = $("#avatar_original img").attr("height");
|
var rx = 96 / coords.w;
|
||||||
|
var ry = 96 / coords.h;
|
||||||
|
|
||||||
$('#avatar_preview img').css({
|
var img_width = $("#avatar_original img").attr("width");
|
||||||
width: Math.round(rx *img_width) + 'px',
|
var img_height = $("#avatar_original img").attr("height");
|
||||||
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_preview img').css({
|
||||||
$('#avatar_crop_x').val(c.x);
|
width: Math.round(rx *img_width) + 'px',
|
||||||
$('#avatar_crop_y').val(c.y);
|
height: Math.round(ry * img_height) + 'px',
|
||||||
$('#avatar_crop_w').val(c.w);
|
marginLeft: '-' + Math.round(rx * coords.x) + 'px',
|
||||||
$('#avatar_crop_h').val(c.h);
|
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);
|
||||||
|
};
|
||||||
|
@ -157,7 +157,7 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
function fileUpload() {
|
function fileUpload() {
|
||||||
var form = $form[0];
|
var form = $form[0];
|
||||||
|
|
||||||
if ($(':input[@name=submit]', form).length) {
|
if ($(':input[name=submit]', form).length) {
|
||||||
alert('Error: Form elements must not be named "submit".');
|
alert('Error: Form elements must not be named "submit".');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -570,7 +570,7 @@ $.fn.clearForm = function() {
|
|||||||
$.fn.clearFields = $.fn.clearInputs = function() {
|
$.fn.clearFields = $.fn.clearInputs = function() {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
var t = this.type, tag = this.tagName.toLowerCase();
|
var t = this.type, tag = this.tagName.toLowerCase();
|
||||||
if (t == 'text' || t == 'password' || tag == 'textarea')
|
if (t == 'file' || t == 'text' || t == 'password' || tag == 'textarea')
|
||||||
this.value = '';
|
this.value = '';
|
||||||
else if (t == 'checkbox' || t == 'radio')
|
else if (t == 'checkbox' || t == 'radio')
|
||||||
this.checked = false;
|
this.checked = false;
|
||||||
|
80
js/util.js
80
js/util.js
@ -17,10 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
$('.attachments').click(function() {$().jOverlay({zIndex:999, success:function(html) {$('.attachment').click(function() {$().jOverlay({url:$(this).attr('href') + '/ajax'}); return false; });
|
|
||||||
}, url:$(this).attr('href') + '/ajax'}); return false; });
|
|
||||||
$('.attachment').click(function() {$().jOverlay({url:$(this).attr('href') + '/ajax'}); return false; });
|
|
||||||
|
|
||||||
// count character on keyup
|
// count character on keyup
|
||||||
function counter(event){
|
function counter(event){
|
||||||
var maxLength = 140;
|
var maxLength = 140;
|
||||||
@ -203,11 +199,11 @@ $(document).ready(function(){
|
|||||||
$("#notices_primary .notices").prepend(document._importNode(li, true));
|
$("#notices_primary .notices").prepend(document._importNode(li, true));
|
||||||
$("#notices_primary .notice:first").css({display:"none"});
|
$("#notices_primary .notice:first").css({display:"none"});
|
||||||
$("#notices_primary .notice:first").fadeIn(2500);
|
$("#notices_primary .notice:first").fadeIn(2500);
|
||||||
NoticeHover();
|
|
||||||
NoticeReply();
|
NoticeReply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$("#notice_data-text").val("");
|
$("#notice_data-text").val("");
|
||||||
|
$("#notice_data-attach").val("");
|
||||||
counter();
|
counter();
|
||||||
}
|
}
|
||||||
$("#form_notice").removeClass("processing");
|
$("#form_notice").removeClass("processing");
|
||||||
@ -219,26 +215,26 @@ $(document).ready(function(){
|
|||||||
$("#form_notice").each(addAjaxHidden);
|
$("#form_notice").each(addAjaxHidden);
|
||||||
NoticeHover();
|
NoticeHover();
|
||||||
NoticeReply();
|
NoticeReply();
|
||||||
|
NoticeAttachments();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function NoticeHover() {
|
function NoticeHover() {
|
||||||
$("#content .notice").hover(
|
function mouseHandler(e) {
|
||||||
function () {
|
$(e.target).closest('li.hentry')[(e.type === 'mouseover') ? 'addClass' : 'removeClass']('hover');
|
||||||
$(this).addClass('hover');
|
};
|
||||||
},
|
$('#content .notices').mouseover(mouseHandler);
|
||||||
function () {
|
$('#content .notices').mouseout(mouseHandler);
|
||||||
$(this).removeClass('hover');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function NoticeReply() {
|
function NoticeReply() {
|
||||||
if ($('#notice_data-text').length > 0) {
|
if ($('#notice_data-text').length > 0) {
|
||||||
$('#content .notice').each(function() {
|
$('#content .notice').each(function() {
|
||||||
var notice = $(this);
|
var notice = $(this)[0];
|
||||||
$('.notice_reply', $(this)).click(function() {
|
$($('.notice_reply', notice)[0]).click(function() {
|
||||||
var nickname = ($('.author .nickname', notice).length > 0) ? $('.author .nickname', notice) : $('.author .nickname');
|
var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname');
|
||||||
NoticeReplySet(nickname.text(), $('.notice_id', notice).text());
|
NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text());
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -258,3 +254,53 @@ function NoticeReplySet(nick,id) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function NoticeAttachments() {
|
||||||
|
$.fn.jOverlay.options = {
|
||||||
|
method : 'GET',
|
||||||
|
data : '',
|
||||||
|
url : '',
|
||||||
|
color : '#000',
|
||||||
|
opacity : '0.6',
|
||||||
|
zIndex : 99,
|
||||||
|
center : true,
|
||||||
|
imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif',
|
||||||
|
bgClickToClose : true,
|
||||||
|
success : function() {
|
||||||
|
$('#jOverlayContent').append('<button>×</button>');
|
||||||
|
$('#jOverlayContent button').click($.closeOverlay);
|
||||||
|
},
|
||||||
|
timeout : 0
|
||||||
|
};
|
||||||
|
|
||||||
|
$('a.attachment').click(function() {
|
||||||
|
$().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
var t;
|
||||||
|
$("body:not(#shownotice) a.thumbnail").hover(
|
||||||
|
function() {
|
||||||
|
var anchor = $(this);
|
||||||
|
$("a.thumbnail").children('img').hide();
|
||||||
|
anchor.closest(".entry-title").addClass('ov');
|
||||||
|
|
||||||
|
if (anchor.children('img').length == 0) {
|
||||||
|
t = setTimeout(function() {
|
||||||
|
$.get($('address .url')[0].href+'/attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) {
|
||||||
|
anchor.append(data);
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
anchor.children('img').show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
clearTimeout(t);
|
||||||
|
$("a.thumbnail").children('img').hide();
|
||||||
|
$(this).closest(".entry-title").removeClass('ov');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -80,20 +80,22 @@ class AttachmentList extends Widget
|
|||||||
|
|
||||||
function show()
|
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;
|
$atts = new File;
|
||||||
$att = $atts->getAttachments($this->notice->id);
|
$att = $atts->getAttachments($this->notice->id);
|
||||||
|
if (empty($att)) return 0;
|
||||||
|
$this->out->elementStart('dl', array('id' =>'attachments'));
|
||||||
|
$this->out->element('dt', null, _('Attachments'));
|
||||||
|
$this->out->elementStart('dd');
|
||||||
|
$this->out->elementStart('ol', array('class' => 'attachments'));
|
||||||
|
|
||||||
foreach ($att as $n=>$attachment) {
|
foreach ($att as $n=>$attachment) {
|
||||||
$item = $this->newListItem($attachment);
|
$item = $this->newListItem($attachment);
|
||||||
$item->show();
|
$item->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('dd');
|
||||||
$this->out->elementEnd('div');
|
$this->out->elementEnd('ol');
|
||||||
|
$this->out->elementEnd('dl');
|
||||||
|
|
||||||
return count($att);
|
return count($att);
|
||||||
}
|
}
|
||||||
@ -171,7 +173,7 @@ class AttachmentListItem extends Widget
|
|||||||
}
|
}
|
||||||
|
|
||||||
function linkTitle() {
|
function linkTitle() {
|
||||||
return 'Our page for ' . $this->title();
|
return $this->title();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -191,34 +193,25 @@ class AttachmentListItem extends Widget
|
|||||||
}
|
}
|
||||||
|
|
||||||
function linkAttr() {
|
function linkAttr() {
|
||||||
return array('class' => 'attachment', 'href' => common_local_url('attachment', array('attachment' => $this->attachment->id)));
|
return array('class' => 'attachment', 'href' => $this->attachment->url, 'id' => 'attachment-' . $this->attachment->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showLink() {
|
function showLink() {
|
||||||
$attr = $this->linkAttr();
|
$this->out->elementStart('a', $this->linkAttr());
|
||||||
$text = $this->linkTitle();
|
$this->out->element('span', null, $this->linkTitle());
|
||||||
$this->out->elementStart('h4');
|
$this->showRepresentation();
|
||||||
$this->out->element('a', $attr, $text);
|
$this->out->elementEnd('a');
|
||||||
|
|
||||||
if ($this->attachment->url !== $this->title())
|
|
||||||
$this->out->element('span', null, " ({$this->attachment->url})");
|
|
||||||
|
|
||||||
|
|
||||||
$this->out->elementEnd('h4');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNoticeAttachment()
|
function showNoticeAttachment()
|
||||||
{
|
{
|
||||||
$this->showLink();
|
$this->showLink();
|
||||||
$this->showRepresentation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showRepresentation() {
|
function showRepresentation() {
|
||||||
$thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
|
$thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
|
||||||
if (!empty($thumbnail)) {
|
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->element('img', array('alt' => 'nothing to say', 'src' => $thumbnail->url, 'width' => $thumbnail->width, 'height' => $thumbnail->height));
|
||||||
$this->out->elementEnd('a');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +253,7 @@ class Attachment extends AttachmentListItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
function linkTitle() {
|
function linkTitle() {
|
||||||
return 'Direct link to ' . $this->title();
|
return $this->attachment->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showRepresentation() {
|
function showRepresentation() {
|
||||||
@ -275,6 +268,23 @@ class Attachment extends AttachmentListItem
|
|||||||
case 'image/jpeg':
|
case 'image/jpeg':
|
||||||
$this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt'));
|
$this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt'));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'application/ogg':
|
||||||
|
case 'audio/x-speex':
|
||||||
|
case 'video/mpeg':
|
||||||
|
case 'audio/mpeg':
|
||||||
|
case 'video/mp4':
|
||||||
|
case 'video/quicktime':
|
||||||
|
$arr = array('type' => $this->attachment->mimetype,
|
||||||
|
'data' => $this->attachment->url,
|
||||||
|
'width' => 320,
|
||||||
|
'height' => 240
|
||||||
|
);
|
||||||
|
$this->out->elementStart('object', $arr);
|
||||||
|
$this->out->element('param', array('name' => 'src', 'value' => $this->attachment->url));
|
||||||
|
$this->out->element('param', array('name' => 'autoStart', 'value' => 1));
|
||||||
|
$this->out->elementEnd('object');
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
<?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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
if (!defined('LACONICA')) { exit(1); }
|
if (!defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
define('LACONICA_VERSION', '0.7.3');
|
define('LACONICA_VERSION', '0.8.0dev');
|
||||||
|
|
||||||
define('AVATAR_PROFILE_SIZE', 96);
|
define('AVATAR_PROFILE_SIZE', 96);
|
||||||
define('AVATAR_STREAM_SIZE', 48);
|
define('AVATAR_STREAM_SIZE', 48);
|
||||||
@ -159,6 +159,46 @@ $config =
|
|||||||
'newuser' =>
|
'newuser' =>
|
||||||
array('subscribe' => null,
|
array('subscribe' => null,
|
||||||
'welcome' => null),
|
'welcome' => null),
|
||||||
|
'snapshot' =>
|
||||||
|
array('run' => 'web',
|
||||||
|
'frequency' => 10000,
|
||||||
|
'reporturl' => 'http://laconi.ca/stats/report'),
|
||||||
|
'attachments' =>
|
||||||
|
array('supported' => array('image/png',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/gif',
|
||||||
|
'image/svg+xml',
|
||||||
|
'audio/mpeg',
|
||||||
|
'audio/x-speex',
|
||||||
|
'application/ogg',
|
||||||
|
'application/pdf',
|
||||||
|
'application/vnd.oasis.opendocument.text',
|
||||||
|
'application/vnd.oasis.opendocument.text-template',
|
||||||
|
'application/vnd.oasis.opendocument.graphics',
|
||||||
|
'application/vnd.oasis.opendocument.graphics-template',
|
||||||
|
'application/vnd.oasis.opendocument.presentation',
|
||||||
|
'application/vnd.oasis.opendocument.presentation-template',
|
||||||
|
'application/vnd.oasis.opendocument.spreadsheet',
|
||||||
|
'application/vnd.oasis.opendocument.spreadsheet-template',
|
||||||
|
'application/vnd.oasis.opendocument.chart',
|
||||||
|
'application/vnd.oasis.opendocument.chart-template',
|
||||||
|
'application/vnd.oasis.opendocument.image',
|
||||||
|
'application/vnd.oasis.opendocument.image-template',
|
||||||
|
'application/vnd.oasis.opendocument.formula',
|
||||||
|
'application/vnd.oasis.opendocument.formula-template',
|
||||||
|
'application/vnd.oasis.opendocument.text-master',
|
||||||
|
'application/vnd.oasis.opendocument.text-web',
|
||||||
|
'application/x-zip',
|
||||||
|
'application/zip',
|
||||||
|
'text/plain',
|
||||||
|
'video/mpeg',
|
||||||
|
'video/mp4',
|
||||||
|
'video/quicktime',
|
||||||
|
'video/mpeg'),
|
||||||
|
'file_quota' => 5000000,
|
||||||
|
'user_quota' => 50000000,
|
||||||
|
'monthly_quota' => 15000000,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
|
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
|
||||||
@ -170,6 +210,7 @@ $config['db'] =
|
|||||||
'require_prefix' => 'classes/',
|
'require_prefix' => 'classes/',
|
||||||
'class_prefix' => '',
|
'class_prefix' => '',
|
||||||
'mirror' => null,
|
'mirror' => null,
|
||||||
|
'utf8' => true,
|
||||||
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
||||||
'quote_identifiers' => false,
|
'quote_identifiers' => false,
|
||||||
'type' => 'mysql' );
|
'type' => 'mysql' );
|
||||||
@ -219,19 +260,19 @@ if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db']
|
|||||||
|
|
||||||
// XXX: how many of these could be auto-loaded on use?
|
// XXX: how many of these could be auto-loaded on use?
|
||||||
|
|
||||||
require_once('Validate.php');
|
require_once 'Validate.php';
|
||||||
require_once('markdown.php');
|
require_once 'markdown.php';
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/util.php');
|
require_once INSTALLDIR.'/lib/util.php';
|
||||||
require_once(INSTALLDIR.'/lib/action.php');
|
require_once INSTALLDIR.'/lib/action.php';
|
||||||
require_once(INSTALLDIR.'/lib/theme.php');
|
require_once INSTALLDIR.'/lib/theme.php';
|
||||||
require_once(INSTALLDIR.'/lib/mail.php');
|
require_once INSTALLDIR.'/lib/mail.php';
|
||||||
require_once(INSTALLDIR.'/lib/subs.php');
|
require_once INSTALLDIR.'/lib/subs.php';
|
||||||
require_once(INSTALLDIR.'/lib/Shorturl_api.php');
|
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||||
require_once(INSTALLDIR.'/lib/twitter.php');
|
require_once INSTALLDIR.'/lib/twitter.php';
|
||||||
|
|
||||||
require_once(INSTALLDIR.'/lib/clientexception.php');
|
require_once INSTALLDIR.'/lib/clientexception.php';
|
||||||
require_once(INSTALLDIR.'/lib/serverexception.php');
|
require_once INSTALLDIR.'/lib/serverexception.php';
|
||||||
|
|
||||||
// XXX: other formats here
|
// XXX: other formats here
|
||||||
|
|
||||||
|
@ -98,9 +98,9 @@ class FacebookAction extends Action
|
|||||||
// Add a timestamp to the file so Facebook cache wont ignore our changes
|
// Add a timestamp to the file so Facebook cache wont ignore our changes
|
||||||
$ts = filemtime(INSTALLDIR.'/theme/base/css/display.css');
|
$ts = filemtime(INSTALLDIR.'/theme/base/css/display.css');
|
||||||
|
|
||||||
$this->element('link', array('rel' => 'stylesheet',
|
$this->element('link', array('rel' => 'stylesheet',
|
||||||
'type' => 'text/css',
|
'type' => 'text/css',
|
||||||
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
||||||
|
|
||||||
$theme = common_config('site', 'theme');
|
$theme = common_config('site', 'theme');
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ class FacebookAction extends Action
|
|||||||
$this->element('a',
|
$this->element('a',
|
||||||
array('href' => common_local_url('register')), _('Register'));
|
array('href' => common_local_url('register')), _('Register'));
|
||||||
$this->text($loginmsg_part2);
|
$this->text($loginmsg_part2);
|
||||||
$this->elementEnd('p');
|
$this->elementEnd('p');
|
||||||
$this->elementEnd('dd');
|
$this->elementEnd('dd');
|
||||||
|
|
||||||
$this->elementEnd('dl');
|
$this->elementEnd('dl');
|
||||||
@ -317,7 +317,7 @@ class FacebookAction extends Action
|
|||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
$this->submit('submit', _('Login'));
|
$this->submit('submit', _('Login'));
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
|
|
||||||
$this->elementStart('p');
|
$this->elementStart('p');
|
||||||
@ -336,65 +336,65 @@ class FacebookAction extends Action
|
|||||||
|
|
||||||
// Need to include inline CSS for styling the Profile box
|
// Need to include inline CSS for styling the Profile box
|
||||||
|
|
||||||
$app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
|
$app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
|
||||||
$icon_url = $app_props['icon_url'];
|
$icon_url = $app_props['icon_url'];
|
||||||
|
|
||||||
$style = '<style>
|
$style = '<style>
|
||||||
.entry-title *,
|
.entry-title *,
|
||||||
.entry-content * {
|
.entry-content * {
|
||||||
font-size:14px;
|
font-size:14px;
|
||||||
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||||
}
|
}
|
||||||
.entry-title a,
|
.entry-title a,
|
||||||
.entry-content a {
|
.entry-content a {
|
||||||
color:#002E6E;
|
color:#002E6E;
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry-title .vcard .photo {
|
.entry-title .vcard .photo {
|
||||||
float:left;
|
float:left;
|
||||||
display:inline;
|
display:inline;
|
||||||
margin-right:11px;
|
margin-right:11px;
|
||||||
margin-bottom:11px
|
margin-bottom:11px
|
||||||
}
|
}
|
||||||
.entry-title {
|
.entry-title {
|
||||||
margin-bottom:11px;
|
margin-bottom:11px;
|
||||||
}
|
}
|
||||||
.entry-title p.entry-content {
|
.entry-title p.entry-content {
|
||||||
display:inline;
|
display:inline;
|
||||||
margin-left:5px;
|
margin-left:5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.entry-content {
|
div.entry-content {
|
||||||
clear:both;
|
clear:both;
|
||||||
}
|
}
|
||||||
div.entry-content dl,
|
div.entry-content dl,
|
||||||
div.entry-content dt,
|
div.entry-content dt,
|
||||||
div.entry-content dd {
|
div.entry-content dd {
|
||||||
display:inline;
|
display:inline;
|
||||||
text-transform:lowercase;
|
text-transform:lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.entry-content dd,
|
div.entry-content dd,
|
||||||
div.entry-content .device dt {
|
div.entry-content .device dt {
|
||||||
margin-left:0;
|
margin-left:0;
|
||||||
margin-right:5px;
|
margin-right:5px;
|
||||||
}
|
}
|
||||||
div.entry-content dl.timestamp dt,
|
div.entry-content dl.timestamp dt,
|
||||||
div.entry-content dl.response dt {
|
div.entry-content dl.response dt {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
div.entry-content dd a {
|
div.entry-content dd a {
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
#facebook_laconica_app {
|
#facebook_laconica_app {
|
||||||
text-indent:-9999px;
|
text-indent:-9999px;
|
||||||
height:16px;
|
height:16px;
|
||||||
width:16px;
|
width:16px;
|
||||||
display:block;
|
display:block;
|
||||||
background:url('.$icon_url.') no-repeat 0 0;
|
background:url('.$icon_url.') no-repeat 0 0;
|
||||||
float:right;
|
float:right;
|
||||||
}
|
}
|
||||||
</style>';
|
</style>';
|
||||||
|
|
||||||
$this->xw->openMemory();
|
$this->xw->openMemory();
|
||||||
@ -646,48 +646,16 @@ class FacebookNoticeListItem extends NoticeListItem
|
|||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
$this->showStart();
|
$this->showStart();
|
||||||
|
$this->showNotice();
|
||||||
|
$this->showNoticeInfo();
|
||||||
|
|
||||||
$this->out->elementStart('div', 'entry-title');
|
// XXX: Need to update to show attachements and controls
|
||||||
$this->showAuthor();
|
|
||||||
$this->showContent();
|
|
||||||
$this->out->elementEnd('div');
|
|
||||||
|
|
||||||
$this->out->elementStart('div', 'entry-content');
|
|
||||||
$this->showNoticeLink();
|
|
||||||
$this->showNoticeSource();
|
|
||||||
$this->showReplyTo();
|
|
||||||
$this->out->elementEnd('div');
|
|
||||||
|
|
||||||
$this->showEnd();
|
$this->showEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNoticeLink()
|
|
||||||
{
|
|
||||||
$noticeurl = common_local_url('shownotice',
|
|
||||||
array('notice' => $this->notice->id));
|
|
||||||
// XXX: we need to figure this out better. Is this right?
|
|
||||||
if (strcmp($this->notice->uri, $noticeurl) != 0 &&
|
|
||||||
preg_match('/^http/', $this->notice->uri)) {
|
|
||||||
$noticeurl = $this->notice->uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->out->elementStart('dl', 'timestamp');
|
|
||||||
$this->out->element('dt', null, _('Published'));
|
|
||||||
$this->out->elementStart('dd', null);
|
|
||||||
$this->out->elementStart('a', array('rel' => 'bookmark',
|
|
||||||
'href' => $noticeurl));
|
|
||||||
$dt = common_date_iso8601($this->notice->created);
|
|
||||||
$this->out->element('abbr', array('class' => 'published',
|
|
||||||
'title' => $dt),
|
|
||||||
common_date_string($this->notice->created));
|
|
||||||
$this->out->elementEnd('a');
|
|
||||||
$this->out->elementEnd('dd');
|
|
||||||
$this->out->elementEnd('dl');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -706,28 +674,16 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Recipe function for displaying a single notice in the
|
* Recipe function for displaying a single notice in the
|
||||||
* Facebook App's Profile
|
* Facebook App profile notice box
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
|
$this->showNotice();
|
||||||
$this->out->elementStart('div', 'entry-title');
|
$this->showNoticeInfo();
|
||||||
$this->showAuthor();
|
|
||||||
$this->showContent();
|
|
||||||
$this->out->elementEnd('div');
|
|
||||||
|
|
||||||
$this->out->elementStart('div', 'entry-content');
|
|
||||||
|
|
||||||
$this->showNoticeLink();
|
|
||||||
$this->showNoticeSource();
|
|
||||||
$this->showReplyTo();
|
|
||||||
$this->out->elementEnd('div');
|
|
||||||
|
|
||||||
$this->showAppLink();
|
$this->showAppLink();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAppLink()
|
function showAppLink()
|
||||||
|
16
lib/form.php
16
lib/form.php
@ -52,6 +52,8 @@ require_once INSTALLDIR.'/lib/widget.php';
|
|||||||
|
|
||||||
class Form extends Widget
|
class Form extends Widget
|
||||||
{
|
{
|
||||||
|
var $enctype = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form
|
* Show the form
|
||||||
*
|
*
|
||||||
@ -63,11 +65,15 @@ class Form extends Widget
|
|||||||
|
|
||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
$this->out->elementStart('form',
|
$attributes = array('id' => $this->id(),
|
||||||
array('id' => $this->id(),
|
'class' => $this->formClass(),
|
||||||
'class' => $this->formClass(),
|
'method' => 'post',
|
||||||
'method' => 'post',
|
'action' => $this->action());
|
||||||
'action' => $this->action()));
|
|
||||||
|
if (!empty($this->enctype)) {
|
||||||
|
$attributes['enctype'] = $this->enctype;
|
||||||
|
}
|
||||||
|
$this->out->elementStart('form', $attributes);
|
||||||
$this->out->elementStart('fieldset');
|
$this->out->elementStart('fieldset');
|
||||||
$this->formLegend();
|
$this->formLegend();
|
||||||
$this->sessionToken();
|
$this->sessionToken();
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
<?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';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -90,6 +90,7 @@ class NoticeForm extends Form
|
|||||||
$this->user = common_current_user();
|
$this->user = common_current_user();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->enctype = 'multipart/form-data';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,17 +143,21 @@ class NoticeForm extends Form
|
|||||||
'rows' => 4,
|
'rows' => 4,
|
||||||
'name' => 'status_textarea'),
|
'name' => 'status_textarea'),
|
||||||
($this->content) ? $this->content : '');
|
($this->content) ? $this->content : '');
|
||||||
|
|
||||||
$this->out->elementStart('dl', 'form_note');
|
$this->out->elementStart('dl', 'form_note');
|
||||||
$this->out->element('dt', null, _('Available characters'));
|
$this->out->element('dt', null, _('Available characters'));
|
||||||
$this->out->element('dd', array('id' => 'notice_text-count'),
|
$this->out->element('dd', array('id' => 'notice_text-count'),
|
||||||
'140');
|
'140');
|
||||||
$this->out->elementEnd('dl');
|
$this->out->elementEnd('dl');
|
||||||
|
$this->out->element('label', array('for' => 'notice_data-attach'), _('Attach'));
|
||||||
|
$this->out->element('input', array('id' => 'notice_data-attach',
|
||||||
|
'type' => 'file',
|
||||||
|
'name' => 'attach',
|
||||||
|
'title' => _('Attach a file')));
|
||||||
if ($this->action) {
|
if ($this->action) {
|
||||||
$this->out->hidden('notice_return-to', $this->action, 'returnto');
|
$this->out->hidden('notice_return-to', $this->action, 'returnto');
|
||||||
}
|
}
|
||||||
$this->out->hidden('notice_in-reply-to', $this->action, 'inreplyto');
|
$this->out->hidden('notice_in-reply-to', $this->action, 'inreplyto');
|
||||||
|
$this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,6 +34,7 @@ if (!defined('LACONICA')) {
|
|||||||
|
|
||||||
require_once INSTALLDIR.'/lib/favorform.php';
|
require_once INSTALLDIR.'/lib/favorform.php';
|
||||||
require_once INSTALLDIR.'/lib/disfavorform.php';
|
require_once INSTALLDIR.'/lib/disfavorform.php';
|
||||||
|
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* widget for displaying a list of notices
|
* widget for displaying a list of notices
|
||||||
@ -85,7 +86,7 @@ class NoticeList extends Widget
|
|||||||
{
|
{
|
||||||
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||||
$this->out->element('h2', null, _('Notices'));
|
$this->out->element('h2', null, _('Notices'));
|
||||||
$this->out->elementStart('ul', array('class' => 'notices'));
|
$this->out->elementStart('ol', array('class' => 'notices xoxo'));
|
||||||
|
|
||||||
$cnt = 0;
|
$cnt = 0;
|
||||||
|
|
||||||
@ -100,7 +101,7 @@ class NoticeList extends Widget
|
|||||||
$item->show();
|
$item->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ol');
|
||||||
$this->out->elementEnd('div');
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
return $cnt;
|
return $cnt;
|
||||||
@ -180,86 +181,49 @@ class NoticeListItem extends Widget
|
|||||||
$this->showStart();
|
$this->showStart();
|
||||||
$this->showNotice();
|
$this->showNotice();
|
||||||
$this->showNoticeAttachments();
|
$this->showNoticeAttachments();
|
||||||
$this->showNoticeOptions();
|
|
||||||
$this->showNoticeInfo();
|
$this->showNoticeInfo();
|
||||||
|
$this->showNoticeOptions();
|
||||||
$this->showEnd();
|
$this->showEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNotice()
|
function showNotice()
|
||||||
{
|
{
|
||||||
if(0)
|
$this->out->elementStart('div', 'entry-title');
|
||||||
$this->out->elementStart('entry-title');
|
|
||||||
else
|
|
||||||
|
|
||||||
if ('shownotice' === $this->out->args['action']) {
|
|
||||||
$width = '85%';
|
|
||||||
} else {
|
|
||||||
$width = '90%';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$this->out->elementStart('div', array('class' => 'entry-title', 'style' => "float: left; width: $width;"));
|
|
||||||
$this->showAuthor();
|
$this->showAuthor();
|
||||||
$this->showContent();
|
$this->showContent();
|
||||||
$this->out->elementEnd('div');
|
$this->out->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNoticeAttachments()
|
function showNoticeAttachments() {
|
||||||
{
|
if ($this->isUsedInList()) {
|
||||||
$f2p = new File_to_post;
|
return;
|
||||||
$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';
|
|
||||||
}
|
}
|
||||||
|
$al = new AttachmentList($this->notice, $this->out);
|
||||||
|
$al->show();
|
||||||
|
}
|
||||||
|
|
||||||
$clip = theme_path('images/icons/clip', 'base');
|
function isUsedInList() {
|
||||||
if ('shownotice' === $this->out->args['action']) {
|
return '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);
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
function attachmentCount($discriminant = true) {
|
||||||
|
$file_oembed = new File_oembed;
|
||||||
|
$query = "select count(*) as c from file_oembed join file_to_post on file_oembed.file_id = file_to_post.file_id where post_id=" . $this->notice->id;
|
||||||
|
$file_oembed->query($query);
|
||||||
|
$file_oembed->fetch();
|
||||||
|
return intval($file_oembed->c);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
$this->out->elementEnd('p');
|
function showWithAttachment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNoticeInfo()
|
function showNoticeInfo()
|
||||||
{
|
{
|
||||||
if(0)
|
|
||||||
$this->out->elementStart('div', 'entry-content');
|
$this->out->elementStart('div', 'entry-content');
|
||||||
else
|
|
||||||
|
|
||||||
if ('shownotice' === $this->out->args['action']) {
|
|
||||||
$width = '85%';
|
|
||||||
} else {
|
|
||||||
$width = '90%';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->out->elementStart('div', array('class' => 'entry-content', 'style' => "float: left; width: $width;"));
|
|
||||||
$this->showNoticeLink();
|
$this->showNoticeLink();
|
||||||
|
// $this->showWithAttachment();
|
||||||
$this->showNoticeSource();
|
$this->showNoticeSource();
|
||||||
$this->showContext();
|
$this->showContext();
|
||||||
$this->out->elementEnd('div');
|
$this->out->elementEnd('div');
|
||||||
@ -269,10 +233,7 @@ else
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
if ($user) {
|
if ($user) {
|
||||||
if(0)
|
|
||||||
$this->out->elementStart('div', 'notice-options');
|
$this->out->elementStart('div', 'notice-options');
|
||||||
else
|
|
||||||
$this->out->elementStart('div', array('class' => 'notice-options', 'style' => 'float: right; width: 16%;'));
|
|
||||||
$this->showFaveForm();
|
$this->showFaveForm();
|
||||||
$this->showReplyLink();
|
$this->showReplyLink();
|
||||||
$this->showDeleteLink();
|
$this->showDeleteLink();
|
||||||
@ -403,6 +364,10 @@ else
|
|||||||
// versions (>> 0.4.x)
|
// versions (>> 0.4.x)
|
||||||
$this->out->raw(common_render_content($this->notice->content, $this->notice));
|
$this->out->raw(common_render_content($this->notice->content, $this->notice));
|
||||||
}
|
}
|
||||||
|
$uploaded = $this->notice->getUploadedAttachment();
|
||||||
|
if ($uploaded) {
|
||||||
|
$this->out->element('a', array('href' => $uploaded, 'class' => 'attachment'), $uploaded);
|
||||||
|
}
|
||||||
$this->out->elementEnd('p');
|
$this->out->elementEnd('p');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,6 +398,7 @@ else
|
|||||||
$this->out->element('abbr', array('class' => 'published',
|
$this->out->element('abbr', array('class' => 'published',
|
||||||
'title' => $dt),
|
'title' => $dt),
|
||||||
common_date_string($this->notice->created));
|
common_date_string($this->notice->created));
|
||||||
|
|
||||||
$this->out->elementEnd('a');
|
$this->out->elementEnd('a');
|
||||||
$this->out->elementEnd('dd');
|
$this->out->elementEnd('dd');
|
||||||
$this->out->elementEnd('dl');
|
$this->out->elementEnd('dl');
|
||||||
|
@ -52,12 +52,12 @@ class NoticeSection extends Section
|
|||||||
{
|
{
|
||||||
$notices = $this->getNotices();
|
$notices = $this->getNotices();
|
||||||
$cnt = 0;
|
$cnt = 0;
|
||||||
$this->out->elementStart('ul', 'notices');
|
$this->out->elementStart('ol', 'notices xoxo');
|
||||||
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
||||||
$this->showNotice($notices);
|
$this->showNotice($notices);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ol');
|
||||||
return ($cnt > NOTICES_PER_SECTION);
|
return ($cnt > NOTICES_PER_SECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,24 +153,21 @@ class Router
|
|||||||
|
|
||||||
$m->connect('attachment/:attachment/ajax',
|
$m->connect('attachment/:attachment/ajax',
|
||||||
array('action' => 'attachment_ajax'),
|
array('action' => 'attachment_ajax'),
|
||||||
array('notice' => '[0-9]+'));
|
array('attachment' => '[0-9]+'));
|
||||||
|
|
||||||
$m->connect('attachment/:attachment',
|
$m->connect('attachment/:attachment/thumbnail',
|
||||||
array('action' => 'attachment'),
|
array('action' => 'attachment_thumbnail'),
|
||||||
array('notice' => '[0-9]+'));
|
array('attachment' => '[0-9]+'));
|
||||||
|
|
||||||
// notice
|
|
||||||
|
|
||||||
$m->connect('notice/new', array('action' => 'newnotice'));
|
$m->connect('notice/new', array('action' => 'newnotice'));
|
||||||
$m->connect('notice/new?replyto=:replyto',
|
$m->connect('notice/new?replyto=:replyto',
|
||||||
array('action' => 'newnotice'),
|
array('action' => 'newnotice'),
|
||||||
array('replyto' => '[A-Za-z0-9_-]+'));
|
array('replyto' => '[A-Za-z0-9_-]+'));
|
||||||
$m->connect('notice/:notice/attachments/ajax',
|
|
||||||
array('action' => 'attachments_ajax'),
|
$m->connect('notice/:notice/file',
|
||||||
array('notice' => '[0-9]+'));
|
array('action' => 'file'),
|
||||||
$m->connect('notice/:notice/attachments',
|
array('notice' => '[0-9]+'));
|
||||||
array('action' => 'attachments'),
|
|
||||||
array('notice' => '[0-9]+'));
|
|
||||||
$m->connect('notice/:notice',
|
$m->connect('notice/:notice',
|
||||||
array('action' => 'shownotice'),
|
array('action' => 'shownotice'),
|
||||||
array('notice' => '[0-9]+'));
|
array('notice' => '[0-9]+'));
|
||||||
|
@ -51,7 +51,7 @@ class SearchAction extends Action
|
|||||||
*
|
*
|
||||||
* @return boolean true
|
* @return boolean true
|
||||||
*/
|
*/
|
||||||
function isReadOnly()
|
function isReadOnly($args)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
227
lib/snapshot.php
Normal file
227
lib/snapshot.php
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* A snapshot of site stats that can report itself to headquarters
|
||||||
|
*
|
||||||
|
* 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 Stats
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A snapshot of site stats that can report itself to headquarters
|
||||||
|
*
|
||||||
|
* This class will collect statistics on the site and report them to
|
||||||
|
* a statistics server of the admin's choice. (Default is the big one
|
||||||
|
* at laconi.ca.)
|
||||||
|
*
|
||||||
|
* It can either be called from a cron job, or run occasionally by the
|
||||||
|
* Web site.
|
||||||
|
*
|
||||||
|
* @category Stats
|
||||||
|
* @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 Snapshot
|
||||||
|
{
|
||||||
|
var $stats = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a snapshot
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static function for reporting statistics
|
||||||
|
*
|
||||||
|
* This function checks whether it should report statistics, based on
|
||||||
|
* the current configuation settings. If it should, it creates a new
|
||||||
|
* Snapshot object, takes a snapshot, and reports it to headquarters.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
static function check()
|
||||||
|
{
|
||||||
|
switch (common_config('snapshot', 'run')) {
|
||||||
|
case 'web':
|
||||||
|
// skip if we're not running on the Web.
|
||||||
|
if (!isset($_SERVER) || !array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Run once every frequency hits
|
||||||
|
// XXX: do frequency by time (once a week, etc.) rather than
|
||||||
|
// hits
|
||||||
|
if (rand() % common_config('snapshot', 'frequency') == 0) {
|
||||||
|
$snapshot = new Snapshot();
|
||||||
|
$snapshot->take();
|
||||||
|
$snapshot->report();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'cron':
|
||||||
|
// skip if we're running on the Web
|
||||||
|
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
common_log(LOG_INFO, 'Running snapshot from cron job');
|
||||||
|
// We're running from the command line; assume
|
||||||
|
|
||||||
|
$snapshot = new Snapshot();
|
||||||
|
$snapshot->take();
|
||||||
|
common_log(LOG_INFO, count($snapshot->stats) . " statistics being uploaded.");
|
||||||
|
$snapshot->report();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'never':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
common_log(LOG_WARNING, "Unrecognized value for snapshot run config.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a snapshot of the server
|
||||||
|
*
|
||||||
|
* Builds an array of statistical and configuration data based
|
||||||
|
* on the local database and config files. We avoid grabbing any
|
||||||
|
* information that could be personal or private.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function take()
|
||||||
|
{
|
||||||
|
$this->stats = array();
|
||||||
|
|
||||||
|
// Some basic identification stuff
|
||||||
|
|
||||||
|
$this->stats['version'] = LACONICA_VERSION;
|
||||||
|
$this->stats['phpversion'] = phpversion();
|
||||||
|
$this->stats['name'] = common_config('site', 'name');
|
||||||
|
$this->stats['root'] = common_root_url();
|
||||||
|
|
||||||
|
// non-identifying stats on various tables. Primary
|
||||||
|
// interest is size and rate of activity of service.
|
||||||
|
|
||||||
|
$tables = array('user',
|
||||||
|
'notice',
|
||||||
|
'subscription',
|
||||||
|
'remote_profile',
|
||||||
|
'user_group');
|
||||||
|
|
||||||
|
foreach ($tables as $table) {
|
||||||
|
$this->tableStats($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stats on some important config options
|
||||||
|
|
||||||
|
$this->stats['theme'] = common_config('site', 'theme');
|
||||||
|
$this->stats['dbtype'] = common_config('db', 'type');
|
||||||
|
$this->stats['xmpp'] = common_config('xmpp', 'enabled');
|
||||||
|
$this->stats['inboxes'] = common_config('inboxes', 'enabled');
|
||||||
|
$this->stats['queue'] = common_config('queue', 'enabled');
|
||||||
|
$this->stats['license'] = common_config('license', 'url');
|
||||||
|
$this->stats['fancy'] = common_config('site', 'fancy');
|
||||||
|
$this->stats['private'] = common_config('site', 'private');
|
||||||
|
$this->stats['closed'] = common_config('site', 'closed');
|
||||||
|
$this->stats['memcached'] = common_config('memcached', 'enabled');
|
||||||
|
$this->stats['language'] = common_config('site', 'language');
|
||||||
|
$this->stats['timezone'] = common_config('site', 'timezone');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports statistics to headquarters
|
||||||
|
*
|
||||||
|
* Posts statistics to a reporting server.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function report()
|
||||||
|
{
|
||||||
|
// XXX: Use OICU2 and OAuth to make authorized requests
|
||||||
|
|
||||||
|
$postdata = http_build_query($this->stats);
|
||||||
|
|
||||||
|
$opts =
|
||||||
|
array('http' =>
|
||||||
|
array(
|
||||||
|
'method' => 'POST',
|
||||||
|
'header' => 'Content-type: '.
|
||||||
|
'application/x-www-form-urlencoded',
|
||||||
|
'content' => $postdata,
|
||||||
|
'user_agent' => 'Laconica/'.LACONICA_VERSION
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$context = stream_context_create($opts);
|
||||||
|
|
||||||
|
$reporturl = common_config('snapshot', 'reporturl');
|
||||||
|
|
||||||
|
$result = @file_get_contents($reporturl, false, $context);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates statistics for a single table
|
||||||
|
*
|
||||||
|
* Determines the size of a table and its oldest and newest rows.
|
||||||
|
* Goal here is to see how active a site is. Note that it
|
||||||
|
* fills up the instance stats variable.
|
||||||
|
*
|
||||||
|
* @param string $table name of table to check
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function tableStats($table)
|
||||||
|
{
|
||||||
|
$inst = DB_DataObject::factory($table);
|
||||||
|
|
||||||
|
$inst->selectAdd();
|
||||||
|
$inst->selectAdd('count(*) as cnt, '.
|
||||||
|
'min(created) as first, '.
|
||||||
|
'max(created) as last');
|
||||||
|
|
||||||
|
if ($inst->find(true)) {
|
||||||
|
$this->stats[$table.'count'] = $inst->cnt;
|
||||||
|
$this->stats[$table.'first'] = $inst->first;
|
||||||
|
$this->stats[$table.'last'] = $inst->last;
|
||||||
|
}
|
||||||
|
|
||||||
|
$inst->free();
|
||||||
|
unset($inst);
|
||||||
|
}
|
||||||
|
}
|
26
lib/util.php
26
lib/util.php
@ -496,6 +496,32 @@ function common_linkify($url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$attrs = array('href' => $longurl, 'rel' => 'external');
|
$attrs = array('href' => $longurl, 'rel' => 'external');
|
||||||
|
|
||||||
|
// if this URL is an attachment, then we set class='attachment' and id='attahcment-ID'
|
||||||
|
// where ID is the id of the attachment for the given URL.
|
||||||
|
//
|
||||||
|
// we need a better test telling what can be shown as an attachment
|
||||||
|
// we're currently picking up oembeds only.
|
||||||
|
// I think the best option is another file_view table in the db
|
||||||
|
// and associated dbobject.
|
||||||
|
$query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'";
|
||||||
|
$file = new File;
|
||||||
|
$file->query($query);
|
||||||
|
$file->fetch();
|
||||||
|
|
||||||
|
if (!empty($file->file_id)) {
|
||||||
|
$query = "select file_thumbnail.file_id as file_id from file join file_thumbnail on file.id = file_thumbnail.file_id where file.url='$longurl'";
|
||||||
|
$file2 = new File;
|
||||||
|
$file2->query($query);
|
||||||
|
$file2->fetch();
|
||||||
|
|
||||||
|
if (empty($file2->file_id)) {
|
||||||
|
$attrs['class'] = 'attachment';
|
||||||
|
} else {
|
||||||
|
$attrs['class'] = 'attachment thumbnail';
|
||||||
|
}
|
||||||
|
$attrs['id'] = "attachment-{$file->file_id}";
|
||||||
|
}
|
||||||
return XMLStringer::estring('a', $attrs, $display);
|
return XMLStringer::estring('a', $attrs, $display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
110
plugins/FBConnect/FBCLoginGroupNav.php
Normal file
110
plugins/FBConnect/FBCLoginGroupNav.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Menu for login group of actions
|
||||||
|
*
|
||||||
|
* 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 Menu
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @author Zach Copley <zach@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/widget.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menu for login group of actions
|
||||||
|
*
|
||||||
|
* @category Output
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @author Zach Copley <zach@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 Widget
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FBCLoginGroupNav extends Widget
|
||||||
|
{
|
||||||
|
var $action = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construction
|
||||||
|
*
|
||||||
|
* @param Action $action current action, used for output
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __construct($action=null)
|
||||||
|
{
|
||||||
|
parent::__construct($action);
|
||||||
|
$this->action = $action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the menu
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$this->action->elementStart('dl', array('id' => 'site_nav_local_views'));
|
||||||
|
$this->action->element('dt', null, _('Local views'));
|
||||||
|
$this->action->elementStart('dd');
|
||||||
|
|
||||||
|
// action => array('prompt', 'title')
|
||||||
|
$menu = array();
|
||||||
|
|
||||||
|
$menu['login'] = array(_('Login'),
|
||||||
|
_('Login with a username and password'));
|
||||||
|
|
||||||
|
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||||
|
$menu['register'] = array(_('Register'),
|
||||||
|
_('Sign up for a new account'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu['openidlogin'] = array(_('OpenID'),
|
||||||
|
_('Login or register with OpenID'));
|
||||||
|
|
||||||
|
$menu['FBConnectLogin'] = array(_('Facebook'),
|
||||||
|
_('Login or register using Facebook'));
|
||||||
|
|
||||||
|
$action_name = $this->action->trimmed('action');
|
||||||
|
$this->action->elementStart('ul', array('class' => 'nav'));
|
||||||
|
|
||||||
|
foreach ($menu as $menuaction => $menudesc) {
|
||||||
|
$this->action->menuItem(common_local_url($menuaction),
|
||||||
|
$menudesc[0],
|
||||||
|
$menudesc[1],
|
||||||
|
$action_name === $menuaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->action->elementEnd('ul');
|
||||||
|
|
||||||
|
$this->action->elementEnd('dd');
|
||||||
|
$this->action->elementEnd('dl');
|
||||||
|
}
|
||||||
|
}
|
113
plugins/FBConnect/FBCSettingsNav.php
Normal file
113
plugins/FBConnect/FBCSettingsNav.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Menu for login group of actions
|
||||||
|
*
|
||||||
|
* 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 Menu
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @author Zach Copley <zach@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/widget.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A widget for showing the connect group local nav menu
|
||||||
|
*
|
||||||
|
* @category Output
|
||||||
|
* @package Laconica
|
||||||
|
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||||
|
* @author Zach Copley <zach@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 Widget
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FBCSettingsNav extends Widget
|
||||||
|
{
|
||||||
|
var $action = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construction
|
||||||
|
*
|
||||||
|
* @param Action $action current action, used for output
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __construct($action=null)
|
||||||
|
{
|
||||||
|
parent::__construct($action);
|
||||||
|
$this->action = $action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the menu
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->action->elementStart('dl', array('id' => 'site_nav_local_views'));
|
||||||
|
$this->action->element('dt', null, _('Local views'));
|
||||||
|
$this->action->elementStart('dd');
|
||||||
|
|
||||||
|
# action => array('prompt', 'title')
|
||||||
|
$menu =
|
||||||
|
array('imsettings' =>
|
||||||
|
array(_('IM'),
|
||||||
|
_('Updates by instant messenger (IM)')),
|
||||||
|
'smssettings' =>
|
||||||
|
array(_('SMS'),
|
||||||
|
_('Updates by SMS')),
|
||||||
|
'twittersettings' =>
|
||||||
|
array(_('Twitter'),
|
||||||
|
_('Twitter integration options')),
|
||||||
|
'FBConnectSettings' =>
|
||||||
|
array(_('Facebook'),
|
||||||
|
_('Facebook Connect settings')));
|
||||||
|
|
||||||
|
$action_name = $this->action->trimmed('action');
|
||||||
|
$this->action->elementStart('ul', array('class' => 'nav'));
|
||||||
|
|
||||||
|
foreach ($menu as $menuaction => $menudesc) {
|
||||||
|
if ($menuaction == 'imsettings' &&
|
||||||
|
!common_config('xmpp', 'enabled')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->action->menuItem(common_local_url($menuaction),
|
||||||
|
$menudesc[0],
|
||||||
|
$menudesc[1],
|
||||||
|
$action_name === $menuaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->action->elementEnd('ul');
|
||||||
|
|
||||||
|
$this->action->elementEnd('dd');
|
||||||
|
$this->action->elementEnd('dl');
|
||||||
|
}
|
||||||
|
}
|
73
plugins/FBConnect/FBC_XDReceiver.php
Normal file
73
plugins/FBConnect/FBC_XDReceiver.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates the cross domain communication channel file
|
||||||
|
* (xd_receiver.html). By generating it we can add some caching
|
||||||
|
* instructions.
|
||||||
|
*
|
||||||
|
* See: http://wiki.developers.facebook.com/index.php/Cross_Domain_Communication_Channel
|
||||||
|
*/
|
||||||
|
class FBC_XDReceiverAction extends Action
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do we need to write to the database?
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isReadonly()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a request
|
||||||
|
*
|
||||||
|
* @param array $args Arguments from $_REQUEST
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
// Parent handling, including cache check
|
||||||
|
parent::handle($args);
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPage()
|
||||||
|
{
|
||||||
|
// cache the xd_receiver
|
||||||
|
header('Cache-Control: max-age=225065900');
|
||||||
|
header('Expires:');
|
||||||
|
header('Pragma:');
|
||||||
|
|
||||||
|
$this->startXML('html',
|
||||||
|
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
||||||
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
||||||
|
|
||||||
|
$language = $this->getLanguage();
|
||||||
|
|
||||||
|
$this->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
|
||||||
|
'xml:lang' => $language,
|
||||||
|
'lang' => $language));
|
||||||
|
$this->elementStart('head');
|
||||||
|
$this->element('title', null, 'cross domain receiver page');
|
||||||
|
$this->element('script',
|
||||||
|
array('src' =>
|
||||||
|
'http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js',
|
||||||
|
'type' => 'text/javascript'), '');
|
||||||
|
$this->elementEnd('head');
|
||||||
|
$this->elementStart('body');
|
||||||
|
$this->elementEnd('body');
|
||||||
|
|
||||||
|
$this->elementEnd('html');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
454
plugins/FBConnect/FBConnectAuth.php
Normal file
454
plugins/FBConnect/FBConnectAuth.php
Normal file
@ -0,0 +1,454 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Plugin to enable Facebook Connect
|
||||||
|
*
|
||||||
|
* 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 Zach Copley <zach@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/
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectPlugin.php';
|
||||||
|
|
||||||
|
class FBConnectauthAction extends Action
|
||||||
|
{
|
||||||
|
|
||||||
|
var $fbuid = null;
|
||||||
|
var $fb_fields = null;
|
||||||
|
|
||||||
|
function prepare($args) {
|
||||||
|
parent::prepare($args);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$this->fbuid = getFacebook()->get_loggedin_user();
|
||||||
|
|
||||||
|
if ($this->fbuid > 0) {
|
||||||
|
$this->fb_fields = $this->getFacebookFields($this->fbuid,
|
||||||
|
array('first_name', 'last_name', 'name'));
|
||||||
|
} else {
|
||||||
|
common_debug("No Facebook User found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_WARNING, 'Problem getting Facebook uid: ' .
|
||||||
|
$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
|
||||||
|
if (common_is_real_login()) {
|
||||||
|
|
||||||
|
// User is already logged in. Does she already have a linked Facebook acct?
|
||||||
|
$flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_CONNECT_SERVICE);
|
||||||
|
|
||||||
|
if ($flink) {
|
||||||
|
|
||||||
|
// User already has a linked Facebook account and shouldn't be here
|
||||||
|
common_debug('There is already a local user (' . $flink->user_id .
|
||||||
|
') linked with this Facebook (' . $this->fbuid . ').');
|
||||||
|
|
||||||
|
// We don't want these cookies
|
||||||
|
getFacebook()->clear_cookie_state();
|
||||||
|
|
||||||
|
$this->clientError(_('There is already a local user linked with this Facebook.'));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// User came from the Facebook connect settings tab, and
|
||||||
|
// probably just wants to link/relink their Facebook account
|
||||||
|
$this->connectUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
|
|
||||||
|
$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 ($this->arg('create')) {
|
||||||
|
if (!$this->boolean('license')) {
|
||||||
|
$this->showForm(_('You can\'t register if you don\'t agree to the license.'),
|
||||||
|
$this->trimmed('newname'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->createNewUser();
|
||||||
|
} else if ($this->arg('connect')) {
|
||||||
|
$this->connectNewUser();
|
||||||
|
} else {
|
||||||
|
common_debug(print_r($this->args, true), __FILE__);
|
||||||
|
$this->showForm(_('Something weird happened.'),
|
||||||
|
$this->trimmed('newname'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->tryLogin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPageNotice()
|
||||||
|
{
|
||||||
|
if ($this->error) {
|
||||||
|
$this->element('div', array('class' => 'error'), $this->error);
|
||||||
|
} else {
|
||||||
|
$this->element('div', 'instructions',
|
||||||
|
sprintf(_('This is the first time you\'ve logged into %s so we must connect your Facebook to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('Facebook Account Setup');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showForm($error=null, $username=null)
|
||||||
|
{
|
||||||
|
$this->error = $error;
|
||||||
|
$this->username = $username;
|
||||||
|
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPage()
|
||||||
|
{
|
||||||
|
parent::showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
if (!empty($this->message_text)) {
|
||||||
|
$this->element('p', null, $this->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementStart('form', array('method' => 'post',
|
||||||
|
'id' => 'form_settings_facebook_connect',
|
||||||
|
'class' => 'form_settings',
|
||||||
|
'action' => common_local_url('FBConnectAuth')));
|
||||||
|
$this->elementStart('fieldset', array('id' => 'settings_facebook_connect_options'));
|
||||||
|
$this->element('legend', null, _('Connection options'));
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->element('input', array('type' => 'checkbox',
|
||||||
|
'id' => 'license',
|
||||||
|
'class' => 'checkbox',
|
||||||
|
'name' => 'license',
|
||||||
|
'value' => 'true'));
|
||||||
|
$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'));
|
||||||
|
$this->text(_(' except this private data: password, email address, IM address, phone number.'));
|
||||||
|
$this->elementEnd('label');
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
$this->element('legend', null,
|
||||||
|
_('Create new account'));
|
||||||
|
$this->element('p', null,
|
||||||
|
_('Create a new user with this nickname.'));
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->input('newname', _('New nickname'),
|
||||||
|
($this->username) ? $this->username : '',
|
||||||
|
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
$this->submit('create', _('Create'));
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
$this->element('legend', null,
|
||||||
|
_('Connect existing account'));
|
||||||
|
$this->element('p', null,
|
||||||
|
_('If you already have an account, login with your username and password to connect it to your Facebook.'));
|
||||||
|
$this->elementStart('ul', 'form_data');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->input('nickname', _('Existing nickname'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementStart('li');
|
||||||
|
$this->password('password', _('Password'));
|
||||||
|
$this->elementEnd('li');
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
$this->submit('connect', _('Connect'));
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
function message($msg)
|
||||||
|
{
|
||||||
|
$this->message_text = $msg;
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNewUser()
|
||||||
|
{
|
||||||
|
|
||||||
|
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,
|
||||||
|
'max_length' => 64,
|
||||||
|
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||||
|
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!User::allowed_nickname($nickname)) {
|
||||||
|
$this->showForm(_('Nickname not allowed.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (User::staticGet('nickname', $nickname)) {
|
||||||
|
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fullname = trim($this->fb_fields['firstname'] .
|
||||||
|
' ' . $this->fb_fields['lastname']);
|
||||||
|
|
||||||
|
$args = array('nickname' => $nickname, 'fullname' => $fullname);
|
||||||
|
|
||||||
|
if (!empty($invite)) {
|
||||||
|
$args['code'] = $invite->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::register($args);
|
||||||
|
|
||||||
|
$result = $this->flinkUser($user->id, $this->fbuid);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
$this->serverError(_('Error connecting user to Facebook.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_set_user($user);
|
||||||
|
common_real_login(true);
|
||||||
|
|
||||||
|
common_debug("Registered new user $user->id from Facebook user $this->fbuid");
|
||||||
|
|
||||||
|
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
|
||||||
|
303);
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectNewUser()
|
||||||
|
{
|
||||||
|
$nickname = $this->trimmed('nickname');
|
||||||
|
$password = $this->trimmed('password');
|
||||||
|
|
||||||
|
if (!common_check_user($nickname, $password)) {
|
||||||
|
$this->showForm(_('Invalid username or password.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::staticGet('nickname', $nickname);
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
common_debug("Legit user to connect to Facebook: $nickname");
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->flinkUser($user->id, $this->fbuid);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
$this->serverError(_('Error connecting user to Facebook.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_debug("Connected Facebook user $this->fbuid to local user $user->id");
|
||||||
|
|
||||||
|
common_set_user($user);
|
||||||
|
common_real_login(true);
|
||||||
|
|
||||||
|
$this->goHome($user->nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectUser()
|
||||||
|
{
|
||||||
|
$user = common_current_user();
|
||||||
|
|
||||||
|
$result = $this->flinkUser($user->id, $this->fbuid);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
$this->serverError(_('Error connecting user to Facebook.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_debug("Connected Facebook user $this->fbuid to local user $user->id");
|
||||||
|
|
||||||
|
// Return to Facebook connection settings tab
|
||||||
|
common_redirect(common_local_url('FBConnectSettings'), 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryLogin()
|
||||||
|
{
|
||||||
|
common_debug("Trying Facebook Login...");
|
||||||
|
|
||||||
|
$flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_CONNECT_SERVICE);
|
||||||
|
|
||||||
|
if ($flink) {
|
||||||
|
$user = $flink->getUser();
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
|
||||||
|
common_debug("Logged in Facebook user $flink->foreign_id as user $user->id ($user->nickname)");
|
||||||
|
|
||||||
|
common_set_user($user);
|
||||||
|
common_real_login(true);
|
||||||
|
$this->goHome($user->nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
common_debug("No flink found for fbuid: $this->fbuid");
|
||||||
|
|
||||||
|
$this->showForm(null, $this->bestNewNickname());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goHome($nickname)
|
||||||
|
{
|
||||||
|
$url = common_get_returnto();
|
||||||
|
if ($url) {
|
||||||
|
// We don't have to return to it again
|
||||||
|
common_set_returnto(null);
|
||||||
|
} else {
|
||||||
|
$url = common_local_url('all',
|
||||||
|
array('nickname' =>
|
||||||
|
$nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
common_redirect($url, 303);
|
||||||
|
}
|
||||||
|
|
||||||
|
function flinkUser($user_id, $fbuid)
|
||||||
|
{
|
||||||
|
$flink = new Foreign_link();
|
||||||
|
$flink->user_id = $user_id;
|
||||||
|
$flink->foreign_id = $fbuid;
|
||||||
|
$flink->service = FACEBOOK_CONNECT_SERVICE;
|
||||||
|
$flink->created = common_sql_now();
|
||||||
|
|
||||||
|
$flink_id = $flink->insert();
|
||||||
|
|
||||||
|
return $flink_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bestNewNickname()
|
||||||
|
{
|
||||||
|
if (!empty($this->fb_fields['name'])) {
|
||||||
|
$nickname = $this->nicknamize($this->fb_fields['name']);
|
||||||
|
if ($this->isNewNickname($nickname)) {
|
||||||
|
return $nickname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try the full name
|
||||||
|
|
||||||
|
$fullname = trim($this->fb_fields['firstname'] .
|
||||||
|
' ' . $this->fb_fields['lastname']);
|
||||||
|
|
||||||
|
if (!empty($fullname)) {
|
||||||
|
$fullname = $this->nicknamize($fullname);
|
||||||
|
if ($this->isNewNickname($fullname)) {
|
||||||
|
return $fullname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a string, try to make it work as a nickname
|
||||||
|
|
||||||
|
function nicknamize($str)
|
||||||
|
{
|
||||||
|
$str = preg_replace('/\W/', '', $str);
|
||||||
|
return strtolower($str);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNewNickname($str)
|
||||||
|
{
|
||||||
|
if (!Validate::string($str, array('min_length' => 1,
|
||||||
|
'max_length' => 64,
|
||||||
|
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!User::allowed_nickname($str)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (User::staticGet('nickname', $str)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: Consider moving this to lib/facebookutil.php
|
||||||
|
function getFacebookFields($fb_uid, $fields) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
$facebook = getFacebook();
|
||||||
|
|
||||||
|
$infos = $facebook->api_client->users_getInfo($fb_uid, $fields);
|
||||||
|
|
||||||
|
if (empty($infos)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return reset($infos);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_WARNING, "Facebook client failure when requesting " .
|
||||||
|
join(",", $fields) . " on uid " . $fb_uid .
|
||||||
|
" : ". $e->getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,12 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/*
|
||||||
* Laconica, the distributed open-source microblogging tool
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||||
*
|
*
|
||||||
* Plugin to enable Facebook Connect
|
* This program is free software: you can redistribute it and/or modify
|
||||||
*
|
|
||||||
* 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
|
* 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
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
@ -18,354 +15,53 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* 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/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
|
||||||
* @category Plugin
|
|
||||||
* @package Laconica
|
|
||||||
* @author Zach Copley <zach@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/
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php';
|
if (!defined('LACONICA')) {
|
||||||
require_once INSTALLDIR . '/lib/facebookutil.php';
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
class FBConnectloginAction extends Action
|
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectPlugin.php';
|
||||||
|
|
||||||
|
class FBConnectLoginAction extends Action
|
||||||
{
|
{
|
||||||
|
|
||||||
var $fbuid = null;
|
|
||||||
var $fb_fields = null;
|
|
||||||
|
|
||||||
function prepare($args) {
|
|
||||||
parent::prepare($args);
|
|
||||||
|
|
||||||
$this->fbuid = getFacebook()->get_loggedin_user();
|
|
||||||
$this->fb_fields = $this->getFacebookFields($this->fbuid,
|
|
||||||
array('first_name', 'last_name', 'name'));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
|
|
||||||
if (common_is_real_login()) {
|
if (common_is_real_login()) {
|
||||||
$this->clientError(_('Already logged in.'));
|
$this->clientError(_('Already logged in.'));
|
||||||
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
||||||
$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 ($this->arg('create')) {
|
|
||||||
if (!$this->boolean('license')) {
|
|
||||||
$this->showForm(_('You can\'t register if you don\'t agree to the license.'),
|
|
||||||
$this->trimmed('newname'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$this->createNewUser();
|
|
||||||
} else if ($this->arg('connect')) {
|
|
||||||
$this->connectUser();
|
|
||||||
} else {
|
|
||||||
common_debug(print_r($this->args, true), __FILE__);
|
|
||||||
$this->showForm(_('Something weird happened.'),
|
|
||||||
$this->trimmed('newname'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->tryLogin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInstructions()
|
||||||
|
{
|
||||||
|
return _('Login with your Facebook Account');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPageNotice()
|
function showPageNotice()
|
||||||
{
|
{
|
||||||
if ($this->error) {
|
$instr = $this->getInstructions();
|
||||||
$this->element('div', array('class' => 'error'), $this->error);
|
$output = common_markup_to_html($instr);
|
||||||
} else {
|
$this->elementStart('div', 'instructions');
|
||||||
$this->element('div', 'instructions',
|
$this->raw($output);
|
||||||
sprintf(_('This is the first time you\'ve logged into %s so we must connect your Facebook to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
|
$this->elementEnd('div');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
return _('Facebook Account Setup');
|
return _('Facebook Login');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showForm($error=null, $username=null)
|
function showContent() {
|
||||||
{
|
|
||||||
$this->error = $error;
|
|
||||||
$this->username = $username;
|
|
||||||
|
|
||||||
$this->showPage();
|
$this->elementStart('fieldset');
|
||||||
}
|
$this->element('fb:login-button', array('onlogin' => 'goto_login()',
|
||||||
|
'length' => 'long'));
|
||||||
|
|
||||||
function showPage()
|
$this->elementEnd('fieldset');
|
||||||
{
|
|
||||||
parent::showPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showContent()
|
|
||||||
{
|
|
||||||
if (!empty($this->message_text)) {
|
|
||||||
$this->element('p', null, $this->message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementStart('form', array('method' => 'post',
|
|
||||||
'id' => 'account_connect',
|
|
||||||
'action' => common_local_url('fbconnectlogin')));
|
|
||||||
$this->hidden('token', common_session_token());
|
|
||||||
$this->element('h2', null,
|
|
||||||
_('Create new account'));
|
|
||||||
$this->element('p', null,
|
|
||||||
_('Create a new user with this nickname.'));
|
|
||||||
$this->input('newname', _('New nickname'),
|
|
||||||
($this->username) ? $this->username : '',
|
|
||||||
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
|
||||||
$this->elementStart('p');
|
|
||||||
$this->element('input', array('type' => 'checkbox',
|
|
||||||
'id' => 'license',
|
|
||||||
'name' => 'license',
|
|
||||||
'value' => 'true'));
|
|
||||||
$this->text(_('My text and files are available under '));
|
|
||||||
$this->element('a', array('href' => common_config('license', 'url')),
|
|
||||||
common_config('license', 'title'));
|
|
||||||
$this->text(_(' except this private data: password, email address, IM address, phone number.'));
|
|
||||||
$this->elementEnd('p');
|
|
||||||
$this->submit('create', _('Create'));
|
|
||||||
$this->element('h2', null,
|
|
||||||
_('Connect existing account'));
|
|
||||||
$this->element('p', null,
|
|
||||||
_('If you already have an account, login with your username and password to connect it to your Facebook.'));
|
|
||||||
$this->input('nickname', _('Existing nickname'));
|
|
||||||
$this->password('password', _('Password'));
|
|
||||||
$this->submit('connect', _('Connect'));
|
|
||||||
$this->elementEnd('form');
|
|
||||||
}
|
|
||||||
|
|
||||||
function message($msg)
|
|
||||||
{
|
|
||||||
$this->message_text = $msg;
|
|
||||||
$this->showPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
function createNewUser()
|
|
||||||
{
|
|
||||||
|
|
||||||
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,
|
|
||||||
'max_length' => 64,
|
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
|
||||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!User::allowed_nickname($nickname)) {
|
|
||||||
$this->showForm(_('Nickname not allowed.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (User::staticGet('nickname', $nickname)) {
|
|
||||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fullname = trim($this->fb_fields['firstname'] .
|
|
||||||
' ' . $this->fb_fields['lastname']);
|
|
||||||
|
|
||||||
$args = array('nickname' => $nickname, 'fullname' => $fullname);
|
|
||||||
|
|
||||||
if (!empty($invite)) {
|
|
||||||
$args['code'] = $invite->code;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = User::register($args);
|
|
||||||
|
|
||||||
$result = $this->flinkUser($user->id, $this->fbuid);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
$this->serverError(_('Error connecting user to Facebook.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_set_user($user);
|
|
||||||
common_real_login(true);
|
|
||||||
|
|
||||||
common_debug("Registered new user $user->id from Facebook user $this->fbuid");
|
|
||||||
|
|
||||||
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
|
|
||||||
303);
|
|
||||||
}
|
|
||||||
|
|
||||||
function connectUser()
|
|
||||||
{
|
|
||||||
$nickname = $this->trimmed('nickname');
|
|
||||||
$password = $this->trimmed('password');
|
|
||||||
|
|
||||||
if (!common_check_user($nickname, $password)) {
|
|
||||||
$this->showForm(_('Invalid username or password.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = User::staticGet('nickname', $nickname);
|
|
||||||
|
|
||||||
if ($user) {
|
|
||||||
common_debug("Legit user to connect to Facebook: $nickname");
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $this->flinkUser($user->id, $this->fbuid);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
$this->serverError(_('Error connecting user to Facebook.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
common_debug("Connected Facebook user $this->fbuid to local user $user->id");
|
|
||||||
|
|
||||||
common_set_user($user);
|
|
||||||
common_real_login(true);
|
|
||||||
|
|
||||||
$this->goHome($user->nickname);
|
|
||||||
}
|
|
||||||
|
|
||||||
function tryLogin()
|
|
||||||
{
|
|
||||||
common_debug("Trying Facebook Login...");
|
|
||||||
|
|
||||||
$flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE);
|
|
||||||
|
|
||||||
if ($flink) {
|
|
||||||
$user = $flink->getUser();
|
|
||||||
|
|
||||||
if ($user) {
|
|
||||||
|
|
||||||
common_debug("Logged in Facebook user $flink->foreign_id as user $user->id ($user->nickname)");
|
|
||||||
|
|
||||||
common_set_user($user);
|
|
||||||
common_real_login(true);
|
|
||||||
$this->goHome($user->nickname);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$this->showForm(null, $this->bestNewNickname());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function goHome($nickname)
|
|
||||||
{
|
|
||||||
$url = common_get_returnto();
|
|
||||||
if ($url) {
|
|
||||||
// We don't have to return to it again
|
|
||||||
common_set_returnto(null);
|
|
||||||
} else {
|
|
||||||
$url = common_local_url('all',
|
|
||||||
array('nickname' =>
|
|
||||||
$nickname));
|
|
||||||
}
|
|
||||||
|
|
||||||
common_redirect($url, 303);
|
|
||||||
}
|
|
||||||
|
|
||||||
function flinkUser($user_id, $fbuid)
|
|
||||||
{
|
|
||||||
$flink = new Foreign_link();
|
|
||||||
$flink->user_id = $user_id;
|
|
||||||
$flink->foreign_id = $fbuid;
|
|
||||||
$flink->service = FACEBOOK_SERVICE;
|
|
||||||
$flink->created = common_sql_now();
|
|
||||||
|
|
||||||
$flink_id = $flink->insert();
|
|
||||||
|
|
||||||
return $flink_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
function bestNewNickname()
|
|
||||||
{
|
|
||||||
if (!empty($this->fb_fields['name'])) {
|
|
||||||
$nickname = $this->nicknamize($this->fb_fields['name']);
|
|
||||||
if ($this->isNewNickname($nickname)) {
|
|
||||||
return $nickname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try the full name
|
|
||||||
|
|
||||||
$fullname = trim($this->fb_fields['firstname'] .
|
|
||||||
' ' . $this->fb_fields['lastname']);
|
|
||||||
|
|
||||||
if (!empty($fullname)) {
|
|
||||||
$fullname = $this->nicknamize($fullname);
|
|
||||||
if ($this->isNewNickname($fullname)) {
|
|
||||||
return $fullname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a string, try to make it work as a nickname
|
|
||||||
|
|
||||||
function nicknamize($str)
|
|
||||||
{
|
|
||||||
$str = preg_replace('/\W/', '', $str);
|
|
||||||
return strtolower($str);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNewNickname($str)
|
|
||||||
{
|
|
||||||
if (!Validate::string($str, array('min_length' => 1,
|
|
||||||
'max_length' => 64,
|
|
||||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!User::allowed_nickname($str)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (User::staticGet('nickname', $str)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: Consider moving this to lib/facebookutil.php
|
|
||||||
function getFacebookFields($fb_uid, $fields) {
|
|
||||||
try {
|
|
||||||
$infos = getFacebook()->api_client->users_getInfo($fb_uid, $fields);
|
|
||||||
|
|
||||||
if (empty($infos)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return reset($infos);
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
error_log("Failure in the api when requesting " . join(",", $fields)
|
|
||||||
." on uid " . $fb_uid . " : ". $e->getMessage());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
37
plugins/FBConnect/FBConnectPlugin.css
Normal file
37
plugins/FBConnect/FBConnectPlugin.css
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/** Styles for Facebook logo and Facebook user profile avatar.
|
||||||
|
*
|
||||||
|
* @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/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#site_nav_global_primary #nav_fb {
|
||||||
|
position:relative;
|
||||||
|
margin-left:18px;
|
||||||
|
margin-right:-7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav_fb .fb_profile_pic_rendered img {
|
||||||
|
position:relative;
|
||||||
|
top:3px;
|
||||||
|
left:0;
|
||||||
|
display:inline;
|
||||||
|
border:1px solid #3B5998;
|
||||||
|
padding:1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav_fb img {
|
||||||
|
position:absolute;
|
||||||
|
top:-13px;
|
||||||
|
left:-11px;
|
||||||
|
display:inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#settings_facebook_connect_options legend {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
#form_settings_facebook_connect fieldset fieldset legend {
|
||||||
|
display:block;
|
||||||
|
}
|
@ -31,8 +31,15 @@ if (!defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php';
|
define("FACEBOOK_CONNECT_SERVICE", 3);
|
||||||
|
|
||||||
require_once INSTALLDIR . '/lib/facebookutil.php';
|
require_once INSTALLDIR . '/lib/facebookutil.php';
|
||||||
|
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectAuth.php';
|
||||||
|
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php';
|
||||||
|
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectSettings.php';
|
||||||
|
require_once INSTALLDIR . '/plugins/FBConnect/FBCLoginGroupNav.php';
|
||||||
|
require_once INSTALLDIR . '/plugins/FBConnect/FBCSettingsNav.php';
|
||||||
|
require_once INSTALLDIR . '/plugins/FBConnect/FBC_XDReceiver.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin to enable Facebook Connect
|
* Plugin to enable Facebook Connect
|
||||||
@ -46,7 +53,6 @@ require_once INSTALLDIR . '/lib/facebookutil.php';
|
|||||||
|
|
||||||
class FBConnectPlugin extends Plugin
|
class FBConnectPlugin extends Plugin
|
||||||
{
|
{
|
||||||
|
|
||||||
function __construct()
|
function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
@ -54,91 +60,91 @@ class FBConnectPlugin extends Plugin
|
|||||||
|
|
||||||
// Hook in new actions
|
// Hook in new actions
|
||||||
function onRouterInitialized(&$m) {
|
function onRouterInitialized(&$m) {
|
||||||
$m->connect('main/facebookconnect', array('action' => 'fbconnectlogin'));
|
$m->connect('main/facebookconnect', array('action' => 'FBConnectAuth'));
|
||||||
|
$m->connect('main/facebooklogin', array('action' => 'FBConnectLogin'));
|
||||||
|
$m->connect('settings/facebook', array('action' => 'FBConnectSettings'));
|
||||||
|
$m->connect('xd_receiver.html', array('action' => 'FBC_XDReceiver'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add in xmlns:fb
|
// Add in xmlns:fb
|
||||||
function onStartShowHTML($action)
|
function onStartShowHTML($action)
|
||||||
{
|
{
|
||||||
|
// XXX: Horrible hack to make Safari, FF2, and Chrome work with
|
||||||
// XXX: This is probably a bad place to do general processing
|
// Facebook Connect. These browser cannot use Facebook's
|
||||||
// so maybe I need to make some new events? Maybe in
|
// DOM parsing routines unless the mime type of the page is
|
||||||
// Action::prepare?
|
// text/html even though Facebook Connect uses XHTML. This is
|
||||||
|
// A bug in Facebook Connect, and this is a temporary solution
|
||||||
$name = get_class($action);
|
// until they fix their JavaScript libs.
|
||||||
|
header('Content-Type: text/html');
|
||||||
// Avoid a redirect loop
|
|
||||||
if (!in_array($name, array('FBConnectloginAction', 'ClientErrorAction'))) {
|
|
||||||
|
|
||||||
$this->checkFacebookUser($action);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$httpaccept = isset($_SERVER['HTTP_ACCEPT']) ?
|
|
||||||
$_SERVER['HTTP_ACCEPT'] : null;
|
|
||||||
|
|
||||||
// XXX: allow content negotiation for RDF, RSS, or XRDS
|
|
||||||
|
|
||||||
$cp = common_accept_to_prefs($httpaccept);
|
|
||||||
$sp = common_accept_to_prefs(PAGE_TYPE_PREFS);
|
|
||||||
|
|
||||||
$type = common_negotiate_type($cp, $sp);
|
|
||||||
|
|
||||||
if (!$type) {
|
|
||||||
throw new ClientException(_('This page is not available in a '.
|
|
||||||
'media type you accept'), 406);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
header('Content-Type: '.$type);
|
|
||||||
|
|
||||||
$action->extraHeaders();
|
$action->extraHeaders();
|
||||||
|
|
||||||
$action->startXML('html',
|
$action->startXML('html',
|
||||||
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
||||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
||||||
|
|
||||||
$language = $action->getLanguage();
|
$language = $action->getLanguage();
|
||||||
|
|
||||||
$action->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
|
$action->elementStart('html',
|
||||||
'xmlns:fb' => 'http://www.facebook.com/2008/fbml',
|
array('xmlns' => 'http://www.w3.org/1999/xhtml',
|
||||||
'xml:lang' => $language,
|
'xmlns:fb' => 'http://www.facebook.com/2008/fbml',
|
||||||
'lang' => $language));
|
'xml:lang' => $language,
|
||||||
|
'lang' => $language));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndShowLaconicaScripts($action)
|
// Note: this script needs to appear in the <body>
|
||||||
|
|
||||||
|
function onStartShowHeader($action)
|
||||||
|
{
|
||||||
|
$apikey = common_config('facebook', 'apikey');
|
||||||
|
$plugin_path = common_path('plugins/FBConnect');
|
||||||
|
|
||||||
|
$login_url = common_local_url('FBConnectAuth');
|
||||||
|
$logout_url = common_local_url('logout');
|
||||||
|
|
||||||
|
// XXX: Facebook says we don't need this FB_RequireFeatures(),
|
||||||
|
// but we actually do, for IE and Safari. Gar.
|
||||||
|
|
||||||
|
$html = sprintf('<script type="text/javascript">
|
||||||
|
window.onload = function () {
|
||||||
|
FB_RequireFeatures(
|
||||||
|
["XFBML"],
|
||||||
|
function() {
|
||||||
|
FB.Facebook.init("%s", "../xd_receiver.html");
|
||||||
|
}
|
||||||
|
); }
|
||||||
|
|
||||||
|
function goto_login() {
|
||||||
|
window.location = "%s";
|
||||||
|
}
|
||||||
|
|
||||||
|
function goto_logout() {
|
||||||
|
window.location = "%s";
|
||||||
|
}
|
||||||
|
</script>', $apikey,
|
||||||
|
$login_url, $logout_url);
|
||||||
|
|
||||||
|
$action->raw($html);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this script needs to appear as close as possible to </body>
|
||||||
|
|
||||||
|
function onEndShowFooter($action)
|
||||||
{
|
{
|
||||||
|
|
||||||
$action->element('script',
|
$action->element('script',
|
||||||
array('type' => 'text/javascript',
|
array('type' => 'text/javascript',
|
||||||
'src' => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
|
'src' => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
|
||||||
' ');
|
'');
|
||||||
|
}
|
||||||
|
|
||||||
$apikey = common_config('facebook', 'apikey');
|
function onEndShowLaconicaStyles($action)
|
||||||
$plugin_path = common_path('plugins/FBConnect');
|
{
|
||||||
|
$action->element('link', array('rel' => 'stylesheet',
|
||||||
$url = common_get_returnto();
|
'type' => 'text/css',
|
||||||
|
'href' => common_path('plugins/FBConnect/FBConnectPlugin.css')));
|
||||||
if ($url) {
|
|
||||||
// We don't have to return to it again
|
|
||||||
common_set_returnto(null);
|
|
||||||
} else {
|
|
||||||
$url = common_local_url('public');
|
|
||||||
}
|
|
||||||
|
|
||||||
$html = sprintf('<script type="text/javascript">FB.init("%s", "%s/xd_receiver.htm");
|
|
||||||
|
|
||||||
function refresh_page() {
|
|
||||||
window.location = "%s";
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>', $apikey, $plugin_path, $url);
|
|
||||||
|
|
||||||
|
|
||||||
$action->raw($html);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStartPrimaryNav($action)
|
function onStartPrimaryNav($action)
|
||||||
@ -146,114 +152,148 @@ class FBConnectPlugin extends Plugin
|
|||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
if ($user) {
|
if ($user) {
|
||||||
$action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
|
|
||||||
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
|
$flink = Foreign_link::getByUserId($user->id,
|
||||||
$action->menuItem(common_local_url('profilesettings'),
|
FACEBOOK_CONNECT_SERVICE);
|
||||||
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
|
$fbuid = 0;
|
||||||
if (common_config('xmpp', 'enabled')) {
|
|
||||||
$action->menuItem(common_local_url('imsettings'),
|
if ($flink) {
|
||||||
_('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$facebook = getFacebook();
|
||||||
|
$fbuid = getFacebook()->get_loggedin_user();
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_WARNING,
|
||||||
|
'Problem getting Facebook client: ' .
|
||||||
|
$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display Facebook Logged in indicator w/Facebook favicon
|
||||||
|
|
||||||
|
if ($fbuid > 0) {
|
||||||
|
|
||||||
|
$action->elementStart('li', array('id' => 'nav_fb'));
|
||||||
|
$action->elementStart('fb:profile-pic', array('uid' => $flink->foreign_id,
|
||||||
|
'linked' => 'false',
|
||||||
|
'width' => 16,
|
||||||
|
'height' => 16));
|
||||||
|
$action->elementEnd('fb:profile-pic');
|
||||||
|
|
||||||
|
$iconurl = common_path('/plugins/FBConnect/fbfavicon.ico');
|
||||||
|
$action->element('img', array('src' => $iconurl));
|
||||||
|
|
||||||
|
$action->elementEnd('li');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
|
||||||
|
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
|
||||||
|
$action->menuItem(common_local_url('profilesettings'),
|
||||||
|
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
|
||||||
|
if (common_config('xmpp', 'enabled')) {
|
||||||
|
$action->menuItem(common_local_url('imsettings'),
|
||||||
|
_('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
|
||||||
|
} else {
|
||||||
|
$action->menuItem(common_local_url('smssettings'),
|
||||||
|
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
||||||
|
}
|
||||||
|
$action->menuItem(common_local_url('invite'),
|
||||||
|
_('Invite'),
|
||||||
|
sprintf(_('Invite friends and colleagues to join you on %s'),
|
||||||
|
common_config('site', 'name')),
|
||||||
|
false, 'nav_invitecontact');
|
||||||
|
|
||||||
|
// Need to override the Logout link to make it do FB stuff
|
||||||
|
if ($flink && $fbuid > 0) {
|
||||||
|
|
||||||
|
$logout_url = common_local_url('logout');
|
||||||
|
$title = _('Logout from the site');
|
||||||
|
$text = _('Logout');
|
||||||
|
|
||||||
|
$html = sprintf('<li id="nav_logout"><a href="%s" title="%s" ' .
|
||||||
|
'onclick="FB.Connect.logout(function() { goto_logout() })">%s</a></li>',
|
||||||
|
$logout_url, $title, $text);
|
||||||
|
|
||||||
|
$action->raw($html);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$action->menuItem(common_local_url('smssettings'),
|
$action->menuItem(common_local_url('logout'),
|
||||||
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
_('Logout'), _('Logout from the site'), false, 'nav_logout');
|
||||||
}
|
}
|
||||||
$action->menuItem(common_local_url('invite'),
|
|
||||||
_('Invite'),
|
|
||||||
sprintf(_('Invite friends and colleagues to join you on %s'),
|
|
||||||
common_config('site', 'name')),
|
|
||||||
false, 'nav_invitecontact');
|
|
||||||
|
|
||||||
// Need to override the Logout link to make it do FB stuff
|
|
||||||
|
|
||||||
$logout_url = common_local_url('logout');
|
|
||||||
$title = _('Logout from the site');
|
|
||||||
$text = _('Logout');
|
|
||||||
|
|
||||||
$html = sprintf('<li id="nav_logout"><a href="%s" title="%s" ' .
|
|
||||||
'onclick="FB.Connect.logoutAndRedirect(\'%s\')">%s</a></li>',
|
|
||||||
$logout_url, $title, $logout_url, $text);
|
|
||||||
|
|
||||||
$action->raw($html);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!common_config('site', 'closed')) {
|
if (!common_config('site', 'closed')) {
|
||||||
$action->menuItem(common_local_url('register'),
|
$action->menuItem(common_local_url('register'),
|
||||||
_('Register'), _('Create an account'), false, 'nav_register');
|
_('Register'), _('Create an account'), false, 'nav_register');
|
||||||
}
|
}
|
||||||
$action->menuItem(common_local_url('openidlogin'),
|
$action->menuItem(common_local_url('openidlogin'),
|
||||||
_('OpenID'), _('Login with OpenID'), false, 'nav_openid');
|
_('OpenID'), _('Login with OpenID'), false, 'nav_openid');
|
||||||
$action->menuItem(common_local_url('login'),
|
$action->menuItem(common_local_url('login'),
|
||||||
_('Login'), _('Login to the site'), false, 'nav_login');
|
_('Login'), _('Login to the site'), false, 'nav_login');
|
||||||
}
|
}
|
||||||
|
|
||||||
$action->menuItem(common_local_url('doc', array('title' => 'help')),
|
$action->menuItem(common_local_url('doc', array('title' => 'help')),
|
||||||
_('Help'), _('Help me!'), false, 'nav_help');
|
_('Help'), _('Help me!'), false, 'nav_help');
|
||||||
$action->menuItem(common_local_url('peoplesearch'),
|
$action->menuItem(common_local_url('peoplesearch'),
|
||||||
_('Search'), _('Search for people or text'), false, 'nav_search');
|
_('Search'), _('Search for people or text'), false, 'nav_search');
|
||||||
|
|
||||||
// Tack on "Connect with Facebook" button
|
|
||||||
|
|
||||||
// XXX: Maybe this looks bad and should not go here. Where should it go?
|
|
||||||
|
|
||||||
if (!$user) {
|
|
||||||
$action->elementStart('li');
|
|
||||||
$action->element('fb:login-button', array('onlogin' => 'refresh_page()',
|
|
||||||
'length' => 'long'));
|
|
||||||
$action->elementEnd('li');
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkFacebookUser() {
|
function onStartShowLocalNavBlock($action)
|
||||||
|
{
|
||||||
|
$action_name = get_class($action);
|
||||||
|
|
||||||
|
$login_actions = array('LoginAction', 'RegisterAction',
|
||||||
|
'OpenidloginAction', 'FBConnectLoginAction');
|
||||||
|
|
||||||
|
if (in_array($action_name, $login_actions)) {
|
||||||
|
$nav = new FBCLoginGroupNav($action);
|
||||||
|
$nav->show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$connect_actions = array('SmssettingsAction',
|
||||||
|
'TwittersettingsAction', 'FBConnectSettingsAction');
|
||||||
|
|
||||||
|
if (in_array($action_name, $connect_actions)) {
|
||||||
|
$nav = new FBCSettingsNav($action);
|
||||||
|
$nav->show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartLogout($action)
|
||||||
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
if ($user) {
|
$flink = Foreign_link::getByUserId($user->id, FACEBOOK_CONNECT_SERVICE);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
$action->logout();
|
||||||
|
|
||||||
|
if ($flink) {
|
||||||
|
|
||||||
$facebook = getFacebook();
|
$facebook = getFacebook();
|
||||||
$fbuid = $facebook->get_loggedin_user();
|
|
||||||
|
|
||||||
// If you're a Facebook user and you're logged in do nothing
|
try {
|
||||||
|
$fbuid = $facebook->get_loggedin_user();
|
||||||
|
|
||||||
// If you're a Facebook user and you're not logged in
|
if ($fbuid > 0) {
|
||||||
// redirect to Facebook connect login page because that means you have clicked
|
$facebook->logout(common_local_url('public'));
|
||||||
// the 'connect with Facebook' button and have cookies
|
|
||||||
|
|
||||||
if ($fbuid > 0) {
|
|
||||||
|
|
||||||
if ($facebook->api_client->users_isAppUser($fbuid) ||
|
|
||||||
$facebook->api_client->added) {
|
|
||||||
|
|
||||||
// user should be connected...
|
|
||||||
|
|
||||||
common_debug("Facebook user found: $fbuid");
|
|
||||||
|
|
||||||
if ($user) {
|
|
||||||
common_debug("Facebook user is logged in.");
|
|
||||||
return;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
common_debug("Facebook user is NOT logged in.");
|
|
||||||
common_redirect(common_local_url('fbconnectlogin'), 303);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
common_debug("No Facebook connect user found.");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
common_debug('Expired FB session.');
|
common_log(LOG_WARNING, 'Could\'t logout of Facebook: ' .
|
||||||
|
$e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
203
plugins/FBConnect/FBConnectSettings.php
Normal file
203
plugins/FBConnect/FBConnectSettings.php
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Facebook Connect settings
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Settings
|
||||||
|
* @package Laconica
|
||||||
|
* @author Zach Copley <zach@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR.'/lib/connectsettingsaction.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Facebook Connect settings action
|
||||||
|
*
|
||||||
|
* @category Settings
|
||||||
|
* @package Laconica
|
||||||
|
* @author Zach Copley <zach@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 FBConnectSettingsAction extends ConnectSettingsAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Title of the page
|
||||||
|
*
|
||||||
|
* @return string Title of the page
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return _('Facebook Connect Settings');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructions for use
|
||||||
|
*
|
||||||
|
* @return instructions for use
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getInstructions()
|
||||||
|
{
|
||||||
|
return _('Manage how your account connects to Facebook');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content area of the page
|
||||||
|
*
|
||||||
|
* Shows a form for uploading an avatar.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$user = common_current_user();
|
||||||
|
$flink = Foreign_link::getByUserID($user->id, FACEBOOK_CONNECT_SERVICE);
|
||||||
|
|
||||||
|
$this->elementStart('form', array('method' => 'post',
|
||||||
|
'id' => 'form_settings_facebook',
|
||||||
|
'class' => 'form_settings',
|
||||||
|
'action' =>
|
||||||
|
common_local_url('FBConnectSettings')));
|
||||||
|
|
||||||
|
if (!$flink) {
|
||||||
|
|
||||||
|
$this->element('p', 'instructions',
|
||||||
|
_('There is no Facebook user connected to this account.'));
|
||||||
|
|
||||||
|
$this->element('fb:login-button', array('onlogin' => 'goto_login()',
|
||||||
|
'length' => 'long'));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$this->element('p', 'form_note',
|
||||||
|
_('Connected Facebook user'));
|
||||||
|
|
||||||
|
$this->elementStart('p', array('class' => 'facebook-user-display'));
|
||||||
|
$this->elementStart('fb:profile-pic',
|
||||||
|
array('uid' => $flink->foreign_id,
|
||||||
|
'size' => 'small',
|
||||||
|
'linked' => 'true',
|
||||||
|
'facebook-logo' => 'true'));
|
||||||
|
$this->elementEnd('fb:profile-pic');
|
||||||
|
|
||||||
|
$this->elementStart('fb:name', array('uid' => $flink->foreign_id,
|
||||||
|
'useyou' => 'false'));
|
||||||
|
$this->elementEnd('fb:name');
|
||||||
|
$this->elementEnd('p');
|
||||||
|
|
||||||
|
$this->hidden('token', common_session_token());
|
||||||
|
|
||||||
|
$this->elementStart('fieldset');
|
||||||
|
|
||||||
|
$this->element('legend', null, _('Disconnect my account from Facebook'));
|
||||||
|
|
||||||
|
if (!$user->password) {
|
||||||
|
|
||||||
|
$this->elementStart('p', array('class' => 'form_guide'));
|
||||||
|
$this->text(_('Disconnecting your Faceboook ' .
|
||||||
|
'would make it impossible to log in! Please '));
|
||||||
|
$this->element('a',
|
||||||
|
array('href' => common_local_url('passwordsettings')),
|
||||||
|
_('set a password'));
|
||||||
|
|
||||||
|
$this->text(_(' first.'));
|
||||||
|
$this->elementEnd('p');
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$note = 'Keep your %s account but disconnect from Facebook. ' .
|
||||||
|
'You\'ll use your %s password to log in.';
|
||||||
|
|
||||||
|
$site = common_config('site', 'name');
|
||||||
|
|
||||||
|
$this->element('p', 'instructions',
|
||||||
|
sprintf($note, $site, $site));
|
||||||
|
|
||||||
|
$this->submit('disconnect', _('Disconnect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd('fieldset');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle post
|
||||||
|
*
|
||||||
|
* Disconnects the current Facebook user from the current user's account
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handlePost()
|
||||||
|
{
|
||||||
|
// 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.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->arg('disconnect')) {
|
||||||
|
|
||||||
|
$user = common_current_user();
|
||||||
|
|
||||||
|
$flink = Foreign_link::getByUserID($user->id, FACEBOOK_CONNECT_SERVICE);
|
||||||
|
$result = $flink->delete();
|
||||||
|
|
||||||
|
if ($result === false) {
|
||||||
|
common_log_db_error($user, 'DELETE', __FILE__);
|
||||||
|
$this->serverError(_('Couldn\'t delete link to Facebook.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Clear FB Connect cookies out
|
||||||
|
$facebook = getFacebook();
|
||||||
|
$facebook->clear_cookie_state();
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
common_log(LOG_WARNING,
|
||||||
|
'Couldn\'t clear Facebook cookies: ' .
|
||||||
|
$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->showForm(_('You have disconnected from Facebook.'), true);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->showForm(_('Not sure what you\'re trying to do.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
BIN
plugins/FBConnect/fbfavicon.ico
Normal file
BIN
plugins/FBConnect/fbfavicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -1,10 +0,0 @@
|
|||||||
<!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" >
|
|
||||||
<head>
|
|
||||||
<title>cross domain receiver page</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js" type="text/javascript"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
109
plugins/WikiHashtagsPlugin.php
Normal file
109
plugins/WikiHashtagsPlugin.php
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Laconica, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Plugin to show WikiHashtags content in the sidebar
|
||||||
|
*
|
||||||
|
* 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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
define('WIKIHASHTAGSPLUGIN_VERSION', '0.1');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin to use WikiHashtags
|
||||||
|
*
|
||||||
|
* @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/
|
||||||
|
*
|
||||||
|
* @see Event
|
||||||
|
*/
|
||||||
|
|
||||||
|
class WikiHashtagsPlugin extends Plugin
|
||||||
|
{
|
||||||
|
function __construct($code=null)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartShowSections($action)
|
||||||
|
{
|
||||||
|
$name = $action->trimmed('action');
|
||||||
|
|
||||||
|
if ($name == 'tag') {
|
||||||
|
|
||||||
|
$taginput = $action->trimmed('tag');
|
||||||
|
$tag = common_canonical_tag($taginput);
|
||||||
|
|
||||||
|
if (!empty($tag)) {
|
||||||
|
|
||||||
|
$url = sprintf('http://hashtags.wikia.com/index.php?title=%s&action=render',
|
||||||
|
urlencode($tag));
|
||||||
|
$editurl = sprintf('http://hashtags.wikia.com/index.php?title=%s&action=edit',
|
||||||
|
urlencode($tag));
|
||||||
|
|
||||||
|
$context = stream_context_create(array('http' => array('method' => "GET",
|
||||||
|
'header' =>
|
||||||
|
"User-Agent: " . $this->userAgent())));
|
||||||
|
$html = @file_get_contents($url, false, $context);
|
||||||
|
|
||||||
|
$action->elementStart('div', array('id' => 'wikihashtags', 'class' => 'section'));
|
||||||
|
|
||||||
|
if (!empty($html)) {
|
||||||
|
$action->element('style', null,
|
||||||
|
"span.editsection { display: none }\n".
|
||||||
|
"table.toc { display: none }");
|
||||||
|
$action->raw($html);
|
||||||
|
$action->elementStart('p');
|
||||||
|
$action->element('a', array('href' => $editurl,
|
||||||
|
'title' => sprintf(_('Edit the article for #%s on WikiHashtags'), $tag)),
|
||||||
|
_('Edit'));
|
||||||
|
$action->element('a', array('href' => 'http://www.gnu.org/copyleft/fdl.html',
|
||||||
|
'title' => _('Shared under the terms of the GNU Free Documentation License'),
|
||||||
|
'rel' => 'license'),
|
||||||
|
'GNU FDL');
|
||||||
|
$action->elementEnd('p');
|
||||||
|
} else {
|
||||||
|
$action->element('a', array('href' => $editurl),
|
||||||
|
sprintf(_('Start the article for #%s on WikiHashtags'), $tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
$action->elementEnd('div');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function userAgent()
|
||||||
|
{
|
||||||
|
return 'WikiHashtagsPlugin/'.WIKIHASHTAGSPLUGIN_VERSION .
|
||||||
|
' Laconica/' . LACONICA_VERSION;
|
||||||
|
}
|
||||||
|
}
|
141
scripts/fixup_utf8.php
Normal file
141
scripts/fixup_utf8.php
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* 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
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# Abort if called from a web server
|
||||||
|
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
|
print "This script must be run from the command line\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_set("max_execution_time", "0");
|
||||||
|
ini_set("max_input_time", "0");
|
||||||
|
set_time_limit(0);
|
||||||
|
mb_internal_encoding('UTF-8');
|
||||||
|
|
||||||
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||||
|
define('LACONICA', true);
|
||||||
|
|
||||||
|
require_once(INSTALLDIR . '/lib/common.php');
|
||||||
|
require_once('DB.php');
|
||||||
|
|
||||||
|
function fixup_utf8($id) {
|
||||||
|
|
||||||
|
$dbl = doConnect('latin1');
|
||||||
|
|
||||||
|
if (empty($dbl)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dbu = doConnect('utf8');
|
||||||
|
|
||||||
|
if (empty($dbu)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a separate DB connection
|
||||||
|
|
||||||
|
$sth = $dbu->prepare("UPDATE notice SET content = UNHEX(?), rendered = UNHEX(?) WHERE id = ?");
|
||||||
|
|
||||||
|
if (PEAR::isError($sth)) {
|
||||||
|
echo "ERROR: " . $sth->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'SELECT id, content, rendered FROM notice ' .
|
||||||
|
'WHERE LENGTH(content) != CHAR_LENGTH(content)';
|
||||||
|
|
||||||
|
if (!empty($id)) {
|
||||||
|
$sql .= ' AND id < ' . $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= ' ORDER BY id DESC';
|
||||||
|
|
||||||
|
$rn = $dbl->query($sql);
|
||||||
|
|
||||||
|
if (PEAR::isError($rn)) {
|
||||||
|
echo "ERROR: " . $rn->getMessage() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Number of rows: " . $rn->numRows() . "\n";
|
||||||
|
|
||||||
|
$notice = array();
|
||||||
|
|
||||||
|
while (DB_OK == $rn->fetchInto($notice)) {
|
||||||
|
|
||||||
|
$id = ($notice[0])+0;
|
||||||
|
$content = bin2hex($notice[1]);
|
||||||
|
$rendered = bin2hex($notice[2]);
|
||||||
|
|
||||||
|
echo "$id...";
|
||||||
|
|
||||||
|
$result =& $dbu->execute($sth, array($content, $rendered, $id));
|
||||||
|
|
||||||
|
if (PEAR::isError($result)) {
|
||||||
|
echo "ERROR: " . $result->getMessage() . "\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cnt = $dbu->affectedRows();
|
||||||
|
|
||||||
|
if ($cnt != 1) {
|
||||||
|
echo "ERROR: 0 rows affected\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice = Notice::staticGet('id', $id);
|
||||||
|
$notice->decache();
|
||||||
|
|
||||||
|
echo "OK\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doConnect($charset)
|
||||||
|
{
|
||||||
|
$db = DB::connect(common_config('db', 'database'),
|
||||||
|
array('persistent' => false));
|
||||||
|
|
||||||
|
if (PEAR::isError($db)) {
|
||||||
|
echo "ERROR: " . $db->getMessage() . "\n";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $db->query("SET NAMES $charset");
|
||||||
|
|
||||||
|
if (PEAR::isError($result)) {
|
||||||
|
echo "ERROR: " . $result->getMessage() . "\n";
|
||||||
|
$db->disconnect();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $db->autoCommit(true);
|
||||||
|
|
||||||
|
if (PEAR::isError($result)) {
|
||||||
|
echo "ERROR: " . $result->getMessage() . "\n";
|
||||||
|
$db->disconnect();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = ($argc > 1) ? $argv[1] : null;
|
||||||
|
|
||||||
|
fixup_utf8($id);
|
37
scripts/reportsnapshot.php
Normal file
37
scripts/reportsnapshot.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Laconica - a distributed open-source microblogging tool
|
||||||
|
* 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
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# Abort if called from a web server
|
||||||
|
if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
|
print "This script must be run from the command line\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ini_set("max_execution_time", "0");
|
||||||
|
ini_set("max_input_time", "0");
|
||||||
|
set_time_limit(0);
|
||||||
|
mb_internal_encoding('UTF-8');
|
||||||
|
|
||||||
|
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||||
|
define('LACONICA', true);
|
||||||
|
|
||||||
|
require_once(INSTALLDIR . '/lib/common.php');
|
||||||
|
|
||||||
|
Snapshot::check();
|
@ -214,7 +214,8 @@ class TwitterStatusFetcher extends Daemon
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($timeline as $status) {
|
// Reverse to preserve order
|
||||||
|
foreach (array_reverse($timeline) as $status) {
|
||||||
|
|
||||||
// Hacktastic: filter out stuff coming from this Laconica
|
// Hacktastic: filter out stuff coming from this Laconica
|
||||||
$source = mb_strtolower(common_config('integration', 'source'));
|
$source = mb_strtolower(common_config('integration', 'source'));
|
||||||
|
@ -198,9 +198,11 @@ padding:0 7px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form_settings input.form_action-primary {
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-secondary {
|
||||||
margin-left:29px;
|
margin-left:29px;
|
||||||
padding:0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#form_search .submit {
|
#form_search .submit {
|
||||||
@ -450,6 +452,21 @@ float:left;
|
|||||||
font-size:1.3em;
|
font-size:1.3em;
|
||||||
margin-bottom:7px;
|
margin-bottom:7px;
|
||||||
}
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
text-indent:-9999px;
|
||||||
|
}
|
||||||
|
#form_notice label[for=notice_data-attach],
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
position:absolute;
|
||||||
|
top:25px;
|
||||||
|
right:49px;
|
||||||
|
width:16px;
|
||||||
|
height:16px;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
text-indent:-279px;
|
||||||
|
}
|
||||||
#form_notice #notice_submit label {
|
#form_notice #notice_submit label {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
@ -740,12 +757,14 @@ border-top-style:dotted;
|
|||||||
.notices li {
|
.notices li {
|
||||||
list-style-type:none;
|
list-style-type:none;
|
||||||
}
|
}
|
||||||
.notices li.hover {
|
.notices .notices {
|
||||||
border-radius:4px;
|
margin-top:7px;
|
||||||
-moz-border-radius:4px;
|
margin-left:5%;
|
||||||
-webkit-border-radius:4px;
|
width:95%;
|
||||||
|
float:left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* NOTICES */
|
/* NOTICES */
|
||||||
#notices_primary {
|
#notices_primary {
|
||||||
float:left;
|
float:left;
|
||||||
@ -794,6 +813,9 @@ float:left;
|
|||||||
width:100%;
|
width:100%;
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
}
|
}
|
||||||
|
.notice .entry-title.ov {
|
||||||
|
overflow:visible;
|
||||||
|
}
|
||||||
#shownotice .notice .entry-title {
|
#shownotice .notice .entry-title {
|
||||||
font-size:2.2em;
|
font-size:2.2em;
|
||||||
}
|
}
|
||||||
@ -818,7 +840,7 @@ clear:left;
|
|||||||
float:left;
|
float:left;
|
||||||
font-size:0.95em;
|
font-size:0.95em;
|
||||||
margin-left:59px;
|
margin-left:59px;
|
||||||
width:65%;
|
width:60%;
|
||||||
}
|
}
|
||||||
#showstream .notice div.entry-content,
|
#showstream .notice div.entry-content,
|
||||||
#shownotice .notice div.entry-content {
|
#shownotice .notice div.entry-content {
|
||||||
@ -848,15 +870,12 @@ display:inline-block;
|
|||||||
text-transform:lowercase;
|
text-transform:lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.notice-options {
|
.notice-options {
|
||||||
padding-left:2%;
|
|
||||||
float:left;
|
|
||||||
width:50%;
|
|
||||||
position:relative;
|
position:relative;
|
||||||
font-size:0.95em;
|
font-size:0.95em;
|
||||||
width:12.5%;
|
width:90px;
|
||||||
float:right;
|
float:right;
|
||||||
|
margin-right:11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice-options a {
|
.notice-options a {
|
||||||
@ -918,6 +937,75 @@ padding:0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.notice .attachment {
|
||||||
|
position:relative;
|
||||||
|
padding-left:16px;
|
||||||
|
}
|
||||||
|
#attachments .attachment {
|
||||||
|
padding-left:0;
|
||||||
|
}
|
||||||
|
.notice .attachment img {
|
||||||
|
position:absolute;
|
||||||
|
top:18px;
|
||||||
|
left:0;
|
||||||
|
z-index:99;
|
||||||
|
}
|
||||||
|
#shownotice .notice .attachment img {
|
||||||
|
position:static;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachments {
|
||||||
|
clear:both;
|
||||||
|
float:left;
|
||||||
|
width:100%;
|
||||||
|
margin-top:18px;
|
||||||
|
}
|
||||||
|
#attachments dt {
|
||||||
|
font-weight:bold;
|
||||||
|
font-size:1.3em;
|
||||||
|
margin-bottom:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachments ol li {
|
||||||
|
margin-bottom:18px;
|
||||||
|
list-style-type:decimal;
|
||||||
|
float:left;
|
||||||
|
clear:both;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jOverlayContent,
|
||||||
|
#jOverlayContent #content,
|
||||||
|
#jOverlayContent #content_inner {
|
||||||
|
width: auto !important;
|
||||||
|
margin-bottom:0;
|
||||||
|
}
|
||||||
|
#jOverlayContent #content {
|
||||||
|
padding:11px;
|
||||||
|
min-height:auto;
|
||||||
|
}
|
||||||
|
#jOverlayContent .external span {
|
||||||
|
display:block;
|
||||||
|
margin-bottom:11px;
|
||||||
|
}
|
||||||
|
#jOverlayContent button {
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
right:0;
|
||||||
|
width:29px;
|
||||||
|
height:29px;
|
||||||
|
text-align:center;
|
||||||
|
font-weight:bold;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
#jOverlayContent h1 {
|
||||||
|
max-width:475px;
|
||||||
|
}
|
||||||
|
#jOverlayContent #content {
|
||||||
|
border-radius:7px;
|
||||||
|
-moz-border-radius:7px;
|
||||||
|
-webkit-border-radius:7px;
|
||||||
|
}
|
||||||
|
|
||||||
#usergroups #new_group {
|
#usergroups #new_group {
|
||||||
float: left;
|
float: left;
|
||||||
margin-right: 2em;
|
margin-right: 2em;
|
||||||
@ -1040,8 +1128,6 @@ margin-left:18px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* TOP_POSTERS */
|
/* TOP_POSTERS */
|
||||||
.section tbody td {
|
.section tbody td {
|
||||||
padding-right:18px;
|
padding-right:18px;
|
||||||
@ -1166,6 +1252,7 @@ width:33%;
|
|||||||
}
|
}
|
||||||
#settings_design_color .form_data label {
|
#settings_design_color .form_data label {
|
||||||
float:none;
|
float:none;
|
||||||
|
display:block;
|
||||||
}
|
}
|
||||||
#settings_design_color .form_data .swatch {
|
#settings_design_color .form_data .swatch {
|
||||||
padding:11px;
|
padding:11px;
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
@import url("display.css");
|
|
||||||
@import url("../../identica/css/display.css");
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
font-size:14px;
|
font-size:14px;
|
||||||
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||||
|
@ -30,3 +30,12 @@ margin-right:4px;
|
|||||||
.entity_profile {
|
.entity_profile {
|
||||||
width:64%;
|
width:64%;
|
||||||
}
|
}
|
||||||
|
.notice {
|
||||||
|
z-index:1;
|
||||||
|
}
|
||||||
|
.notice:hover {
|
||||||
|
z-index:9999;
|
||||||
|
}
|
||||||
|
.notice .thumbnail img {
|
||||||
|
z-index:9999;
|
||||||
|
}
|
BIN
theme/base/images/icons/clip-inline.png
Normal file
BIN
theme/base/images/icons/clip-inline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
theme/base/images/icons/twotone/green/clip-01.gif
Normal file
BIN
theme/base/images/icons/twotone/green/clip-01.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 B |
BIN
theme/base/images/icons/twotone/green/clip-02.gif
Normal file
BIN
theme/base/images/icons/twotone/green/clip-02.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 B |
@ -198,10 +198,13 @@ padding:0 7px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
margin-left:29px;
|
|
||||||
padding:0;
|
padding:0;
|
||||||
}
|
}
|
||||||
|
.form_settings input.form_action-secondary {
|
||||||
|
margin-left:29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#form_search .submit {
|
#form_search .submit {
|
||||||
margin-left:11px;
|
margin-left:11px;
|
||||||
@ -443,6 +446,27 @@ float:left;
|
|||||||
font-size:1.3em;
|
font-size:1.3em;
|
||||||
margin-bottom:7px;
|
margin-bottom:7px;
|
||||||
}
|
}
|
||||||
|
#form_notice label {
|
||||||
|
display:block;
|
||||||
|
float:left;
|
||||||
|
font-size:1.3em;
|
||||||
|
margin-bottom:7px;
|
||||||
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
text-indent:-9999px;
|
||||||
|
}
|
||||||
|
#form_notice label[for=notice_data-attach],
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
position:absolute;
|
||||||
|
top:25px;
|
||||||
|
right:49px;
|
||||||
|
width:16px;
|
||||||
|
height:16px;
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
text-indent:-279px;
|
||||||
|
}
|
||||||
#form_notice #notice_submit label {
|
#form_notice #notice_submit label {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ border-color:#aaa;
|
|||||||
border-color:#ddd;
|
border-color:#ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
background:none;
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ div.notice-options input,
|
|||||||
.entity_send-a-message a,
|
.entity_send-a-message a,
|
||||||
.form_user_nudge input.submit,
|
.form_user_nudge input.submit,
|
||||||
.entity_nudge p,
|
.entity_nudge p,
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
color:#002E6E;
|
color:#002E6E;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +102,13 @@ color:#333;
|
|||||||
#form_notice.warning #notice_text-count {
|
#form_notice.warning #notice_text-count {
|
||||||
color:#000;
|
color:#000;
|
||||||
}
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
|
||||||
#form_notice.processing #notice_action-submit {
|
#form_notice.processing #notice_action-submit {
|
||||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||||
cursor:wait;
|
cursor:wait;
|
||||||
|
@ -199,9 +199,11 @@ padding:0 7px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form_settings input.form_action-primary {
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-secondary {
|
||||||
margin-left:29px;
|
margin-left:29px;
|
||||||
padding:0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#form_search .submit {
|
#form_search .submit {
|
||||||
@ -1267,7 +1269,7 @@ border-color:#aaa;
|
|||||||
border-color:#ddd;
|
border-color:#ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
background:none;
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1296,7 +1298,7 @@ div.notice-options input,
|
|||||||
.entity_send-a-message a,
|
.entity_send-a-message a,
|
||||||
.form_user_nudge input.submit,
|
.form_user_nudge input.submit,
|
||||||
.entity_nudge p,
|
.entity_nudge p,
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
color:#0084B4;
|
color:#0084B4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ border-color:#aaa;
|
|||||||
border-color:#C3D6DF;
|
border-color:#C3D6DF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
background:none;
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ div.notice-options input,
|
|||||||
.entity_send-a-message a,
|
.entity_send-a-message a,
|
||||||
.form_user_nudge input.submit,
|
.form_user_nudge input.submit,
|
||||||
.entity_nudge p,
|
.entity_nudge p,
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
color:#002E6E;
|
color:#002E6E;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +82,13 @@ color:#333;
|
|||||||
#form_notice.warning #notice_text-count {
|
#form_notice.warning #notice_text-count {
|
||||||
color:#000;
|
color:#000;
|
||||||
}
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
|
||||||
#form_notice.processing #notice_action-submit {
|
#form_notice.processing #notice_action-submit {
|
||||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||||
cursor:wait;
|
cursor:wait;
|
||||||
@ -175,10 +182,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* NOTICES */
|
/* NOTICES */
|
||||||
.notices li.over {
|
.notice .attachment {
|
||||||
background-color:#fcfcfc;
|
background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#attachments .attachment {
|
||||||
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice-options .notice_reply a,
|
.notice-options .notice_reply a,
|
||||||
.notice-options form input.submit {
|
.notice-options form input.submit {
|
||||||
background-color:transparent;
|
background-color:transparent;
|
||||||
@ -197,7 +206,9 @@ background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-r
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notices div.entry-content,
|
.notices div.entry-content,
|
||||||
.notices div.notice-options {
|
.notices div.notice-options,
|
||||||
|
.notices li.hover .notices div.entry-content,
|
||||||
|
.notices li.hover .notices div.notice-options {
|
||||||
opacity:0.4;
|
opacity:0.4;
|
||||||
}
|
}
|
||||||
.notices li.hover div.entry-content,
|
.notices li.hover div.entry-content,
|
||||||
@ -214,6 +225,19 @@ font-family:sans-serif;
|
|||||||
.notices li.hover {
|
.notices li.hover {
|
||||||
background-color:#fcfcfc;
|
background-color:#fcfcfc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notices .notices {
|
||||||
|
background-color:rgba(200, 200, 200, 0.050);
|
||||||
|
}
|
||||||
|
.notices .notices .notices {
|
||||||
|
background-color:rgba(200, 200, 200, 0.100);
|
||||||
|
}
|
||||||
|
.notices .notices .notices .notices {
|
||||||
|
background-color:rgba(200, 200, 200, 0.150);
|
||||||
|
}
|
||||||
|
.notices .notices .notices .notices .notices {
|
||||||
|
background-color:rgba(200, 200, 200, 0.300);
|
||||||
|
}
|
||||||
/*END: NOTICES */
|
/*END: NOTICES */
|
||||||
|
|
||||||
#new_group a {
|
#new_group a {
|
||||||
|
@ -189,9 +189,11 @@ padding:0 7px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form_settings input.form_action-primary {
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-secondary {
|
||||||
margin-left:29px;
|
margin-left:29px;
|
||||||
padding:0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#form_search .submit {
|
#form_search .submit {
|
||||||
|
@ -38,7 +38,7 @@ color:#ccc;
|
|||||||
border-color:#ddd;
|
border-color:#ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
background:none;
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ div.notice-options input,
|
|||||||
.entity_send-a-message a,
|
.entity_send-a-message a,
|
||||||
.form_user_nudge input.submit,
|
.form_user_nudge input.submit,
|
||||||
.entity_nudge p,
|
.entity_nudge p,
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
color:#0f0;
|
color:#0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ border-color:#aaa;
|
|||||||
border-color:#ddd;
|
border-color:#ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
background:none;
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ div.notice-options input,
|
|||||||
.entity_send-a-message a,
|
.entity_send-a-message a,
|
||||||
.form_user_nudge input.submit,
|
.form_user_nudge input.submit,
|
||||||
.entity_nudge p,
|
.entity_nudge p,
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
color:#002E6E;
|
color:#002E6E;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +82,13 @@ color:#333;
|
|||||||
#form_notice.warning #notice_text-count {
|
#form_notice.warning #notice_text-count {
|
||||||
color:#000;
|
color:#000;
|
||||||
}
|
}
|
||||||
|
#form_notice label[for=notice_data-attach] {
|
||||||
|
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#form_notice #notice_data-attach {
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
|
||||||
#form_notice.processing #notice_action-submit {
|
#form_notice.processing #notice_action-submit {
|
||||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||||
cursor:wait;
|
cursor:wait;
|
||||||
@ -175,10 +182,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* NOTICES */
|
/* NOTICES */
|
||||||
.notices li.over {
|
.notice .attachment {
|
||||||
background-color:#fcfcfc;
|
background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%;
|
||||||
|
}
|
||||||
|
#attachments .attachment {
|
||||||
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice-options .notice_reply a,
|
.notice-options .notice_reply a,
|
||||||
.notice-options form input.submit {
|
.notice-options form input.submit {
|
||||||
background-color:transparent;
|
background-color:transparent;
|
||||||
@ -197,7 +206,9 @@ background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-r
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notices div.entry-content,
|
.notices div.entry-content,
|
||||||
.notices div.notice-options {
|
.notices div.notice-options,
|
||||||
|
.notices li.hover .notices div.entry-content,
|
||||||
|
.notices li.hover .notices div.notice-options {
|
||||||
opacity:0.4;
|
opacity:0.4;
|
||||||
}
|
}
|
||||||
.notices li.hover div.entry-content,
|
.notices li.hover div.entry-content,
|
||||||
@ -214,6 +225,19 @@ font-family:sans-serif;
|
|||||||
.notices li.hover {
|
.notices li.hover {
|
||||||
background-color:#fcfcfc;
|
background-color:#fcfcfc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notices .notices {
|
||||||
|
background-color:rgba(200, 200, 200, 0.050);
|
||||||
|
}
|
||||||
|
.notices .notices .notices {
|
||||||
|
background-color:rgba(200, 200, 200, 0.100);
|
||||||
|
}
|
||||||
|
.notices .notices .notices .notices {
|
||||||
|
background-color:rgba(200, 200, 200, 0.150);
|
||||||
|
}
|
||||||
|
.notices .notices .notices .notices .notices {
|
||||||
|
background-color:rgba(200, 200, 200, 0.300);
|
||||||
|
}
|
||||||
/*END: NOTICES */
|
/*END: NOTICES */
|
||||||
|
|
||||||
#new_group a {
|
#new_group a {
|
||||||
|
@ -198,9 +198,11 @@ padding:0 7px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form_settings input.form_action-primary {
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-secondary {
|
||||||
margin-left:29px;
|
margin-left:29px;
|
||||||
padding:0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#form_search .submit {
|
#form_search .submit {
|
||||||
|
@ -37,7 +37,7 @@ border-color:#aaa;
|
|||||||
border-color:#ddd;
|
border-color:#ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
background:none;
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ div.notice-options input,
|
|||||||
.entity_send-a-message a,
|
.entity_send-a-message a,
|
||||||
.form_user_nudge input.submit,
|
.form_user_nudge input.submit,
|
||||||
.entity_nudge p,
|
.entity_nudge p,
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
color:#8F0000;
|
color:#8F0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,9 +199,11 @@ padding:0 7px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form_settings input.form_action-primary {
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-secondary {
|
||||||
margin-left:29px;
|
margin-left:29px;
|
||||||
padding:0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#form_search .submit {
|
#form_search .submit {
|
||||||
|
@ -36,7 +36,7 @@ border-color:#aaa;
|
|||||||
border-color:#ddd;
|
border-color:#ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
background:none;
|
background:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ div.notice-options input,
|
|||||||
.entity_send-a-message a,
|
.entity_send-a-message a,
|
||||||
.form_user_nudge input.submit,
|
.form_user_nudge input.submit,
|
||||||
.entity_nudge p,
|
.entity_nudge p,
|
||||||
.form_settings input.form_action-secondary {
|
.form_settings input.form_action-primary {
|
||||||
color:#000;
|
color:#000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user