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/*
|
||||
files/*
|
||||
file/*
|
||||
_darcs/*
|
||||
logs/*
|
||||
config.php
|
||||
@ -16,3 +17,8 @@ dataobject.ini
|
||||
.buildpath
|
||||
.project
|
||||
.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
|
||||
=========
|
||||
|
||||
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
|
||||
tracking the "git" version of the software, you will probably want
|
||||
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
|
||||
'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
|
||||
=====================
|
||||
|
||||
@ -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
|
||||
requests to go to the 'database' (master) server, you'll need
|
||||
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
|
||||
------
|
||||
@ -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
|
||||
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
|
||||
===============
|
||||
|
||||
|
@ -67,6 +67,7 @@ class ApiAction extends Action
|
||||
$this->process_command();
|
||||
} else {
|
||||
# basic authentication failed
|
||||
common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname.");
|
||||
$this->show_basic_auth_error();
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,6 @@ if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||
//require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
||||
|
||||
/**
|
||||
@ -67,11 +65,11 @@ class AttachmentAction extends Action
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->arg('attachment');
|
||||
if ($id = $this->trimmed('attachment')) {
|
||||
$this->attachment = File::staticGet($id);
|
||||
}
|
||||
|
||||
$this->attachment = File::staticGet($id);
|
||||
|
||||
if (!$this->attachment) {
|
||||
if (empty($this->attachment)) {
|
||||
$this->clientError(_('No such attachment.'), 404);
|
||||
return false;
|
||||
}
|
||||
@ -178,10 +176,8 @@ class AttachmentAction extends Action
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('ul', array('class' => 'attachments'));
|
||||
$ali = new Attachment($this->attachment, $this);
|
||||
$cnt = $ali->show();
|
||||
$this->elementEnd('ul');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,26 +45,6 @@ require_once INSTALLDIR.'/actions/attachment.php';
|
||||
|
||||
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.
|
||||
*
|
||||
@ -95,8 +75,6 @@ class Attachment_ajaxAction extends AttachmentAction
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Last-modified date for page
|
||||
*
|
||||
|
@ -31,9 +31,7 @@ if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||
//require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
require_once INSTALLDIR.'/actions/attachments.php';
|
||||
require_once INSTALLDIR.'/actions/attachment.php';
|
||||
|
||||
/**
|
||||
* Show notice attachments
|
||||
@ -45,39 +43,8 @@ require_once INSTALLDIR.'/actions/attachments.php';
|
||||
* @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.
|
||||
*
|
||||
@ -100,16 +67,52 @@ class Attachments_ajaxAction extends AttachmentsAction
|
||||
*/
|
||||
function showCore()
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'core'));
|
||||
if (Event::handle('StartShowContentBlock', array($this))) {
|
||||
$this->showContentBlock();
|
||||
Event::handle('EndShowContentBlock', array($this));
|
||||
$file_thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
|
||||
if (empty($file_thumbnail->url)) {
|
||||
return;
|
||||
}
|
||||
$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/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, Controlez-Vous, Inc.
|
||||
* Copyright (C) 2009, Control Yourself, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
@ -31,7 +31,7 @@ if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once(INSTALLDIR.'/lib/noticelist.php');
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
|
||||
/**
|
||||
* Conversation tree in the browser
|
||||
@ -42,9 +42,10 @@ require_once(INSTALLDIR.'/lib/noticelist.php');
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class ConversationAction extends Action
|
||||
{
|
||||
var $id = null;
|
||||
var $id = null;
|
||||
var $page = null;
|
||||
|
||||
/**
|
||||
@ -69,24 +70,47 @@ class ConversationAction extends Action
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the action
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page title
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _("Conversation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Show content.
|
||||
*
|
||||
* Display a hierarchical unordered list in the content area.
|
||||
* Uses ConversationTree to do most of the heavy lifting.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
// FIXME this needs to be a tree, not a list
|
||||
|
||||
$qry = 'SELECT * FROM notice WHERE conversation = %s ';
|
||||
|
||||
$offset = ($this->page-1)*NOTICES_PER_PAGE;
|
||||
$offset = ($this->page-1) * NOTICES_PER_PAGE;
|
||||
$limit = NOTICES_PER_PAGE + 1;
|
||||
|
||||
$txt = sprintf($qry, $this->id);
|
||||
@ -95,9 +119,9 @@ class ConversationAction extends Action
|
||||
'notice:conversation:'.$this->id,
|
||||
$offset, $limit);
|
||||
|
||||
$nl = new NoticeList($notices, $this);
|
||||
$ct = new ConversationTree($notices, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
$cnt = $ct->show();
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'conversation', array('id' => $this->id));
|
||||
@ -105,3 +129,170 @@ class ConversationAction extends Action
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversation tree
|
||||
*
|
||||
* The widget class for displaying a hierarchical list of notices.
|
||||
*
|
||||
* @category Widget
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class ConversationTree extends NoticeList
|
||||
{
|
||||
var $tree = null;
|
||||
var $table = null;
|
||||
|
||||
/**
|
||||
* Show the tree of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function show()
|
||||
{
|
||||
$cnt = 0;
|
||||
|
||||
$this->tree = array();
|
||||
$this->table = array();
|
||||
|
||||
while ($this->notice->fetch()) {
|
||||
|
||||
$cnt++;
|
||||
|
||||
$id = $this->notice->id;
|
||||
$notice = clone($this->notice);
|
||||
|
||||
$this->table[$id] = $notice;
|
||||
|
||||
if (is_null($notice->reply_to)) {
|
||||
$this->tree['root'] = array($notice->id);
|
||||
} else if (array_key_exists($notice->reply_to, $this->tree)) {
|
||||
$this->tree[$notice->reply_to][] = $notice->id;
|
||||
} else {
|
||||
$this->tree[$notice->reply_to] = array($notice->id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||
$this->out->element('h2', null, _('Notices'));
|
||||
$this->out->elementStart('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('notice', $this->trimmed('notice'));
|
||||
$this->element('p', null, _('Are you sure you want to delete this notice?'));
|
||||
$this->submit('form_action-yes', _('Yes'), 'submit form_action-primary', 'yes');
|
||||
$this->submit('form_action-no', _('No'), 'submit form_action-secondary', 'no');
|
||||
$this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not delete this notice"));
|
||||
$this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Delete this notice'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$this->elementStart('form', array('method' => 'POST',
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_design',
|
||||
'class' => 'form_settings',
|
||||
'action' =>
|
||||
@ -82,7 +82,7 @@ class DesignsettingsAction extends AccountSettingsAction
|
||||
$this->element('legend', null, _('Change background image'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->element('label', array('for' => 'design_ background-image_file'),
|
||||
$this->element('label', array('for' => 'design_background-image_file'),
|
||||
_('Upload file'));
|
||||
$this->element('input', array('name' => 'design_background-image_file',
|
||||
'type' => 'file',
|
||||
@ -140,10 +140,12 @@ class DesignsettingsAction extends AccountSettingsAction
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->submit('save', _('Save'));
|
||||
$this->element('input', array('type' => 'reset',
|
||||
$this->element('input', array('id' => 'settings_design_reset',
|
||||
'type' => '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:
|
||||
json_encode(form values)
|
||||
|
@ -115,7 +115,7 @@ class FacebookhomeAction extends FacebookAction
|
||||
$flink->foreign_id = $this->fbuid;
|
||||
$flink->service = FACEBOOK_SERVICE;
|
||||
$flink->created = common_sql_now();
|
||||
$flink->set_flags(true, false, false);
|
||||
$flink->set_flags(true, false, false, false);
|
||||
|
||||
$flink_id = $flink->insert();
|
||||
|
||||
@ -138,9 +138,6 @@ class FacebookhomeAction extends FacebookAction
|
||||
|
||||
function setDefaults()
|
||||
{
|
||||
// A default prefix string for notices
|
||||
$this->facebook->api_client->data_setUserPreference(
|
||||
FACEBOOK_NOTICE_PREFIX, 'dented: ');
|
||||
$this->facebook->api_client->data_setUserPreference(
|
||||
FACEBOOK_PROMPTED_UPDATE_PREF, 'false');
|
||||
}
|
||||
|
@ -17,7 +17,9 @@
|
||||
* 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');
|
||||
|
||||
@ -67,7 +69,7 @@ class FacebookinviteAction extends FacebookAction
|
||||
function showSuccessContent()
|
||||
{
|
||||
|
||||
$this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'),
|
||||
$this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'),
|
||||
common_config('site', 'name')));
|
||||
$this->element('p', null, _('Invitations have been sent to the following users:'));
|
||||
|
||||
@ -89,16 +91,6 @@ class FacebookinviteAction extends FacebookAction
|
||||
|
||||
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')) .
|
||||
htmlentities('<fb:req-choice url="' . $this->app_uri . '" label="Add"/>');
|
||||
|
||||
@ -109,36 +101,43 @@ class FacebookinviteAction extends FacebookAction
|
||||
'content' => $content));
|
||||
$this->hidden('invite', 'true');
|
||||
$actiontext = sprintf(_('Invite your friends to use %s'), common_config('site', 'name'));
|
||||
|
||||
$multi_params = array('showborder' => 'false');
|
||||
|
||||
$multi_params = array('showborder' => 'false');
|
||||
$multi_params['actiontext'] = $actiontext;
|
||||
|
||||
if ($exclude_ids_csv) {
|
||||
$multi_params['bypass'] = 'cancel';
|
||||
|
||||
// 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['bypass'] = 'cancel';
|
||||
|
||||
$this->element('fb:multi-friend-selector', $multi_params);
|
||||
|
||||
$this->elementEnd('fb:request-form');
|
||||
|
||||
$this->element('h2', null, sprintf(_('Friends already using %s:'),
|
||||
common_config('site', 'name')));
|
||||
$this->elementStart('ul', array('id' => 'facebook-friends'));
|
||||
|
||||
foreach ($exclude_ids as $friend) {
|
||||
$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');
|
||||
}
|
||||
if ($exclude_ids) {
|
||||
|
||||
$this->elementEnd("ul");
|
||||
$this->element('h2', null, sprintf(_('Friends already using %s:'),
|
||||
common_config('site', 'name')));
|
||||
$this->elementStart('ul', array('id' => 'facebook-friends'));
|
||||
|
||||
foreach ($exclude_ids as $friend) {
|
||||
$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");
|
||||
}
|
||||
}
|
||||
|
||||
function title()
|
||||
|
||||
function title()
|
||||
{
|
||||
return sprintf(_('Send invitations'));
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class FacebooksettingsAction extends FacebookAction
|
||||
$prefix = $this->trimmed('prefix');
|
||||
|
||||
$original = clone($this->flink);
|
||||
$this->flink->set_flags($noticesync, $replysync, false);
|
||||
$this->flink->set_flags($noticesync, $replysync, false, false);
|
||||
$result = $this->flink->update($original);
|
||||
|
||||
$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)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('Not logged in.'));
|
||||
} 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
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->saveNewNotice();
|
||||
} 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
|
||||
*
|
||||
@ -131,7 +159,6 @@ class NewnoticeAction extends Action
|
||||
$this->clientError(_('No content!'));
|
||||
} else {
|
||||
$content_shortened = common_shorten_links($content);
|
||||
|
||||
if (mb_strlen($content_shortened) > 140) {
|
||||
$this->clientError(_('That\'s too long. '.
|
||||
'Max notice size is 140 chars.'));
|
||||
@ -158,17 +185,53 @@ class NewnoticeAction extends Action
|
||||
$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,
|
||||
($replyto == 'false') ? null : $replyto);
|
||||
|
||||
if (is_string($notice)) {
|
||||
$this->clientError($notice);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($mimetype)) {
|
||||
$this->storeFile($notice, $mimetype);
|
||||
}
|
||||
$this->saveUrls($notice);
|
||||
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
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
|
||||
*
|
||||
* follow redirects and save all available file information
|
||||
@ -203,7 +293,7 @@ class NewnoticeAction extends Action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function saveUrls($notice) {
|
||||
function saveUrls($notice, $uploaded = null) {
|
||||
common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id);
|
||||
}
|
||||
|
||||
@ -316,3 +406,4 @@ class NewnoticeAction extends Action
|
||||
$nli->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,10 +208,10 @@ class ShownoticeAction extends Action
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('ul', array('class' => 'notices'));
|
||||
$this->elementStart('ol', array('class' => 'notices xoxo'));
|
||||
$nli = new NoticeListItem($this->notice, $this);
|
||||
$nli->show();
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('ol');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,8 +49,6 @@ class TagAction extends Action
|
||||
{
|
||||
$pop = new PopularNoticeSection($this);
|
||||
$pop->show();
|
||||
$freqatt = new FrequentAttachmentSection($this);
|
||||
$freqatt->show();
|
||||
}
|
||||
|
||||
function title()
|
||||
|
@ -120,4 +120,30 @@ class File extends Memcached_DataObject
|
||||
File_to_post::processNew($file_id, $notice_id);
|
||||
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->orderBy('len');
|
||||
$file->find(true);
|
||||
if (!empty($file->id)) {
|
||||
if (!empty($file->url) && (strlen($file->url) < strlen($long_url))) {
|
||||
return $file->url;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ class Foreign_link extends Memcached_DataObject
|
||||
|
||||
public $__table = 'foreign_link'; // table name
|
||||
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 $credentials; // varchar(255)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
$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);
|
||||
|
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
|
||||
user_id = K
|
||||
|
||||
[file]
|
||||
id = 129
|
||||
url = 2
|
||||
mimetype = 2
|
||||
size = 1
|
||||
title = 2
|
||||
date = 1
|
||||
protected = 1
|
||||
|
||||
[file__keys]
|
||||
id = N
|
||||
|
||||
[file_oembed]
|
||||
id = 129
|
||||
file_id = 1
|
||||
version = 2
|
||||
type = 2
|
||||
provider = 2
|
||||
provider_url = 2
|
||||
width = 1
|
||||
height = 1
|
||||
html = 34
|
||||
title = 2
|
||||
author_name = 2
|
||||
author_url = 2
|
||||
url = 2
|
||||
|
||||
[file_oembed__keys]
|
||||
id = N
|
||||
|
||||
[file_redirection]
|
||||
id = 129
|
||||
url = 2
|
||||
file_id = 1
|
||||
redirections = 1
|
||||
httpcode = 1
|
||||
|
||||
[file_redirection__keys]
|
||||
id = N
|
||||
|
||||
[file_thumbnail]
|
||||
id = 129
|
||||
file_id = 1
|
||||
url = 2
|
||||
width = 1
|
||||
height = 1
|
||||
|
||||
[file_thumbnail__keys]
|
||||
id = N
|
||||
|
||||
[file_to_post]
|
||||
id = 129
|
||||
file_id = 1
|
||||
post_id = 1
|
||||
|
||||
[file_to_post__keys]
|
||||
id = N
|
||||
|
||||
[foreign_link]
|
||||
user_id = 129
|
||||
foreign_id = 129
|
||||
@ -392,63 +450,3 @@ modified = 384
|
||||
[user_openid__keys]
|
||||
canonical = K
|
||||
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 you have downloaded libraries in random little places, you
|
||||
#can add the paths here
|
||||
// If you have downloaded libraries in random little places, you
|
||||
// can add the paths here
|
||||
|
||||
#$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());
|
||||
// $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());
|
||||
|
||||
# We get called by common.php, $config is a tree with lots of config
|
||||
# options
|
||||
# These are for configuring your URLs
|
||||
// We get called by common.php, $config is a tree with lots of config
|
||||
// options
|
||||
// These are for configuring your URLs
|
||||
|
||||
$config['site']['name'] = 'Just another Laconica microblog';
|
||||
$config['site']['server'] = 'localhost';
|
||||
$config['site']['path'] = 'laconica';
|
||||
#$config['site']['fancy'] = false;
|
||||
#$config['site']['theme'] = 'default';
|
||||
#To enable the built-in mobile style sheet, defaults to false.
|
||||
#$config['site']['mobile'] = true;
|
||||
#For contact email, defaults to $_SERVER["SERVER_ADMIN"]
|
||||
#$config['site']['email'] = 'admin@example.net';
|
||||
#Brought by...
|
||||
#$config['site']['broughtby'] = 'Individual or Company';
|
||||
#$config['site']['broughtbyurl'] = 'http://example.net/';
|
||||
#If you don't want to let users register (say, for a one-person install)
|
||||
#Crude but effective -- register everybody, then lock down
|
||||
#$config['site']['closed'] = true;
|
||||
#Only allow registration for people invited by another user
|
||||
#$config['site']['inviteonly'] = true;
|
||||
#Make the site invisible to non-logged-in users
|
||||
#$config['site']['private'] = true;
|
||||
// $config['site']['fancy'] = false;
|
||||
// $config['site']['theme'] = 'default';
|
||||
// To enable the built-in mobile style sheet, defaults to false.
|
||||
// $config['site']['mobile'] = true;
|
||||
// For contact email, defaults to $_SERVER["SERVER_ADMIN"]
|
||||
// $config['site']['email'] = 'admin@example.net';
|
||||
// Brought by...
|
||||
// $config['site']['broughtby'] = 'Individual or Company';
|
||||
// $config['site']['broughtbyurl'] = 'http://example.net/';
|
||||
// If you don't want to let users register (say, for a one-person install)
|
||||
// Crude but effective -- register everybody, then lock down
|
||||
// $config['site']['closed'] = true;
|
||||
// Only allow registration for people invited by another user
|
||||
// $config['site']['inviteonly'] = true;
|
||||
// Make the site invisible to non-logged-in users
|
||||
// $config['site']['private'] = true;
|
||||
|
||||
# 'direct' for direct notice links in sections
|
||||
# 'attachment' for notice attachment links in sections
|
||||
# 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
|
||||
// $config['site']['logfile'] = '/tmp/laconica.log';
|
||||
|
||||
# If you want logging sent to a file instead of syslog
|
||||
#$config['site']['logfile'] = '/tmp/laconica.log';
|
||||
// Enables extra log information, for example full details of PEAR DB errors
|
||||
// $config['site']['logdebug'] = true;
|
||||
|
||||
# Enables extra log information, for example full details of PEAR DB errors
|
||||
#$config['site']['logdebug'] = true;
|
||||
// To set your own logo, overriding the one in the theme
|
||||
// $config['site']['logo'] = '/mylogo.png';
|
||||
|
||||
#To set your own logo, overriding the one in the theme
|
||||
#$config['site']['logo'] = '/mylogo.png';
|
||||
|
||||
# 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
|
||||
// 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']['ini_your_db_name'] = $config['db']['schema_location'].'/laconica.ini';
|
||||
# *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||
# 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
|
||||
# ours.
|
||||
# *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||
#$config['db']['debug'] = 0;
|
||||
#$config['db']['db_driver'] = 'MDB2';
|
||||
// $config['db']['ini_your_db_name'] = $config['db']['schema_location'].'/laconica.ini';
|
||||
// *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||
// 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
|
||||
// ours.
|
||||
// *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||
// $config['db']['debug'] = 0;
|
||||
// $config['db']['db_driver'] = 'MDB2';
|
||||
|
||||
#Database type. For mysql, these defaults are fine. For postgresql, set
|
||||
#'quote_identifiers' to true and 'type' to 'pgsql':
|
||||
#$config['db']['quote_identifiers'] = false;
|
||||
#$config['db']['type'] = 'mysql';
|
||||
// Database type. For mysql, these defaults are fine. For postgresql, set
|
||||
// 'quote_identifiers' to true and 'type' to 'pgsql':
|
||||
// $config['db']['quote_identifiers'] = false;
|
||||
// $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
|
||||
#Add your own here. Note: empty array by default
|
||||
#$config['nickname']['blacklist'][] = 'scobleizer';
|
||||
// Standard fancy-url clashes prevented by not allowing nicknames on a blacklist
|
||||
// Add your own here. Note: empty array by default
|
||||
// $config['nickname']['blacklist'][] = 'scobleizer';
|
||||
|
||||
# sphinx search
|
||||
// sphinx search
|
||||
$config['sphinx']['enabled'] = false;
|
||||
$config['sphinx']['server'] = 'localhost';
|
||||
$config['sphinx']['port'] = 3312;
|
||||
|
||||
# Users to populate the 'Featured' tab
|
||||
#$config['nickname']['featured'][] = 'scobleizer';
|
||||
// Users to populate the 'Featured' tab
|
||||
// $config['nickname']['featured'][] = 'scobleizer';
|
||||
|
||||
# xmpp
|
||||
#$config['xmpp']['enabled'] = false;
|
||||
#$config['xmpp']['server'] = 'server.example.net';
|
||||
#$config['xmpp']['host'] = NULL; # Only set if different from server
|
||||
#$config['xmpp']['port'] = 5222;
|
||||
#$config['xmpp']['user'] = 'update';
|
||||
#$config['xmpp']['encryption'] = false;
|
||||
#$config['xmpp']['resource'] = 'uniquename';
|
||||
#$config['xmpp']['password'] = 'blahblahblah';
|
||||
#$config['xmpp']['public'][] = 'someindexer@example.net';
|
||||
#$config['xmpp']['debug'] = false;
|
||||
// xmpp
|
||||
// $config['xmpp']['enabled'] = false;
|
||||
// $config['xmpp']['server'] = 'server.example.net';
|
||||
// $config['xmpp']['host'] = NULL; // Only set if different from server
|
||||
// $config['xmpp']['port'] = 5222;
|
||||
// $config['xmpp']['user'] = 'update';
|
||||
// $config['xmpp']['encryption'] = false;
|
||||
// $config['xmpp']['resource'] = 'uniquename';
|
||||
// $config['xmpp']['password'] = 'blahblahblah';
|
||||
// $config['xmpp']['public'][] = 'someindexer@example.net';
|
||||
// $config['xmpp']['debug'] = false;
|
||||
|
||||
#Default locale info
|
||||
#$config['site']['timezone'] = 'Pacific/Auckland';
|
||||
#$config['site']['language'] = 'en_NZ';
|
||||
// Default locale info
|
||||
// $config['site']['timezone'] = 'Pacific/Auckland';
|
||||
// $config['site']['language'] = 'en_NZ';
|
||||
|
||||
#Email info, used for all outbound email
|
||||
#$config['mail']['notifyfrom'] = 'microblog@example.net';
|
||||
#$config['mail']['domain'] = 'microblog.example.net';
|
||||
# See http://pear.php.net/manual/en/package.mail.mail.factory.php for options
|
||||
#$config['mail']['backend'] = 'smtp';
|
||||
#$config['mail']['params'] = array(
|
||||
# 'host' => 'localhost',
|
||||
# 'port' => 25,
|
||||
# );
|
||||
#For incoming email, if enabled. Defaults to site server name.
|
||||
#$config['mail']['domain'] = 'incoming.example.net';
|
||||
// Email info, used for all outbound email
|
||||
// $config['mail']['notifyfrom'] = 'microblog@example.net';
|
||||
// $config['mail']['domain'] = 'microblog.example.net';
|
||||
// See http://pear.php.net/manual/en/package.mail.mail.factory.php for options
|
||||
// $config['mail']['backend'] = 'smtp';
|
||||
// $config['mail']['params'] = array(
|
||||
// 'host' => 'localhost',
|
||||
// 'port' => 25,
|
||||
// );
|
||||
// For incoming email, if enabled. Defaults to site server name.
|
||||
// $config['mail']['domain'] = 'incoming.example.net';
|
||||
|
||||
#exponential decay factor for tags, default 10 days
|
||||
#raise this if traffic is slow, lower it if it's fast
|
||||
#$config['tag']['dropoff'] = 86400.0 * 10;
|
||||
// exponential decay factor for tags, default 10 days
|
||||
// raise this if traffic is slow, lower it if it's fast
|
||||
// $config['tag']['dropoff'] = 86400.0 * 10;
|
||||
|
||||
#exponential decay factor for popular (most favorited notices)
|
||||
#default 10 days -- similar to tag dropoff
|
||||
#$config['popular']['dropoff'] = 86400.0 * 10;
|
||||
// exponential decay factor for popular (most favorited notices)
|
||||
// default 10 days -- similar to tag dropoff
|
||||
// $config['popular']['dropoff'] = 86400.0 * 10;
|
||||
|
||||
#optionally show non-local messages in public timeline
|
||||
#$config['public']['localonly'] = false;
|
||||
// optionally show non-local messages in public timeline
|
||||
// $config['public']['localonly'] = false;
|
||||
|
||||
#hide certain users from public pages, by ID
|
||||
#$config['public']['blacklist'][] = 123;
|
||||
#$config['public']['blacklist'][] = 2307;
|
||||
// hide certain users from public pages, by ID
|
||||
// $config['public']['blacklist'][] = 123;
|
||||
// $config['public']['blacklist'][] = 2307;
|
||||
|
||||
#Mark certain notice sources as automatic and thus not
|
||||
#appropriate for public feed
|
||||
#$config['public]['autosource'][] = 'twitterfeed';
|
||||
#$config['public]['autosource'][] = 'rssdent';
|
||||
#$config['public]['autosource'][] = 'Ping.Fm';
|
||||
#$config['public]['autosource'][] = 'HelloTxt';
|
||||
#$config['public]['autosource'][] = 'Updating.Me';
|
||||
// Mark certain notice sources as automatic and thus not
|
||||
// appropriate for public feed
|
||||
// $config['public]['autosource'][] = 'twitterfeed';
|
||||
// $config['public]['autosource'][] = 'rssdent';
|
||||
// $config['public]['autosource'][] = 'Ping.Fm';
|
||||
// $config['public]['autosource'][] = 'HelloTxt';
|
||||
// $config['public]['autosource'][] = 'Updating.Me';
|
||||
|
||||
#Do notice broadcasts offline
|
||||
#If you use this, you must run the six offline daemons in the
|
||||
#background. See the README for details.
|
||||
#$config['queue']['enabled'] = true;
|
||||
// Do notice broadcasts offline
|
||||
// If you use this, you must run the six offline daemons in the
|
||||
// background. See the README for details.
|
||||
// $config['queue']['enabled'] = true;
|
||||
|
||||
#Queue subsystem
|
||||
#subsystems: internal (default) or stomp
|
||||
#using stomp requires an external message queue server
|
||||
#$config['queue']['subsystem'] = 'stomp';
|
||||
#$config['queue']['stomp_server'] = 'tcp://localhost:61613';
|
||||
#use different queue_basename for each laconica instance managed by the server
|
||||
#$config['queue']['queue_basename'] = 'laconica';
|
||||
// Queue subsystem
|
||||
// subsystems: internal (default) or stomp
|
||||
// using stomp requires an external message queue server
|
||||
// $config['queue']['subsystem'] = 'stomp';
|
||||
// $config['queue']['stomp_server'] = 'tcp://localhost:61613';
|
||||
// use different queue_basename for each laconica instance managed by the server
|
||||
// $config['queue']['queue_basename'] = 'laconica';
|
||||
|
||||
#The following customise the behaviour of the various daemons:
|
||||
#$config['daemon']['piddir'] = '/var/run';
|
||||
#$config['daemon']['user'] = false;
|
||||
#$config['daemon']['group'] = false;
|
||||
// The following customise the behaviour of the various daemons:
|
||||
// $config['daemon']['piddir'] = '/var/run';
|
||||
// $config['daemon']['user'] = false;
|
||||
// $config['daemon']['group'] = false;
|
||||
|
||||
#For installations with high traffic, laconica can use MemCached to cache
|
||||
#frequently requested information. Only enable the following if you have
|
||||
#MemCached up and running:
|
||||
#$config['memcached']['enabled'] = false;
|
||||
#$config['memcached']['server'] = 'localhost';
|
||||
#$config['memcached']['port'] = 11211;
|
||||
// For installations with high traffic, laconica can use MemCached to cache
|
||||
// frequently requested information. Only enable the following if you have
|
||||
// MemCached up and running:
|
||||
// $config['memcached']['enabled'] = false;
|
||||
// $config['memcached']['server'] = 'localhost';
|
||||
// $config['memcached']['port'] = 11211;
|
||||
|
||||
# Enable bidirectional Twitter bridge
|
||||
#$config['twitterbridge']['enabled'] = true;
|
||||
// Twitter integration source attribute. Note: default is Laconica
|
||||
// $config['integration']['source'] = 'Laconica';
|
||||
|
||||
#Twitter integration source attribute. Note: default is Laconica
|
||||
#$config['integration']['source'] = 'Laconica';
|
||||
// Edit throttling. Off by default. If turned on, you can only post 20 notices
|
||||
// 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
|
||||
# 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.
|
||||
// $config['throttle']['enabled'] = true;
|
||||
// $config['throttle']['count'] = 100;
|
||||
// $config['throttle']['timespan'] = 3600;
|
||||
|
||||
#$config['throttle']['enabled'] = true;
|
||||
#$config['throttle']['count'] = 100;
|
||||
#$config['throttle']['timespan'] = 3600;
|
||||
// List of users banned from posting (nicknames and/or IDs)
|
||||
// $config['profile']['banned'][] = 'hacker';
|
||||
// $config['profile']['banned'][] = 12345;
|
||||
|
||||
# List of users banned from posting (nicknames and/or IDs)
|
||||
#$config['profile']['banned'][] = 'hacker';
|
||||
#$config['profile']['banned'][] = 12345;
|
||||
// Config section for the built-in Facebook application
|
||||
// $config['facebook']['apikey'] = 'APIKEY';
|
||||
// $config['facebook']['secret'] = 'SECRET';
|
||||
|
||||
# Config section for the built-in Facebook application
|
||||
#$config['facebook']['apikey'] = 'APIKEY';
|
||||
#$config['facebook']['secret'] = 'SECRET';
|
||||
// Add Google Analytics
|
||||
// require_once('plugins/GoogleAnalyticsPlugin.php');
|
||||
// $ga = new GoogleAnalyticsPlugin('your secret code');
|
||||
|
||||
# Facebook Connect plugin (Needs valid APIKEY above)
|
||||
#require_once(INSTALLDIR.'/plugins/FBConnect/FBConnectPlugin.php');
|
||||
#$fbc = new FBConnectPlugin();
|
||||
// Use Templating (template: /tpl/index.php)
|
||||
// require_once('plugins/TemplatePlugin.php');
|
||||
// $tpl = new TemplatePlugin();
|
||||
|
||||
# Add Google Analytics
|
||||
# require_once('plugins/GoogleAnalyticsPlugin.php');
|
||||
# $ga = new GoogleAnalyticsPlugin('your secret code');
|
||||
// Don't allow saying the same thing more than once per hour
|
||||
// $config['site']['dupelimit'] = 3600;
|
||||
// Don't enforce the dupe limit
|
||||
// $config['site']['dupelimit'] = -1;
|
||||
|
||||
# Use Templating (template: /tpl/index.php)
|
||||
# require_once('plugins/TemplatePlugin.php');
|
||||
# $tpl = new TemplatePlugin();
|
||||
// Base string for minting Tag URIs in Atom feeds. Defaults to
|
||||
// "yourserver,2009". This needs to be configured properly for your Atom
|
||||
// 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
|
||||
#$config['site']['dupelimit'] = 3600;
|
||||
#Don't enforce the dupe limit
|
||||
#$config['site']['dupelimit'] = -1;
|
||||
// Don't use SSL
|
||||
// $config['site']['ssl'] = 'never';
|
||||
// Use SSL only for sensitive pages (like login, password change)
|
||||
// $config['site']['ssl'] = 'sometimes';
|
||||
// Use SSL for all pages
|
||||
// $config['site']['ssl'] = 'always';
|
||||
|
||||
#Base string for minting Tag URIs in Atom feeds. Defaults to
|
||||
#"yourserver,2009". This needs to be configured properly for your Atom
|
||||
#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'
|
||||
// Use a different hostname for SSL-encrypted pages
|
||||
// $config['site']['sslserver'] = 'secure.example.org';
|
||||
|
||||
#Don't use SSL
|
||||
#$config['site']['ssl'] = 'never';
|
||||
#Use SSL only for sensitive pages (like login, password change)
|
||||
#$config['site']['ssl'] = 'sometimes';
|
||||
#Use SSL for all pages
|
||||
#$config['site']['ssl'] = 'always';
|
||||
// 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);
|
||||
// }
|
||||
|
||||
#Use a different hostname for SSL-encrypted pages
|
||||
#$config['site']['sslserver'] = 'secure.example.org';
|
||||
// How often to send snapshots; in # of web hits. Ideally,
|
||||
// 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)
|
||||
values
|
||||
('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 (
|
||||
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),
|
||||
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',
|
||||
@ -426,12 +426,12 @@ create table group_inbox (
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table file (
|
||||
id integer primary key auto_increment,
|
||||
url varchar(255), mimetype varchar(50),
|
||||
size integer,
|
||||
title varchar(255),
|
||||
date integer(11),
|
||||
protected integer(1),
|
||||
id integer primary key auto_increment,
|
||||
url varchar(255), mimetype varchar(50),
|
||||
size integer,
|
||||
title varchar(255),
|
||||
date integer(11),
|
||||
protected integer(1),
|
||||
|
||||
unique(url)
|
||||
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
@ -447,40 +447,38 @@ create table file_oembed (
|
||||
height integer,
|
||||
html text,
|
||||
title varchar(255),
|
||||
author_name varchar(50),
|
||||
author_url varchar(255),
|
||||
url varchar(255),
|
||||
author_name varchar(50),
|
||||
author_url varchar(255),
|
||||
url varchar(255),
|
||||
|
||||
unique(file_id)
|
||||
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
|
||||
create table file_redirection (
|
||||
id integer primary key auto_increment,
|
||||
url varchar(255),
|
||||
file_id integer,
|
||||
redirections integer,
|
||||
httpcode integer,
|
||||
id integer primary key auto_increment,
|
||||
url varchar(255),
|
||||
file_id integer,
|
||||
redirections integer,
|
||||
httpcode integer,
|
||||
|
||||
unique(url)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table file_thumbnail (
|
||||
id integer primary key auto_increment,
|
||||
file_id integer,
|
||||
url varchar(255),
|
||||
width integer,
|
||||
height integer,
|
||||
id integer primary key auto_increment,
|
||||
file_id integer,
|
||||
url varchar(255),
|
||||
width integer,
|
||||
height integer,
|
||||
|
||||
unique(file_id),
|
||||
unique(file_id),
|
||||
unique(url)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table file_to_post (
|
||||
id integer primary key auto_increment,
|
||||
file_id integer,
|
||||
post_id integer,
|
||||
id integer primary key auto_increment,
|
||||
file_id integer,
|
||||
post_id integer,
|
||||
|
||||
unique(file_id, post_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
|
||||
|
@ -2,13 +2,16 @@ INSERT INTO notice_source
|
||||
(code, name, url, created)
|
||||
VALUES
|
||||
('adium', 'Adium', 'http://www.adiumx.com/', now()),
|
||||
('AgentSolo.com','AgentSolo.com','http://www.agentsolo.com/', now()),
|
||||
('betwittered','BeTwittered','http://www.32hours.com/betwitteredinfo/', now()),
|
||||
('bti','bti','http://gregkh.github.com/bti/', now()),
|
||||
('cliqset', 'Cliqset', 'http://www.cliqset.com/', 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()),
|
||||
('eventbox','EventBox','http://thecosmicmachine.com/eventbox/ ', now()),
|
||||
('Facebook','Facebook','http://apps.facebook.com/identica/', now()),
|
||||
('feed2omb','feed2omb','http://projects.ciarang.com/p/feed2omb/', now()),
|
||||
('gravity', 'Gravity', 'http://mobileways.de/gravity', now()),
|
||||
('Gwibber','Gwibber','http://launchpad.net/gwibber', now()),
|
||||
('HelloTxt','HelloTxt','http://hellotxt.com/', now()),
|
||||
('identicatools','Laconica Tools','http://bitbucketlabs.net/laconica-tools/', now()),
|
||||
@ -27,6 +30,7 @@ VALUES
|
||||
('pingvine','PingVine','http://pingvine.com/', now()),
|
||||
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
|
||||
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
|
||||
('qtwitter','qTwitter','http://qtwitter.ayoy.net/', now()),
|
||||
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
|
||||
('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', 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()
|
||||
{
|
||||
// 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.");
|
||||
}
|
||||
global $user, $action, $config;
|
||||
|
||||
Snapshot::check();
|
||||
|
||||
if (!_have_config()) {
|
||||
$msg = sprintf(_("No configuration file found. Try running ".
|
||||
"the installation program first."));
|
||||
|
61
install.php
61
install.php
@ -35,15 +35,17 @@ function main()
|
||||
|
||||
function checkPrereqs()
|
||||
{
|
||||
$pass = true;
|
||||
|
||||
if (file_exists(INSTALLDIR.'/config.php')) {
|
||||
?><p class="error">Config file "config.php" already exists.</p>
|
||||
<?php
|
||||
return false;
|
||||
$pass = false;
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
|
||||
?><p class="error">Require PHP version 5 or greater.</p><?php
|
||||
return false;
|
||||
$pass = false;
|
||||
}
|
||||
|
||||
$reqs = array('gd', 'mysql', 'curl',
|
||||
@ -53,7 +55,7 @@ function checkPrereqs()
|
||||
foreach ($reqs as $req) {
|
||||
if (!checkExtension($req)) {
|
||||
?><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>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?></code>
|
||||
<?php
|
||||
return false;
|
||||
$pass = false;
|
||||
}
|
||||
|
||||
if (!is_writable(INSTALLDIR.'/avatar/')) {
|
||||
?><p class="error">Cannot write avatar directory: <code><?php echo INSTALLDIR; ?>/avatar/</code></p>
|
||||
<p>On your server, try this command: <code>chmod a+w <?php echo INSTALLDIR; ?>/avatar/</code></p>
|
||||
<?
|
||||
return false;
|
||||
$pass = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $pass;
|
||||
}
|
||||
|
||||
function checkExtension($name)
|
||||
@ -114,16 +116,16 @@ function showForm()
|
||||
<input type="radio" name="fancy" id="fancy-disable" value="" /> disable<br />
|
||||
<p class="form_guide" id='fancy-form_guide'>Enable fancy (pretty) URLs. Auto-detection failed, it depends on Javascript.</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="host">Hostname</label>
|
||||
<input type="text" id="host" name="host" />
|
||||
<p class="form_guide">Database hostname</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="host">Site path</label>
|
||||
<input type="text" id="path" name="path" value="$config_path" />
|
||||
<p class="form_guide">Site path, following the "/" after the domain name in the URL. Empty is fine. Field should be filled automatically.</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="host">Hostname</label>
|
||||
<input type="text" id="host" name="host" />
|
||||
<p class="form_guide">Database hostname</p>
|
||||
</li>
|
||||
<li>
|
||||
<label for="host">Database</label>
|
||||
<input type="text" id="database" name="database" />
|
||||
@ -173,36 +175,38 @@ function handlePost()
|
||||
<dd>
|
||||
<ul>
|
||||
<?php
|
||||
$fail = false;
|
||||
|
||||
if (empty($host)) {
|
||||
updateStatus("No hostname specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if (empty($database)) {
|
||||
updateStatus("No database specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if (empty($username)) {
|
||||
updateStatus("No username specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if (empty($password)) {
|
||||
updateStatus("No password specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if (empty($sitename)) {
|
||||
updateStatus("No sitename specified.", true);
|
||||
showForm();
|
||||
return;
|
||||
$fail = true;
|
||||
}
|
||||
|
||||
if($fail){
|
||||
showForm();
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus("Starting installation...");
|
||||
updateStatus("Checking database...");
|
||||
$conn = mysql_connect($host, $username, $password);
|
||||
@ -247,7 +251,7 @@ function handlePost()
|
||||
}
|
||||
updateStatus("Done!");
|
||||
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
|
||||
@ -257,16 +261,17 @@ function writeConf($sitename, $sqlUrl, $fancy, $path)
|
||||
{
|
||||
$res = file_put_contents(INSTALLDIR.'/config.php',
|
||||
"<?php\n".
|
||||
"if (!defined('LACONICA')) { exit(1); }\n\n".
|
||||
"\$config['site']['name'] = \"$sitename\";\n\n".
|
||||
($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
|
||||
"\$config['site']['path'] = \"$path\";\n\n".
|
||||
"\$config['db']['database'] = \"$sqlUrl\";\n\n");
|
||||
"\$config['db']['database'] = \"$sqlUrl\";\n\n".
|
||||
"?>");
|
||||
return $res;
|
||||
}
|
||||
|
||||
function runDbScript($filename, $conn)
|
||||
{
|
||||
return true;
|
||||
$sql = trim(file_get_contents($filename));
|
||||
$stmts = explode(';', $sql);
|
||||
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">
|
||||
<head>
|
||||
<title>Install Laconica</title>
|
||||
<link rel="stylesheet" type="text/css" href="theme/base/css/display.css?version=0.8" media="screen, projection, tv"/>
|
||||
<link rel="shortcut icon" href="favicon.ico"/>
|
||||
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
|
||||
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
|
||||
<!--[if lte IE 6]><link rel="stylesheet" type="text/css" theme/base/css/ie6.css?version=0.8" /><![endif]-->
|
||||
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/earthy/css/ie.css?version=0.8" /><![endif]-->
|
||||
<script src='js/jquery.min.js'></script>
|
||||
<script src='js/install.js'></script>
|
||||
<!--[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/install.js"></script>
|
||||
</head>
|
||||
<body id="install">
|
||||
<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() {
|
||||
function UpdateColors(e) {
|
||||
var S = f.linked;
|
||||
var C = f.color;
|
||||
|
||||
if (S && S.value && S.value != C) {
|
||||
UpdateSwatch(S);
|
||||
|
||||
switch (parseInt(f.linked.id.slice(-1))) {
|
||||
case 0: default:
|
||||
$('body').css({'background-color':C});
|
||||
break;
|
||||
case 1:
|
||||
$('#content').css({'background-color':C});
|
||||
break;
|
||||
case 2:
|
||||
$('#aside_primary').css({'background-color':C});
|
||||
break;
|
||||
case 3:
|
||||
$('body').css({'color':C});
|
||||
break;
|
||||
case 4:
|
||||
$('a').css({'color':C});
|
||||
break;
|
||||
}
|
||||
S.value = C;
|
||||
function UpdateColors(S) {
|
||||
C = $(S).val();
|
||||
switch (parseInt(S.id.slice(-1))) {
|
||||
case 0: default:
|
||||
$('body').css({'background-color':C});
|
||||
break;
|
||||
case 1:
|
||||
$('#content').css({'background-color':C});
|
||||
break;
|
||||
case 2:
|
||||
$('#aside_primary').css({'background-color':C});
|
||||
break;
|
||||
case 3:
|
||||
$('body').css({'color':C});
|
||||
break;
|
||||
case 4:
|
||||
$('a').css({'color':C});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,35 +34,52 @@ $(document).ready(function() {
|
||||
}
|
||||
|
||||
function UpdateSwatch(e) {
|
||||
$(e).css({
|
||||
"background-color": e.value,
|
||||
"color": f.hsl[2] > 0.5 ? "#000": "#fff"
|
||||
});
|
||||
$(e).css({"background-color": e.value,
|
||||
"color": f.hsl[2] > 0.5 ? "#000": "#fff"});
|
||||
}
|
||||
|
||||
$('#settings_design_color').append('<div id="color-picker"></div>');
|
||||
$('#color-picker').hide();
|
||||
function SynchColors(e) {
|
||||
var S = f.linked;
|
||||
var C = f.color;
|
||||
|
||||
var f = $.farbtastic('#color-picker', UpdateColors);
|
||||
var swatches = $('#settings_design_color .swatch');
|
||||
if (S && S.value && S.value != C) {
|
||||
S.value = C;
|
||||
UpdateSwatch(S);
|
||||
UpdateColors(S);
|
||||
}
|
||||
}
|
||||
|
||||
swatches
|
||||
.each(UpdateColors)
|
||||
function Init() {
|
||||
$('#settings_design_color').append('<div id="color-picker"></div>');
|
||||
$('#color-picker').hide();
|
||||
|
||||
.blur(function() {
|
||||
$(this).val($(this).val().toUpperCase());
|
||||
})
|
||||
f = $.farbtastic('#color-picker', SynchColors);
|
||||
swatches = $('#settings_design_color .swatch');
|
||||
|
||||
.focus(function() {
|
||||
$('#color-picker').show();
|
||||
UpdateFarbtastic(this);
|
||||
})
|
||||
|
||||
.change(function() {
|
||||
UpdateFarbtastic(this);
|
||||
UpdateSwatch(this);
|
||||
}).change()
|
||||
|
||||
;
|
||||
swatches
|
||||
.each(SynchColors)
|
||||
.blur(function() {
|
||||
$(this).val($(this).val().toUpperCase());
|
||||
})
|
||||
.focus(function() {
|
||||
$('#color-picker').show();
|
||||
UpdateFarbtastic(this);
|
||||
})
|
||||
.change(function() {
|
||||
UpdateFarbtastic(this);
|
||||
UpdateSwatch(this);
|
||||
UpdateColors(this);
|
||||
}).change();
|
||||
}
|
||||
|
||||
var f, swatches;
|
||||
Init();
|
||||
$('#form_settings_design').bind('reset', function(){
|
||||
setTimeout(function(){
|
||||
swatches.each(function(){UpdateColors(this);});
|
||||
$('#color-picker').remove();
|
||||
swatches.unbind();
|
||||
Init();
|
||||
},10);
|
||||
});
|
||||
});
|
||||
|
@ -1,39 +1,48 @@
|
||||
$(function(){
|
||||
var x = ($('#avatar_crop_x').val()) ? $('#avatar_crop_x').val() : 0;
|
||||
var y = ($('#avatar_crop_y').val()) ? $('#avatar_crop_y').val() : 0;
|
||||
var w = ($('#avatar_crop_w').val()) ? $('#avatar_crop_w').val() : $("#avatar_original img").attr("width");
|
||||
var h = ($('#avatar_crop_h').val()) ? $('#avatar_crop_h').val() : $("#avatar_original img").attr("height");
|
||||
/** Init for Jcrop library and page setup
|
||||
*
|
||||
* @package Laconica
|
||||
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||
* @copyright 2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
jQuery("#avatar_original img").Jcrop({
|
||||
onChange: showPreview,
|
||||
setSelect: [ x, y, w, h ],
|
||||
onSelect: updateCoords,
|
||||
aspectRatio: 1,
|
||||
boxWidth: 480,
|
||||
boxHeight: 480,
|
||||
bgColor: '#000',
|
||||
bgOpacity: .4
|
||||
});
|
||||
});
|
||||
$(function(){
|
||||
var x = ($('#avatar_crop_x').val()) ? $('#avatar_crop_x').val() : 0;
|
||||
var y = ($('#avatar_crop_y').val()) ? $('#avatar_crop_y').val() : 0;
|
||||
var w = ($('#avatar_crop_w').val()) ? $('#avatar_crop_w').val() : $("#avatar_original img").attr("width");
|
||||
var h = ($('#avatar_crop_h').val()) ? $('#avatar_crop_h').val() : $("#avatar_original img").attr("height");
|
||||
|
||||
function showPreview(coords) {
|
||||
var rx = 96 / coords.w;
|
||||
var ry = 96 / coords.h;
|
||||
jQuery("#avatar_original img").Jcrop({
|
||||
onChange: showPreview,
|
||||
setSelect: [ x, y, w, h ],
|
||||
onSelect: updateCoords,
|
||||
aspectRatio: 1,
|
||||
boxWidth: 480,
|
||||
boxHeight: 480,
|
||||
bgColor: '#000',
|
||||
bgOpacity: .4
|
||||
});
|
||||
});
|
||||
|
||||
var img_width = $("#avatar_original img").attr("width");
|
||||
var img_height = $("#avatar_original img").attr("height");
|
||||
function showPreview(coords) {
|
||||
var rx = 96 / coords.w;
|
||||
var ry = 96 / coords.h;
|
||||
|
||||
$('#avatar_preview img').css({
|
||||
width: Math.round(rx *img_width) + 'px',
|
||||
height: Math.round(ry * img_height) + 'px',
|
||||
marginLeft: '-' + Math.round(rx * coords.x) + 'px',
|
||||
marginTop: '-' + Math.round(ry * coords.y) + 'px'
|
||||
});
|
||||
};
|
||||
var img_width = $("#avatar_original img").attr("width");
|
||||
var img_height = $("#avatar_original img").attr("height");
|
||||
|
||||
function updateCoords(c) {
|
||||
$('#avatar_crop_x').val(c.x);
|
||||
$('#avatar_crop_y').val(c.y);
|
||||
$('#avatar_crop_w').val(c.w);
|
||||
$('#avatar_crop_h').val(c.h);
|
||||
};
|
||||
$('#avatar_preview img').css({
|
||||
width: Math.round(rx *img_width) + 'px',
|
||||
height: Math.round(ry * img_height) + 'px',
|
||||
marginLeft: '-' + Math.round(rx * coords.x) + 'px',
|
||||
marginTop: '-' + Math.round(ry * coords.y) + 'px'
|
||||
});
|
||||
};
|
||||
|
||||
function updateCoords(c) {
|
||||
$('#avatar_crop_x').val(c.x);
|
||||
$('#avatar_crop_y').val(c.y);
|
||||
$('#avatar_crop_w').val(c.w);
|
||||
$('#avatar_crop_h').val(c.h);
|
||||
};
|
||||
|
@ -157,7 +157,7 @@ $.fn.ajaxSubmit = function(options) {
|
||||
function fileUpload() {
|
||||
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".');
|
||||
return;
|
||||
}
|
||||
@ -570,7 +570,7 @@ $.fn.clearForm = function() {
|
||||
$.fn.clearFields = $.fn.clearInputs = function() {
|
||||
return this.each(function() {
|
||||
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 = '';
|
||||
else if (t == 'checkbox' || t == 'radio')
|
||||
this.checked = false;
|
||||
|
80
js/util.js
80
js/util.js
@ -17,10 +17,6 @@
|
||||
*/
|
||||
|
||||
$(document).ready(function(){
|
||||
$('.attachments').click(function() {$().jOverlay({zIndex:999, success:function(html) {$('.attachment').click(function() {$().jOverlay({url:$(this).attr('href') + '/ajax'}); return false; });
|
||||
}, url:$(this).attr('href') + '/ajax'}); return false; });
|
||||
$('.attachment').click(function() {$().jOverlay({url:$(this).attr('href') + '/ajax'}); return false; });
|
||||
|
||||
// count character on keyup
|
||||
function counter(event){
|
||||
var maxLength = 140;
|
||||
@ -203,11 +199,11 @@ $(document).ready(function(){
|
||||
$("#notices_primary .notices").prepend(document._importNode(li, true));
|
||||
$("#notices_primary .notice:first").css({display:"none"});
|
||||
$("#notices_primary .notice:first").fadeIn(2500);
|
||||
NoticeHover();
|
||||
NoticeReply();
|
||||
}
|
||||
}
|
||||
$("#notice_data-text").val("");
|
||||
$("#notice_data-attach").val("");
|
||||
counter();
|
||||
}
|
||||
$("#form_notice").removeClass("processing");
|
||||
@ -219,26 +215,26 @@ $(document).ready(function(){
|
||||
$("#form_notice").each(addAjaxHidden);
|
||||
NoticeHover();
|
||||
NoticeReply();
|
||||
NoticeAttachments();
|
||||
});
|
||||
|
||||
|
||||
function NoticeHover() {
|
||||
$("#content .notice").hover(
|
||||
function () {
|
||||
$(this).addClass('hover');
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass('hover');
|
||||
}
|
||||
);
|
||||
function mouseHandler(e) {
|
||||
$(e.target).closest('li.hentry')[(e.type === 'mouseover') ? 'addClass' : 'removeClass']('hover');
|
||||
};
|
||||
$('#content .notices').mouseover(mouseHandler);
|
||||
$('#content .notices').mouseout(mouseHandler);
|
||||
}
|
||||
|
||||
|
||||
function NoticeReply() {
|
||||
if ($('#notice_data-text').length > 0) {
|
||||
$('#content .notice').each(function() {
|
||||
var notice = $(this);
|
||||
$('.notice_reply', $(this)).click(function() {
|
||||
var nickname = ($('.author .nickname', notice).length > 0) ? $('.author .nickname', notice) : $('.author .nickname');
|
||||
NoticeReplySet(nickname.text(), $('.notice_id', notice).text());
|
||||
var notice = $(this)[0];
|
||||
$($('.notice_reply', notice)[0]).click(function() {
|
||||
var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname');
|
||||
NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text());
|
||||
return false;
|
||||
});
|
||||
});
|
||||
@ -258,3 +254,53 @@ function NoticeReplySet(nick,id) {
|
||||
}
|
||||
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()
|
||||
{
|
||||
// $this->out->elementStart('div', array('id' =>'attachments_primary'));
|
||||
$this->out->elementStart('div', array('id' =>'content'));
|
||||
$this->out->element('h2', null, _('Attachments'));
|
||||
$this->out->elementStart('ul', array('class' => 'attachments'));
|
||||
|
||||
$atts = new File;
|
||||
$att = $atts->getAttachments($this->notice->id);
|
||||
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) {
|
||||
$item = $this->newListItem($attachment);
|
||||
$item->show();
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('div');
|
||||
$this->out->elementEnd('dd');
|
||||
$this->out->elementEnd('ol');
|
||||
$this->out->elementEnd('dl');
|
||||
|
||||
return count($att);
|
||||
}
|
||||
@ -171,7 +173,7 @@ class AttachmentListItem extends Widget
|
||||
}
|
||||
|
||||
function linkTitle() {
|
||||
return 'Our page for ' . $this->title();
|
||||
return $this->title();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,34 +193,25 @@ class AttachmentListItem extends Widget
|
||||
}
|
||||
|
||||
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() {
|
||||
$attr = $this->linkAttr();
|
||||
$text = $this->linkTitle();
|
||||
$this->out->elementStart('h4');
|
||||
$this->out->element('a', $attr, $text);
|
||||
|
||||
if ($this->attachment->url !== $this->title())
|
||||
$this->out->element('span', null, " ({$this->attachment->url})");
|
||||
|
||||
|
||||
$this->out->elementEnd('h4');
|
||||
$this->out->elementStart('a', $this->linkAttr());
|
||||
$this->out->element('span', null, $this->linkTitle());
|
||||
$this->showRepresentation();
|
||||
$this->out->elementEnd('a');
|
||||
}
|
||||
|
||||
function showNoticeAttachment()
|
||||
{
|
||||
$this->showLink();
|
||||
$this->showRepresentation();
|
||||
}
|
||||
|
||||
function showRepresentation() {
|
||||
$thumbnail = File_thumbnail::staticGet('file_id', $this->attachment->id);
|
||||
if (!empty($thumbnail)) {
|
||||
$this->out->elementStart('a', $this->linkAttr()/*'href' => $this->linkTo()*/);
|
||||
$this->out->element('img', array('alt' => 'nothing to say', 'src' => $thumbnail->url, 'width' => $thumbnail->width, 'height' => $thumbnail->height));
|
||||
$this->out->elementEnd('a');
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,7 +253,7 @@ class Attachment extends AttachmentListItem
|
||||
}
|
||||
|
||||
function linkTitle() {
|
||||
return 'Direct link to ' . $this->title();
|
||||
return $this->attachment->url;
|
||||
}
|
||||
|
||||
function showRepresentation() {
|
||||
@ -275,6 +268,23 @@ class Attachment extends AttachmentListItem
|
||||
case 'image/jpeg':
|
||||
$this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt'));
|
||||
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 {
|
||||
|
@ -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); }
|
||||
|
||||
define('LACONICA_VERSION', '0.7.3');
|
||||
define('LACONICA_VERSION', '0.8.0dev');
|
||||
|
||||
define('AVATAR_PROFILE_SIZE', 96);
|
||||
define('AVATAR_STREAM_SIZE', 48);
|
||||
@ -159,6 +159,46 @@ $config =
|
||||
'newuser' =>
|
||||
array('subscribe' => 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');
|
||||
@ -170,6 +210,7 @@ $config['db'] =
|
||||
'require_prefix' => 'classes/',
|
||||
'class_prefix' => '',
|
||||
'mirror' => null,
|
||||
'utf8' => true,
|
||||
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
||||
'quote_identifiers' => false,
|
||||
'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?
|
||||
|
||||
require_once('Validate.php');
|
||||
require_once('markdown.php');
|
||||
require_once 'Validate.php';
|
||||
require_once 'markdown.php';
|
||||
|
||||
require_once(INSTALLDIR.'/lib/util.php');
|
||||
require_once(INSTALLDIR.'/lib/action.php');
|
||||
require_once(INSTALLDIR.'/lib/theme.php');
|
||||
require_once(INSTALLDIR.'/lib/mail.php');
|
||||
require_once(INSTALLDIR.'/lib/subs.php');
|
||||
require_once(INSTALLDIR.'/lib/Shorturl_api.php');
|
||||
require_once(INSTALLDIR.'/lib/twitter.php');
|
||||
require_once INSTALLDIR.'/lib/util.php';
|
||||
require_once INSTALLDIR.'/lib/action.php';
|
||||
require_once INSTALLDIR.'/lib/theme.php';
|
||||
require_once INSTALLDIR.'/lib/mail.php';
|
||||
require_once INSTALLDIR.'/lib/subs.php';
|
||||
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||
require_once INSTALLDIR.'/lib/twitter.php';
|
||||
|
||||
require_once(INSTALLDIR.'/lib/clientexception.php');
|
||||
require_once(INSTALLDIR.'/lib/serverexception.php');
|
||||
require_once INSTALLDIR.'/lib/clientexception.php';
|
||||
require_once INSTALLDIR.'/lib/serverexception.php';
|
||||
|
||||
// XXX: other formats here
|
||||
|
||||
|
@ -38,14 +38,14 @@ require_once INSTALLDIR.'/lib/noticeform.php';
|
||||
|
||||
class FacebookAction extends Action
|
||||
{
|
||||
|
||||
|
||||
var $facebook = null;
|
||||
var $fbuid = null;
|
||||
var $flink = null;
|
||||
var $action = null;
|
||||
var $app_uri = null;
|
||||
var $app_name = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -60,71 +60,71 @@ class FacebookAction extends Action
|
||||
function __construct($output='php://output', $indent=true, $facebook=null, $flink=null)
|
||||
{
|
||||
parent::__construct($output, $indent);
|
||||
|
||||
|
||||
$this->facebook = $facebook;
|
||||
$this->flink = $flink;
|
||||
|
||||
|
||||
if ($this->flink) {
|
||||
$this->fbuid = $flink->foreign_id;
|
||||
$this->fbuid = $flink->foreign_id;
|
||||
$this->user = $flink->getUser();
|
||||
}
|
||||
|
||||
|
||||
$this->args = array();
|
||||
}
|
||||
|
||||
|
||||
function prepare($argarray)
|
||||
{
|
||||
{
|
||||
parent::prepare($argarray);
|
||||
|
||||
|
||||
$this->facebook = getFacebook();
|
||||
$this->fbuid = $this->facebook->require_login();
|
||||
|
||||
|
||||
$this->action = $this->trimmed('action');
|
||||
|
||||
|
||||
$app_props = $this->facebook->api_client->Admin_getAppProperties(
|
||||
array('canvas_name', 'application_name'));
|
||||
|
||||
|
||||
$this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name'];
|
||||
$this->app_name = $app_props['application_name'];
|
||||
|
||||
$this->flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE);
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function showStylesheets()
|
||||
{
|
||||
// Add a timestamp to the file so Facebook cache wont ignore our changes
|
||||
$ts = filemtime(INSTALLDIR.'/theme/base/css/display.css');
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
||||
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
|
||||
|
||||
$theme = common_config('site', 'theme');
|
||||
|
||||
|
||||
$ts = filemtime(INSTALLDIR. '/theme/' . $theme .'/css/display.css');
|
||||
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/display.css', null) . '?ts=' . $ts));
|
||||
|
||||
|
||||
$ts = filemtime(INSTALLDIR.'/theme/base/css/facebookapp.css');
|
||||
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => theme_path('css/facebookapp.css', 'base') . '?ts=' . $ts));
|
||||
}
|
||||
|
||||
|
||||
function showScripts()
|
||||
{
|
||||
// Add a timestamp to the file so Facebook cache wont ignore our changes
|
||||
$ts = filemtime(INSTALLDIR.'/js/facebookapp.js');
|
||||
|
||||
|
||||
$this->element('script', array('src' => common_path('js/facebookapp.js') . '?ts=' . $ts));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start an Facebook ready HTML document
|
||||
*
|
||||
@ -138,11 +138,11 @@ class FacebookAction extends Action
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function startHTML($type=null)
|
||||
{
|
||||
function startHTML($type=null)
|
||||
{
|
||||
$this->showStylesheets();
|
||||
$this->showScripts();
|
||||
|
||||
|
||||
$this->elementStart('div', array('class' => 'facebook-page'));
|
||||
}
|
||||
|
||||
@ -177,18 +177,18 @@ class FacebookAction extends Action
|
||||
$this->showFooter();
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
|
||||
function showAside()
|
||||
{
|
||||
}
|
||||
|
||||
function showHead($error, $success)
|
||||
{
|
||||
|
||||
|
||||
if ($error) {
|
||||
$this->element("h1", null, $error);
|
||||
}
|
||||
|
||||
|
||||
if ($success) {
|
||||
$this->element("h1", null, $success);
|
||||
}
|
||||
@ -198,10 +198,10 @@ class FacebookAction extends Action
|
||||
$this->element('fb:add-section-button', array('section' => 'profile'));
|
||||
$this->elementEnd('span');
|
||||
$this->elementEnd('fb:if-section-not-added');
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Make this into a widget later
|
||||
function showLocalNav()
|
||||
{
|
||||
@ -229,8 +229,8 @@ class FacebookAction extends Action
|
||||
$this->elementEnd('li');
|
||||
|
||||
$this->elementEnd('ul');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show header of the page.
|
||||
*
|
||||
@ -245,7 +245,7 @@ class FacebookAction extends Action
|
||||
$this->showNoticeForm();
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show page, a template method.
|
||||
*
|
||||
@ -258,7 +258,7 @@ class FacebookAction extends Action
|
||||
$this->showBody();
|
||||
$this->endHTML();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function showInstructions()
|
||||
{
|
||||
@ -278,7 +278,7 @@ class FacebookAction extends Action
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('register')), _('Register'));
|
||||
$this->text($loginmsg_part2);
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('dd');
|
||||
|
||||
$this->elementEnd('dl');
|
||||
@ -317,7 +317,7 @@ class FacebookAction extends Action
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->submit('submit', _('Login'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
|
||||
$this->elementStart('p');
|
||||
@ -329,73 +329,73 @@ class FacebookAction extends Action
|
||||
$this->elementEnd('div');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function updateProfileBox($notice)
|
||||
{
|
||||
|
||||
// Need to include inline CSS for styling the Profile box
|
||||
|
||||
$app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
|
||||
$icon_url = $app_props['icon_url'];
|
||||
$app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
|
||||
$icon_url = $app_props['icon_url'];
|
||||
|
||||
$style = '<style>
|
||||
.entry-title *,
|
||||
.entry-content * {
|
||||
font-size:14px;
|
||||
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||
}
|
||||
.entry-title a,
|
||||
.entry-content a {
|
||||
color:#002E6E;
|
||||
}
|
||||
.entry-title *,
|
||||
.entry-content * {
|
||||
font-size:14px;
|
||||
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||
}
|
||||
.entry-title a,
|
||||
.entry-content a {
|
||||
color:#002E6E;
|
||||
}
|
||||
|
||||
.entry-title .vcard .photo {
|
||||
float:left;
|
||||
display:inline;
|
||||
margin-right:11px;
|
||||
margin-bottom:11px
|
||||
margin-right:11px;
|
||||
margin-bottom:11px
|
||||
}
|
||||
.entry-title {
|
||||
margin-bottom:11px;
|
||||
}
|
||||
.entry-title {
|
||||
margin-bottom:11px;
|
||||
}
|
||||
.entry-title p.entry-content {
|
||||
display:inline;
|
||||
margin-left:5px;
|
||||
margin-left:5px;
|
||||
}
|
||||
|
||||
div.entry-content {
|
||||
clear:both;
|
||||
}
|
||||
div.entry-content {
|
||||
clear:both;
|
||||
}
|
||||
div.entry-content dl,
|
||||
div.entry-content dt,
|
||||
div.entry-content dd {
|
||||
display:inline;
|
||||
text-transform:lowercase;
|
||||
text-transform:lowercase;
|
||||
}
|
||||
|
||||
div.entry-content dd,
|
||||
div.entry-content .device dt {
|
||||
margin-left:0;
|
||||
margin-right:5px;
|
||||
div.entry-content .device dt {
|
||||
margin-left:0;
|
||||
margin-right:5px;
|
||||
}
|
||||
div.entry-content dl.timestamp dt,
|
||||
div.entry-content dl.response dt {
|
||||
div.entry-content dl.response dt {
|
||||
display:none;
|
||||
}
|
||||
div.entry-content dd a {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
#facebook_laconica_app {
|
||||
text-indent:-9999px;
|
||||
height:16px;
|
||||
width:16px;
|
||||
display:block;
|
||||
background:url('.$icon_url.') no-repeat 0 0;
|
||||
float:right;
|
||||
}
|
||||
</style>';
|
||||
#facebook_laconica_app {
|
||||
text-indent:-9999px;
|
||||
height:16px;
|
||||
width:16px;
|
||||
display:block;
|
||||
background:url('.$icon_url.') no-repeat 0 0;
|
||||
float:right;
|
||||
}
|
||||
</style>';
|
||||
|
||||
$this->xw->openMemory();
|
||||
|
||||
@ -407,12 +407,12 @@ class FacebookAction extends Action
|
||||
|
||||
$fbml_main = "<fb:narrow>$style " . $this->xw->outputMemory(false) . "</fb:narrow>";
|
||||
|
||||
$this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main);
|
||||
$this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main);
|
||||
|
||||
$this->xw->openURI('php://output');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate pagination links
|
||||
*
|
||||
@ -457,24 +457,24 @@ class FacebookAction extends Action
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
|
||||
function updateFacebookStatus($notice)
|
||||
|
||||
function updateFacebookStatus($notice)
|
||||
{
|
||||
$prefix = $this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $this->fbuid);
|
||||
$content = "$prefix $notice->content";
|
||||
|
||||
|
||||
if ($this->facebook->api_client->users_hasAppPermission('status_update', $this->fbuid)) {
|
||||
$this->facebook->api_client->users_setStatus($content, $this->fbuid, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function saveNewNotice()
|
||||
{
|
||||
|
||||
$user = $this->flink->getUser();
|
||||
|
||||
$content = $this->trimmed('status_textarea');
|
||||
|
||||
|
||||
if (!$content) {
|
||||
$this->showPage(_('No notice content!'));
|
||||
return;
|
||||
@ -492,9 +492,9 @@ class FacebookAction extends Action
|
||||
$cmd = $inter->handle_command($user, $content_shortened);
|
||||
|
||||
if ($cmd) {
|
||||
|
||||
|
||||
// XXX fix this
|
||||
|
||||
|
||||
$cmd->execute(new WebChannel());
|
||||
return;
|
||||
}
|
||||
@ -510,20 +510,20 @@ class FacebookAction extends Action
|
||||
}
|
||||
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
|
||||
// Also update the user's Facebook status
|
||||
$this->updateFacebookStatus($notice);
|
||||
$this->updateProfileBox($notice);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FacebookNoticeForm extends NoticeForm
|
||||
class FacebookNoticeForm extends NoticeForm
|
||||
{
|
||||
|
||||
|
||||
var $post_action = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -532,13 +532,13 @@ class FacebookNoticeForm extends NoticeForm
|
||||
* @param string $content content to pre-fill
|
||||
*/
|
||||
|
||||
function __construct($out=null, $action=null, $content=null,
|
||||
function __construct($out=null, $action=null, $content=null,
|
||||
$post_action=null, $user=null)
|
||||
{
|
||||
parent::__construct($out, $action, $content, $user);
|
||||
$this->post_action = $post_action;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
@ -554,7 +554,7 @@ class FacebookNoticeForm extends NoticeForm
|
||||
|
||||
class FacebookNoticeList extends NoticeList
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
@ -565,7 +565,7 @@ class FacebookNoticeList extends NoticeList
|
||||
{
|
||||
parent::__construct($notice, $out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* show the list of notices
|
||||
*
|
||||
@ -619,7 +619,7 @@ class FacebookNoticeList extends NoticeList
|
||||
}
|
||||
|
||||
class FacebookNoticeListItem extends NoticeListItem
|
||||
{
|
||||
{
|
||||
|
||||
/**
|
||||
* constructor
|
||||
@ -646,51 +646,19 @@ class FacebookNoticeListItem extends NoticeListItem
|
||||
function show()
|
||||
{
|
||||
$this->showStart();
|
||||
$this->showNotice();
|
||||
$this->showNoticeInfo();
|
||||
|
||||
$this->out->elementStart('div', 'entry-title');
|
||||
$this->showAuthor();
|
||||
$this->showContent();
|
||||
$this->out->elementEnd('div');
|
||||
|
||||
$this->out->elementStart('div', 'entry-content');
|
||||
$this->showNoticeLink();
|
||||
$this->showNoticeSource();
|
||||
$this->showReplyTo();
|
||||
$this->out->elementEnd('div');
|
||||
// XXX: Need to update to show attachements and controls
|
||||
|
||||
$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
|
||||
{
|
||||
|
||||
{
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
@ -703,36 +671,24 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
||||
{
|
||||
parent::__construct($notice, $out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recipe function for displaying a single notice in the
|
||||
* Facebook App's Profile
|
||||
* Recipe function for displaying a single notice in the
|
||||
* Facebook App profile notice box
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function show()
|
||||
{
|
||||
|
||||
$this->out->elementStart('div', 'entry-title');
|
||||
$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->showNotice();
|
||||
$this->showNoticeInfo();
|
||||
$this->showAppLink();
|
||||
|
||||
}
|
||||
|
||||
function showAppLink()
|
||||
function showAppLink()
|
||||
{
|
||||
|
||||
|
||||
$this->facebook = getFacebook();
|
||||
|
||||
$app_props = $this->facebook->api_client->Admin_getAppProperties(
|
||||
@ -740,7 +696,7 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem
|
||||
|
||||
$this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name'];
|
||||
$this->app_name = $app_props['application_name'];
|
||||
|
||||
|
||||
$this->out->elementStart('a', array('id' => 'facebook_laconica_app',
|
||||
'href' => $this->app_uri));
|
||||
$this->out->text($this->app_name);
|
||||
|
16
lib/form.php
16
lib/form.php
@ -52,6 +52,8 @@ require_once INSTALLDIR.'/lib/widget.php';
|
||||
|
||||
class Form extends Widget
|
||||
{
|
||||
var $enctype = null;
|
||||
|
||||
/**
|
||||
* Show the form
|
||||
*
|
||||
@ -63,11 +65,15 @@ class Form extends Widget
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->out->elementStart('form',
|
||||
array('id' => $this->id(),
|
||||
'class' => $this->formClass(),
|
||||
'method' => 'post',
|
||||
'action' => $this->action()));
|
||||
$attributes = array('id' => $this->id(),
|
||||
'class' => $this->formClass(),
|
||||
'method' => 'post',
|
||||
'action' => $this->action());
|
||||
|
||||
if (!empty($this->enctype)) {
|
||||
$attributes['enctype'] = $this->enctype;
|
||||
}
|
||||
$this->out->elementStart('form', $attributes);
|
||||
$this->out->elementStart('fieldset');
|
||||
$this->formLegend();
|
||||
$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';
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,8 @@ class NoticeForm extends Form
|
||||
} else {
|
||||
$this->user = common_current_user();
|
||||
}
|
||||
|
||||
|
||||
$this->enctype = 'multipart/form-data';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,17 +143,21 @@ class NoticeForm extends Form
|
||||
'rows' => 4,
|
||||
'name' => 'status_textarea'),
|
||||
($this->content) ? $this->content : '');
|
||||
|
||||
$this->out->elementStart('dl', 'form_note');
|
||||
$this->out->element('dt', null, _('Available characters'));
|
||||
$this->out->element('dd', array('id' => 'notice_text-count'),
|
||||
'140');
|
||||
$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) {
|
||||
$this->out->hidden('notice_return-to', $this->action, 'returnto');
|
||||
}
|
||||
$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/disfavorform.php';
|
||||
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
||||
|
||||
/**
|
||||
* 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->element('h2', null, _('Notices'));
|
||||
$this->out->elementStart('ul', array('class' => 'notices'));
|
||||
$this->out->elementStart('ol', array('class' => 'notices xoxo'));
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
@ -100,7 +101,7 @@ class NoticeList extends Widget
|
||||
$item->show();
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('ol');
|
||||
$this->out->elementEnd('div');
|
||||
|
||||
return $cnt;
|
||||
@ -180,86 +181,49 @@ class NoticeListItem extends Widget
|
||||
$this->showStart();
|
||||
$this->showNotice();
|
||||
$this->showNoticeAttachments();
|
||||
$this->showNoticeOptions();
|
||||
$this->showNoticeInfo();
|
||||
$this->showNoticeOptions();
|
||||
$this->showEnd();
|
||||
}
|
||||
|
||||
function showNotice()
|
||||
{
|
||||
if(0)
|
||||
$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->out->elementStart('div', 'entry-title');
|
||||
$this->showAuthor();
|
||||
$this->showContent();
|
||||
$this->out->elementEnd('div');
|
||||
}
|
||||
|
||||
function showNoticeAttachments()
|
||||
{
|
||||
$f2p = new File_to_post;
|
||||
$f2p->post_id = $this->notice->id;
|
||||
$file = new File;
|
||||
$file->joinAdd($f2p);
|
||||
$file->selectAdd();
|
||||
$file->selectAdd('file.id as id');
|
||||
$count = $file->find(true);
|
||||
if (!$count) return;
|
||||
if (1 === $count) {
|
||||
$href = common_local_url('attachment', array('attachment' => $file->id));
|
||||
$att_class = 'attachment';
|
||||
} else {
|
||||
$href = common_local_url('attachments', array('notice' => $this->notice->id));
|
||||
$att_class = 'attachments';
|
||||
function showNoticeAttachments() {
|
||||
if ($this->isUsedInList()) {
|
||||
return;
|
||||
}
|
||||
$al = new AttachmentList($this->notice, $this->out);
|
||||
$al->show();
|
||||
}
|
||||
|
||||
$clip = theme_path('images/icons/clip', 'base');
|
||||
if ('shownotice' === $this->out->args['action']) {
|
||||
$height = '96px';
|
||||
$width = '83%';
|
||||
$width_att = '15%';
|
||||
$clip .= '-big.png';
|
||||
$top = '70px';
|
||||
} else {
|
||||
$height = '48px';
|
||||
$width = '90%';
|
||||
$width_att = '8%';
|
||||
$clip .= '.png';
|
||||
$top = '20px';
|
||||
}
|
||||
if(0)
|
||||
$this->out->elementStart('div', 'entry-attachments');
|
||||
else
|
||||
$this->out->elementStart('p', array('class' => 'entry-attachments', 'style' => "float: right; width: $width_att; background: url($clip) no-repeat; text-align: right; height: $height;"));
|
||||
$this->out->element('a', array('class' => $att_class, 'style' => "text-decoration: none; padding-top: $top; display: block; height: $height;", 'href' => $href, 'title' => "# of attachments: $count"), $count === 1 ? '' : $count);
|
||||
function isUsedInList() {
|
||||
return 'shownotice' !== $this->out->args['action'];
|
||||
}
|
||||
|
||||
/*
|
||||
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()
|
||||
{
|
||||
if(0)
|
||||
$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->showWithAttachment();
|
||||
$this->showNoticeSource();
|
||||
$this->showContext();
|
||||
$this->out->elementEnd('div');
|
||||
@ -269,10 +233,7 @@ else
|
||||
{
|
||||
$user = common_current_user();
|
||||
if ($user) {
|
||||
if(0)
|
||||
$this->out->elementStart('div', 'notice-options');
|
||||
else
|
||||
$this->out->elementStart('div', array('class' => 'notice-options', 'style' => 'float: right; width: 16%;'));
|
||||
$this->showFaveForm();
|
||||
$this->showReplyLink();
|
||||
$this->showDeleteLink();
|
||||
@ -403,6 +364,10 @@ else
|
||||
// versions (>> 0.4.x)
|
||||
$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');
|
||||
}
|
||||
|
||||
@ -433,6 +398,7 @@ else
|
||||
$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');
|
||||
|
@ -52,12 +52,12 @@ class NoticeSection extends Section
|
||||
{
|
||||
$notices = $this->getNotices();
|
||||
$cnt = 0;
|
||||
$this->out->elementStart('ul', 'notices');
|
||||
$this->out->elementStart('ol', 'notices xoxo');
|
||||
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
|
||||
$this->showNotice($notices);
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('ol');
|
||||
return ($cnt > NOTICES_PER_SECTION);
|
||||
}
|
||||
|
||||
|
@ -153,24 +153,21 @@ class Router
|
||||
|
||||
$m->connect('attachment/:attachment/ajax',
|
||||
array('action' => 'attachment_ajax'),
|
||||
array('notice' => '[0-9]+'));
|
||||
array('attachment' => '[0-9]+'));
|
||||
|
||||
$m->connect('attachment/:attachment',
|
||||
array('action' => 'attachment'),
|
||||
array('notice' => '[0-9]+'));
|
||||
|
||||
// notice
|
||||
$m->connect('attachment/:attachment/thumbnail',
|
||||
array('action' => 'attachment_thumbnail'),
|
||||
array('attachment' => '[0-9]+'));
|
||||
|
||||
$m->connect('notice/new', array('action' => 'newnotice'));
|
||||
$m->connect('notice/new?replyto=:replyto',
|
||||
array('action' => 'newnotice'),
|
||||
array('replyto' => '[A-Za-z0-9_-]+'));
|
||||
$m->connect('notice/:notice/attachments/ajax',
|
||||
array('action' => 'attachments_ajax'),
|
||||
array('notice' => '[0-9]+'));
|
||||
$m->connect('notice/:notice/attachments',
|
||||
array('action' => 'attachments'),
|
||||
array('notice' => '[0-9]+'));
|
||||
|
||||
$m->connect('notice/:notice/file',
|
||||
array('action' => 'file'),
|
||||
array('notice' => '[0-9]+'));
|
||||
|
||||
$m->connect('notice/:notice',
|
||||
array('action' => 'shownotice'),
|
||||
array('notice' => '[0-9]+'));
|
||||
|
@ -51,7 +51,7 @@ class SearchAction extends Action
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
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');
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
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
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
@ -18,354 +15,53 @@
|
||||
*
|
||||
* 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/FBConnectLogin.php';
|
||||
require_once INSTALLDIR . '/lib/facebookutil.php';
|
||||
if (!defined('LACONICA')) {
|
||||
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)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (common_is_real_login()) {
|
||||
$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()
|
||||
{
|
||||
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')));
|
||||
}
|
||||
$instr = $this->getInstructions();
|
||||
$output = common_markup_to_html($instr);
|
||||
$this->elementStart('div', 'instructions');
|
||||
$this->raw($output);
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Facebook Account Setup');
|
||||
return _('Facebook Login');
|
||||
}
|
||||
|
||||
function showForm($error=null, $username=null)
|
||||
{
|
||||
$this->error = $error;
|
||||
$this->username = $username;
|
||||
function showContent() {
|
||||
|
||||
$this->showPage();
|
||||
}
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('fb:login-button', array('onlogin' => 'goto_login()',
|
||||
'length' => 'long'));
|
||||
|
||||
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' => '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;
|
||||
}
|
||||
$this->elementEnd('fieldset');
|
||||
}
|
||||
|
||||
}
|
||||
|
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);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectLogin.php';
|
||||
define("FACEBOOK_CONNECT_SERVICE", 3);
|
||||
|
||||
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
|
||||
@ -46,7 +53,6 @@ require_once INSTALLDIR . '/lib/facebookutil.php';
|
||||
|
||||
class FBConnectPlugin extends Plugin
|
||||
{
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
@ -54,91 +60,91 @@ class FBConnectPlugin extends Plugin
|
||||
|
||||
// Hook in new actions
|
||||
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
|
||||
function onStartShowHTML($action)
|
||||
{
|
||||
|
||||
// XXX: This is probably a bad place to do general processing
|
||||
// so maybe I need to make some new events? Maybe in
|
||||
// Action::prepare?
|
||||
|
||||
$name = get_class($action);
|
||||
|
||||
// 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);
|
||||
// XXX: Horrible hack to make Safari, FF2, and Chrome work with
|
||||
// Facebook Connect. These browser cannot use Facebook's
|
||||
// DOM parsing routines unless the mime type of the page is
|
||||
// text/html even though Facebook Connect uses XHTML. This is
|
||||
// A bug in Facebook Connect, and this is a temporary solution
|
||||
// until they fix their JavaScript libs.
|
||||
header('Content-Type: text/html');
|
||||
|
||||
$action->extraHeaders();
|
||||
|
||||
$action->startXML('html',
|
||||
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
||||
'-//W3C//DTD XHTML 1.0 Strict//EN',
|
||||
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
|
||||
|
||||
$language = $action->getLanguage();
|
||||
|
||||
$action->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
|
||||
'xmlns:fb' => 'http://www.facebook.com/2008/fbml',
|
||||
'xml:lang' => $language,
|
||||
'lang' => $language));
|
||||
$action->elementStart('html',
|
||||
array('xmlns' => 'http://www.w3.org/1999/xhtml',
|
||||
'xmlns:fb' => 'http://www.facebook.com/2008/fbml',
|
||||
'xml:lang' => $language,
|
||||
'lang' => $language));
|
||||
|
||||
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',
|
||||
array('type' => 'text/javascript',
|
||||
'src' => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
|
||||
' ');
|
||||
'');
|
||||
}
|
||||
|
||||
$apikey = common_config('facebook', 'apikey');
|
||||
$plugin_path = common_path('plugins/FBConnect');
|
||||
|
||||
$url = common_get_returnto();
|
||||
|
||||
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 onEndShowLaconicaStyles($action)
|
||||
{
|
||||
$action->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => common_path('plugins/FBConnect/FBConnectPlugin.css')));
|
||||
}
|
||||
|
||||
function onStartPrimaryNav($action)
|
||||
@ -146,114 +152,148 @@ class FBConnectPlugin extends Plugin
|
||||
$user = common_current_user();
|
||||
|
||||
if ($user) {
|
||||
$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');
|
||||
|
||||
$flink = Foreign_link::getByUserId($user->id,
|
||||
FACEBOOK_CONNECT_SERVICE);
|
||||
$fbuid = 0;
|
||||
|
||||
if ($flink) {
|
||||
|
||||
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 {
|
||||
$action->menuItem(common_local_url('smssettings'),
|
||||
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
|
||||
$action->menuItem(common_local_url('logout'),
|
||||
_('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 {
|
||||
if (!common_config('site', 'closed')) {
|
||||
$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'),
|
||||
_('OpenID'), _('Login with OpenID'), false, 'nav_openid');
|
||||
_('OpenID'), _('Login with OpenID'), false, 'nav_openid');
|
||||
$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')),
|
||||
_('Help'), _('Help me!'), false, 'nav_help');
|
||||
_('Help'), _('Help me!'), false, 'nav_help');
|
||||
$action->menuItem(common_local_url('peoplesearch'),
|
||||
_('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');
|
||||
}
|
||||
_('Search'), _('Search for people or text'), false, 'nav_search');
|
||||
|
||||
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();
|
||||
|
||||
if ($user) {
|
||||
return;
|
||||
}
|
||||
$flink = Foreign_link::getByUserId($user->id, FACEBOOK_CONNECT_SERVICE);
|
||||
|
||||
try {
|
||||
$action->logout();
|
||||
|
||||
if ($flink) {
|
||||
|
||||
$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
|
||||
// redirect to Facebook connect login page because that means you have clicked
|
||||
// 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.");
|
||||
if ($fbuid > 0) {
|
||||
$facebook->logout(common_local_url('public'));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
common_debug('Expired FB session.');
|
||||
} catch (Exception $e) {
|
||||
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;
|
||||
}
|
||||
|
||||
foreach ($timeline as $status) {
|
||||
// Reverse to preserve order
|
||||
foreach (array_reverse($timeline) as $status) {
|
||||
|
||||
// Hacktastic: filter out stuff coming from this Laconica
|
||||
$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 {
|
||||
margin-left:29px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#form_search .submit {
|
||||
@ -450,6 +452,21 @@ 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 {
|
||||
display:none;
|
||||
}
|
||||
@ -740,12 +757,14 @@ border-top-style:dotted;
|
||||
.notices li {
|
||||
list-style-type:none;
|
||||
}
|
||||
.notices li.hover {
|
||||
border-radius:4px;
|
||||
-moz-border-radius:4px;
|
||||
-webkit-border-radius:4px;
|
||||
.notices .notices {
|
||||
margin-top:7px;
|
||||
margin-left:5%;
|
||||
width:95%;
|
||||
float:left;
|
||||
}
|
||||
|
||||
|
||||
/* NOTICES */
|
||||
#notices_primary {
|
||||
float:left;
|
||||
@ -794,6 +813,9 @@ float:left;
|
||||
width:100%;
|
||||
overflow:hidden;
|
||||
}
|
||||
.notice .entry-title.ov {
|
||||
overflow:visible;
|
||||
}
|
||||
#shownotice .notice .entry-title {
|
||||
font-size:2.2em;
|
||||
}
|
||||
@ -818,7 +840,7 @@ clear:left;
|
||||
float:left;
|
||||
font-size:0.95em;
|
||||
margin-left:59px;
|
||||
width:65%;
|
||||
width:60%;
|
||||
}
|
||||
#showstream .notice div.entry-content,
|
||||
#shownotice .notice div.entry-content {
|
||||
@ -848,15 +870,12 @@ display:inline-block;
|
||||
text-transform:lowercase;
|
||||
}
|
||||
|
||||
|
||||
.notice-options {
|
||||
padding-left:2%;
|
||||
float:left;
|
||||
width:50%;
|
||||
position:relative;
|
||||
font-size:0.95em;
|
||||
width:12.5%;
|
||||
width:90px;
|
||||
float:right;
|
||||
margin-right:11px;
|
||||
}
|
||||
|
||||
.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 {
|
||||
float: left;
|
||||
margin-right: 2em;
|
||||
@ -1040,8 +1128,6 @@ margin-left:18px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* TOP_POSTERS */
|
||||
.section tbody td {
|
||||
padding-right:18px;
|
||||
@ -1166,6 +1252,7 @@ width:33%;
|
||||
}
|
||||
#settings_design_color .form_data label {
|
||||
float:none;
|
||||
display:block;
|
||||
}
|
||||
#settings_design_color .form_data .swatch {
|
||||
padding:11px;
|
||||
|
@ -1,6 +1,3 @@
|
||||
@import url("display.css");
|
||||
@import url("../../identica/css/display.css");
|
||||
|
||||
* {
|
||||
font-size:14px;
|
||||
font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
|
||||
|
@ -30,3 +30,12 @@ margin-right:4px;
|
||||
.entity_profile {
|
||||
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 {
|
||||
margin-left:29px;
|
||||
.form_settings input.form_action-primary {
|
||||
padding:0;
|
||||
}
|
||||
.form_settings input.form_action-secondary {
|
||||
margin-left:29px;
|
||||
}
|
||||
|
||||
|
||||
#form_search .submit {
|
||||
margin-left:11px;
|
||||
@ -443,6 +446,27 @@ float:left;
|
||||
font-size:1.3em;
|
||||
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 {
|
||||
display:none;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ border-color:#aaa;
|
||||
border-color:#ddd;
|
||||
}
|
||||
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
background:none;
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ div.notice-options input,
|
||||
.entity_send-a-message a,
|
||||
.form_user_nudge input.submit,
|
||||
.entity_nudge p,
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
color:#002E6E;
|
||||
}
|
||||
|
||||
@ -102,6 +102,13 @@ color:#333;
|
||||
#form_notice.warning #notice_text-count {
|
||||
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 {
|
||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||
cursor:wait;
|
||||
|
@ -199,9 +199,11 @@ padding:0 7px;
|
||||
}
|
||||
|
||||
|
||||
.form_settings input.form_action-primary {
|
||||
padding:0;
|
||||
}
|
||||
.form_settings input.form_action-secondary {
|
||||
margin-left:29px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#form_search .submit {
|
||||
@ -1267,7 +1269,7 @@ border-color:#aaa;
|
||||
border-color:#ddd;
|
||||
}
|
||||
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
background:none;
|
||||
}
|
||||
|
||||
@ -1296,7 +1298,7 @@ div.notice-options input,
|
||||
.entity_send-a-message a,
|
||||
.form_user_nudge input.submit,
|
||||
.entity_nudge p,
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
color:#0084B4;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ border-color:#aaa;
|
||||
border-color:#C3D6DF;
|
||||
}
|
||||
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
background:none;
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ div.notice-options input,
|
||||
.entity_send-a-message a,
|
||||
.form_user_nudge input.submit,
|
||||
.entity_nudge p,
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
color:#002E6E;
|
||||
}
|
||||
|
||||
@ -82,6 +82,13 @@ color:#333;
|
||||
#form_notice.warning #notice_text-count {
|
||||
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 {
|
||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||
cursor:wait;
|
||||
@ -175,10 +182,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
|
||||
}
|
||||
|
||||
/* NOTICES */
|
||||
.notices li.over {
|
||||
background-color:#fcfcfc;
|
||||
.notice .attachment {
|
||||
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 form input.submit {
|
||||
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.notice-options {
|
||||
.notices div.notice-options,
|
||||
.notices li.hover .notices div.entry-content,
|
||||
.notices li.hover .notices div.notice-options {
|
||||
opacity:0.4;
|
||||
}
|
||||
.notices li.hover div.entry-content,
|
||||
@ -214,6 +225,19 @@ font-family:sans-serif;
|
||||
.notices li.hover {
|
||||
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 */
|
||||
|
||||
#new_group a {
|
||||
|
@ -189,9 +189,11 @@ padding:0 7px;
|
||||
}
|
||||
|
||||
|
||||
.form_settings input.form_action-primary {
|
||||
padding:0;
|
||||
}
|
||||
.form_settings input.form_action-secondary {
|
||||
margin-left:29px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#form_search .submit {
|
||||
|
@ -38,7 +38,7 @@ color:#ccc;
|
||||
border-color:#ddd;
|
||||
}
|
||||
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
background:none;
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ div.notice-options input,
|
||||
.entity_send-a-message a,
|
||||
.form_user_nudge input.submit,
|
||||
.entity_nudge p,
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
color:#0f0;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ border-color:#aaa;
|
||||
border-color:#ddd;
|
||||
}
|
||||
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
background:none;
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ div.notice-options input,
|
||||
.entity_send-a-message a,
|
||||
.form_user_nudge input.submit,
|
||||
.entity_nudge p,
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
color:#002E6E;
|
||||
}
|
||||
|
||||
@ -82,6 +82,13 @@ color:#333;
|
||||
#form_notice.warning #notice_text-count {
|
||||
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 {
|
||||
background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
|
||||
cursor:wait;
|
||||
@ -175,10 +182,12 @@ background-image:url(../../base/images/icons/twotone/green/shield.gif);
|
||||
}
|
||||
|
||||
/* NOTICES */
|
||||
.notices li.over {
|
||||
background-color:#fcfcfc;
|
||||
.notice .attachment {
|
||||
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 form input.submit {
|
||||
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.notice-options {
|
||||
.notices div.notice-options,
|
||||
.notices li.hover .notices div.entry-content,
|
||||
.notices li.hover .notices div.notice-options {
|
||||
opacity:0.4;
|
||||
}
|
||||
.notices li.hover div.entry-content,
|
||||
@ -214,6 +225,19 @@ font-family:sans-serif;
|
||||
.notices li.hover {
|
||||
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 */
|
||||
|
||||
#new_group a {
|
||||
|
@ -198,9 +198,11 @@ padding:0 7px;
|
||||
}
|
||||
|
||||
|
||||
.form_settings input.form_action-primary {
|
||||
padding:0;
|
||||
}
|
||||
.form_settings input.form_action-secondary {
|
||||
margin-left:29px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#form_search .submit {
|
||||
|
@ -37,7 +37,7 @@ border-color:#aaa;
|
||||
border-color:#ddd;
|
||||
}
|
||||
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
background:none;
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ div.notice-options input,
|
||||
.entity_send-a-message a,
|
||||
.form_user_nudge input.submit,
|
||||
.entity_nudge p,
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
color:#8F0000;
|
||||
}
|
||||
|
||||
|
@ -199,9 +199,11 @@ padding:0 7px;
|
||||
}
|
||||
|
||||
|
||||
.form_settings input.form_action-primary {
|
||||
padding:0;
|
||||
}
|
||||
.form_settings input.form_action-secondary {
|
||||
margin-left:29px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#form_search .submit {
|
||||
|
@ -36,7 +36,7 @@ border-color:#aaa;
|
||||
border-color:#ddd;
|
||||
}
|
||||
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
background:none;
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ div.notice-options input,
|
||||
.entity_send-a-message a,
|
||||
.form_user_nudge input.submit,
|
||||
.entity_nudge p,
|
||||
.form_settings input.form_action-secondary {
|
||||
.form_settings input.form_action-primary {
|
||||
color:#000;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user