forked from GNUsocial/gnu-social
Merge commit 'origin/0.9.x' into 0.9.x
This commit is contained in:
commit
f4459dfedc
209
README
209
README
@ -2,8 +2,8 @@
|
|||||||
README
|
README
|
||||||
------
|
------
|
||||||
|
|
||||||
StatusNet 0.8.2 ("Life and How to Live It")
|
StatusNet 0.9.0 ("Stand") Release Candidate 2
|
||||||
1 Nov 2009
|
22 Dec 2009
|
||||||
|
|
||||||
This is the README file for StatusNet (formerly Laconica), the Open
|
This is the README file for StatusNet (formerly Laconica), the Open
|
||||||
Source microblogging platform. It includes installation instructions,
|
Source microblogging platform. It includes installation instructions,
|
||||||
@ -16,10 +16,10 @@ About
|
|||||||
|
|
||||||
StatusNet (formerly Laconica) is a Free and Open Source microblogging
|
StatusNet (formerly Laconica) is a Free and Open Source microblogging
|
||||||
platform. It helps people in a community, company or group to exchange
|
platform. It helps people in a community, company or group to exchange
|
||||||
short (140 character) messages over the Web. Users can choose which
|
short (140 characters, by default) messages over the Web. Users can
|
||||||
people to "follow" and receive only their friends' or colleagues'
|
choose which people to "follow" and receive only their friends' or
|
||||||
status messages. It provides a similar service to sites like Twitter,
|
colleagues' status messages. It provides a similar service to sites
|
||||||
Jaiku, Yammer, and Plurk.
|
like Twitter, Jaiku, Yammer, and Plurk.
|
||||||
|
|
||||||
With a little work, status messages can be sent to mobile phones,
|
With a little work, status messages can be sent to mobile phones,
|
||||||
instant messenger programs (GTalk/Jabber), and specially-designed
|
instant messenger programs (GTalk/Jabber), and specially-designed
|
||||||
@ -77,81 +77,96 @@ for additional terms.
|
|||||||
New this version
|
New this version
|
||||||
================
|
================
|
||||||
|
|
||||||
This is a minor feature and bugfix release since version 0.8.1,
|
This is a major feature release since version 0.8.2, released Nov 1 2009.
|
||||||
released Aug 26 2009. Notable changes this version:
|
Notable changes this version:
|
||||||
|
|
||||||
- New script for deleting user accounts. Not particularly safe or
|
- Records of deleted notices are stored without the notice content.
|
||||||
community-friendly. Better for deleting abusive accounts than for
|
- Much of the optional core featureset has been moved to plugins.
|
||||||
users who are 'retiring'.
|
- OpenID support moved from core to a plugin. Helps test the strength of
|
||||||
- Improved detection of URLs in notices, specifically for punctuation
|
our plugin architecture and makes it easy to disable this
|
||||||
chars like ~, :, $, _, -, +, !, @, and %.
|
functionality for e.g. intranet sites.
|
||||||
- Removed some extra <dl> semantic HTML code.
|
- Many additional hook events (see EVENTS.txt for details).
|
||||||
- Correct error in status-network database ini file (having multiple
|
- OMB 0.1 support re-implemented using libomb.
|
||||||
statusnet sites with a single codebase)
|
- Re-structure database so notices, messages, bios and group
|
||||||
- Fixed error output for Twitter posting failures.
|
descriptions can be over 140 characters. Limit defined by
|
||||||
- Fixed bug in Twitter queue handler that requeued inapplicable
|
site administrator as configuration option; can be unlimited.
|
||||||
notices ad infinitum.
|
- Configuration data now optionally stored in the database, which
|
||||||
- Improve FOAF output for remote users.
|
overrides any settings in config files.
|
||||||
- new commands to join and leave groups.
|
- Twitter integration re-implemented as a plugin.
|
||||||
- Fixed bug in which you cannot turn off importing friends timelines
|
- Facebook integration re-implemented as a plugin.
|
||||||
flag.
|
- Role-based authorization framework. Users can have named roles, and
|
||||||
- Better error handling in Twitter posting.
|
roles can have rights (e.g., to delete notices, change configuration
|
||||||
- Show oEmbed data for XHTML files as well as plain HTML.
|
data, or ban uncooperative users). Default roles 'admin' (for
|
||||||
- Updated bug database link in README.
|
configuration) and 'moderator' (for community management) added.
|
||||||
- add support for HTTP Basic Auth in PHP CGI or FastCGI (e.g. GoDaddy).
|
- Plugin for PubSubHubBub (PuSH) support.
|
||||||
- autofocus input to selected entry elements depending on page.
|
- Considerable code style cleanup to meet PEAR code standards.
|
||||||
- updated layout for filter-by-tag form.
|
- Made a common library for HTTP-client access which uses available
|
||||||
- better layout for inbox and outbox pages.
|
HTTP libraries where possible.
|
||||||
- fix highlighting search terms in attributes of notice list elements.
|
- Added statuses/home_timeline method to API.
|
||||||
- Correctly handle errors in linkback plugin.
|
- Hooks for plugins to handle notices offline, either by defining
|
||||||
- Updated biz theme.
|
their own queue handler scripts or to use a default plugin queue
|
||||||
- Updated cloudy theme.
|
handler script.
|
||||||
- Don't match '::' as an IPv6 address.
|
- Plugins can now modify the database schema, adding their own tables
|
||||||
- Use the same decision logic for deciding whether to mark an
|
or modifying existing ones.
|
||||||
attachment as an enclosure in RSS or as a paperclip item in Web
|
- Groups API.
|
||||||
output.
|
- Twitter API supports Web caching for some methods.
|
||||||
- Fixed a bug in the Piwik plugin that hard-coded the site ID.
|
- Twitter API refactored into one-action-per-method.
|
||||||
- Add a param, inreplyto, to notice/new to allow an explicit response
|
- Realtime plugin supports a tear-off window.
|
||||||
to another notice.
|
- FOAF for groups.
|
||||||
- Show username in subject of emails.
|
- Moved all JavaScript tags to just before </body> by default,
|
||||||
- Check if avatar exists before trying to delete it.
|
significantly speeding up apparent page load time.
|
||||||
- Correctly add omb_version to response for request token in OMB.
|
- Added a Realtime plugin for Orbited server.
|
||||||
- Add a few more SMS carriers.
|
- Added a mobile plugin to give a more mobile-phone-friendly layout
|
||||||
- Add a few more notice sources.
|
when a mobile browser is detected.
|
||||||
- Vary: header.
|
- Use CSS sprites for most common icons.
|
||||||
- Improvements to the AutoCompletePlugin.
|
- Fixes for images and buttons on Web output.
|
||||||
- Check for 'dl' before using it.
|
- New plugin requires that users validate their email before posting.
|
||||||
- Make it impossible to delete self-subscriptions via the API.
|
- New plugin UserFlag lets users flag other profiles for review.
|
||||||
- Fix pagination of tagged user pages.
|
- Considerably better i18n support. Use TranslateWiki to update
|
||||||
- Make PiwikAnalyticsPlugin work with addPlugin().
|
translations.
|
||||||
- Removed trailing single space in user nicknames in notice lists.
|
- Notices and profiles now store location information.
|
||||||
- Show context link if a notice starts a conversation.
|
- New plugin, Geonames, for turning location names and lat/long pairs
|
||||||
- blacklist all files and directories in install dir.
|
into structured IDs and vice versa. Architecture reusable for other
|
||||||
- handle GoDaddy-style PATH_INFO, including script name.
|
systems.
|
||||||
- add home_timeline synonym for friends_timeline.
|
- Better check of license compatibility between site licenses.
|
||||||
- Add a popup window for the realtime plugin.
|
- Some improvements in XMPP output.
|
||||||
- Add some more streams for the realtime plugin.
|
- Media upload in the API.
|
||||||
- Fix a bug that overwrote group creation timestamp on every edit.
|
- Replies appear in the user's inbox.
|
||||||
- Moved HTTP error code strings to a class variable.
|
- Improved the UI on the bookmarklet.
|
||||||
- The Twitter API now returns server errors in the correct format.
|
- StatusNet identities can be used as OpenID identities.
|
||||||
- Reset the doctype for HTML output.
|
- Script to register a user.
|
||||||
- Fixed a number of notices.
|
- Script to make someone a group admin.
|
||||||
- Don't show search suggestions for private sites.
|
- Script to make someone a site admin or moderator.
|
||||||
- Some corrections to FBConnect nav overrides.
|
- 'login' command.
|
||||||
- Slightly less database-intensive session management.
|
- Pluggable authentication.
|
||||||
- Updated name of software in installer script.
|
- LDAP authentication plugin.
|
||||||
- Include long-form attachment URLs if url-shortener is disabled.
|
- Script for console interaction with the site (!).
|
||||||
- Include updated localisations for Polish, Greek, Hebrew, Icelandic,
|
- Users don't see group posts from people they've blocked.
|
||||||
Norwegian, and Chinese.
|
- Admin panel interface for changing site configuration.
|
||||||
- Include upstream fixes to gettext.php.
|
- Users can be sandboxed (limited contributions) or silenced
|
||||||
- Correct for regression in Facebook API for updates.
|
(no contributions) by moderators.
|
||||||
- Ignore "Sent from my iPhone" (and similar) in mail updates.
|
- Many changes to make language usage more consistent.
|
||||||
- Use the NICKNAME_FMT constant for detecting nicknames.
|
- Sphinx search moved to a plugin.
|
||||||
- Check for site servername config'd.
|
- GeoURL plugin.
|
||||||
- Compatibility fix for empty status updates with Twitter API.
|
- Profile and group lists support hAtom.
|
||||||
- Option to show files privately (EXPERIMENTAL! Use with caution.)
|
- Massive refactoring of util.js.
|
||||||
- a script to register a new user.
|
- Mapstraction plugin to show maps on inbox and profile pages.
|
||||||
- a script to make a user admin of a group.
|
- Play/pause buttons for realtime notices.
|
||||||
|
- Support for geo microformat.
|
||||||
|
- Partial support for feed subscriptions, RSSCloud, PubSubHubBub.
|
||||||
|
- Support for geolocation in browser (Chrome, Firefox).
|
||||||
|
- Quit trying to negotiate HTML format. Always use text/html.
|
||||||
|
We lose, and so do Web standards. Boo.
|
||||||
|
- Better logging of request info.
|
||||||
|
- Better output for errors in Web interface.
|
||||||
|
- No longer store .mo files; these need to be generated.
|
||||||
|
- Minify plugin.
|
||||||
|
- Events to allow pluginizing logger.
|
||||||
|
- New framework for plugin localization.
|
||||||
|
- Gravatar plugin.
|
||||||
|
- Add support for "repeats" (similar to Twitter's "retweets").
|
||||||
|
- Support for repeats in Twitter API.
|
||||||
|
- Better notification of direct messages.
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
=============
|
=============
|
||||||
@ -358,7 +373,7 @@ It's possible to configure the software so it looks like this instead:
|
|||||||
|
|
||||||
These "fancy URLs" are more readable and memorable for users. To use
|
These "fancy URLs" are more readable and memorable for users. To use
|
||||||
fancy URLs, you must either have Apache 2.x with .htaccess enabled and
|
fancy URLs, you must either have Apache 2.x with .htaccess enabled and
|
||||||
mod_redirect enabled, -OR- know how to configure "url redirection" in
|
mod_rewrite enabled, -OR- know how to configure "url redirection" in
|
||||||
your server.
|
your server.
|
||||||
|
|
||||||
1. Copy the htaccess.sample file to .htaccess in your StatusNet
|
1. Copy the htaccess.sample file to .htaccess in your StatusNet
|
||||||
@ -384,6 +399,18 @@ like:
|
|||||||
If you changed your HTTP server configuration, you may need to restart
|
If you changed your HTTP server configuration, you may need to restart
|
||||||
the server first.
|
the server first.
|
||||||
|
|
||||||
|
If it doesn't work, double-check that AllowOverride for the StatusNet
|
||||||
|
directory is 'All' in your Apache configuration file. This is usually
|
||||||
|
/etc/httpd.conf, /etc/apache/httpd.conf, or (on Debian and Ubuntu)
|
||||||
|
/etc/apache2/sites-available/default. See the Apache documentation for
|
||||||
|
.htaccess files for more details:
|
||||||
|
|
||||||
|
http://httpd.apache.org/docs/2.2/howto/htaccess.html
|
||||||
|
|
||||||
|
Also, check that mod_rewrite is installed and enabled:
|
||||||
|
|
||||||
|
http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html
|
||||||
|
|
||||||
Sphinx
|
Sphinx
|
||||||
------
|
------
|
||||||
|
|
||||||
@ -685,13 +712,9 @@ to users on a remote site. (Or not... it's not well tested.) The
|
|||||||
|
|
||||||
If fancy URLs is enabled, access to file attachments can also be
|
If fancy URLs is enabled, access to file attachments can also be
|
||||||
restricted to logged-in users only. Uncomment the appropriate rewrite
|
restricted to logged-in users only. Uncomment the appropriate rewrite
|
||||||
<<<<<<< HEAD:README
|
|
||||||
rule in .htaccess or your server's httpd.conf. (This most likely will
|
rule in .htaccess or your server's httpd.conf. (This most likely will
|
||||||
not work if you are using a virtual server for attachments, so consider
|
not work if you are using a virtual server for attachments, so consider
|
||||||
the performance/security tradeoff.)
|
the performance/security tradeoff.)
|
||||||
=======
|
|
||||||
rule in .htaccess or your server's httpd.conf.
|
|
||||||
>>>>>>> 446de62... Revert "Added some explanatory text to README":README
|
|
||||||
|
|
||||||
Upgrading
|
Upgrading
|
||||||
=========
|
=========
|
||||||
@ -1407,6 +1430,21 @@ contentlimit: max length of the plain-text content of a message.
|
|||||||
Default is null, meaning to use the site-wide text limit.
|
Default is null, meaning to use the site-wide text limit.
|
||||||
0 means no limit.
|
0 means no limit.
|
||||||
|
|
||||||
|
logincommand
|
||||||
|
------------
|
||||||
|
|
||||||
|
Configuration options for the login command.
|
||||||
|
|
||||||
|
disabled: whether to enable this command. If enabled, users who send
|
||||||
|
the text 'login' to the site through any channel will
|
||||||
|
receive a link to login to the site automatically in return.
|
||||||
|
Possibly useful for users who primarily use an XMPP or SMS
|
||||||
|
interface and can't be bothered to remember their site
|
||||||
|
password. Note that the security implications of this are
|
||||||
|
pretty serious and have not been thoroughly tested. You
|
||||||
|
should enable it only after you've convinced yourself that
|
||||||
|
it is safe. Default is 'false'.
|
||||||
|
|
||||||
Plugins
|
Plugins
|
||||||
=======
|
=======
|
||||||
|
|
||||||
@ -1573,6 +1611,7 @@ if anyone's been overlooked in error.
|
|||||||
* Federico Marani
|
* Federico Marani
|
||||||
* Craig Andrews
|
* Craig Andrews
|
||||||
* mEDI
|
* mEDI
|
||||||
|
* Brett Taylor
|
||||||
|
|
||||||
Thanks also to the developers of our upstream library code and to the
|
Thanks also to the developers of our upstream library code and to the
|
||||||
thousands of people who have tried out Identi.ca, installed StatusNet,
|
thousands of people who have tried out Identi.ca, installed StatusNet,
|
||||||
|
@ -175,7 +175,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mail_notify_message($message, $this->user, $this->other);
|
$message->notify();
|
||||||
|
|
||||||
if ($this->format == 'xml') {
|
if ($this->format == 'xml') {
|
||||||
$this->showSingleXmlDirectMessage($message);
|
$this->showSingleXmlDirectMessage($message);
|
||||||
|
@ -72,7 +72,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction
|
|||||||
$this->original = Notice::staticGet('id', $id);
|
$this->original = Notice::staticGet('id', $id);
|
||||||
|
|
||||||
if (empty($this->original)) {
|
if (empty($this->original)) {
|
||||||
$this->clientError(_('No such notice'),
|
$this->clientError(_('No such notice.'),
|
||||||
400, $this->format);
|
400, $this->format);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction
|
|||||||
$this->user = $this->auth_user;
|
$this->user = $this->auth_user;
|
||||||
|
|
||||||
if ($this->user->id == $notice->profile_id) {
|
if ($this->user->id == $notice->profile_id) {
|
||||||
$this->clientError(_('Cannot repeat your own notice'));
|
$this->clientError(_('Cannot repeat your own notice.'),
|
||||||
400, $this->format);
|
400, $this->format);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -88,7 +88,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction
|
|||||||
$profile = $this->user->getProfile();
|
$profile = $this->user->getProfile();
|
||||||
|
|
||||||
if ($profile->hasRepeated($id)) {
|
if ($profile->hasRepeated($id)) {
|
||||||
$this->clientError(_('Already repeated that notice'),
|
$this->clientError(_('Already repeated that notice.'),
|
||||||
400, $this->format);
|
400, $this->format);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ class ApiStatusesRetweetsAction extends ApiAuthAction
|
|||||||
$this->original = Notice::staticGet('id', $id);
|
$this->original = Notice::staticGet('id', $id);
|
||||||
|
|
||||||
if (empty($this->original)) {
|
if (empty($this->original)) {
|
||||||
$this->clientError(_('No such notice'),
|
$this->clientError(_('No such notice.'),
|
||||||
400, $this->format);
|
400, $this->format);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -169,17 +169,13 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
|||||||
$notices = array();
|
$notices = array();
|
||||||
|
|
||||||
if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
|
if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
|
||||||
$notice = $this->user->noticeInbox(
|
$notice = $this->user->ownFriendsTimeline(($this->page-1) * $this->count,
|
||||||
($this->page-1) * $this->count,
|
|
||||||
$this->count, $this->since_id,
|
$this->count, $this->since_id,
|
||||||
$this->max_id, $this->since
|
$this->max_id, $this->since);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
$notice = $this->user->noticesWithFriends(
|
$notice = $this->user->friendsTimeline(($this->page-1) * $this->count,
|
||||||
($this->page-1) * $this->count,
|
|
||||||
$this->count, $this->since_id,
|
$this->count, $this->since_id,
|
||||||
$this->max_id, $this->since
|
$this->max_id, $this->since);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($notice->fetch()) {
|
while ($notice->fetch()) {
|
||||||
|
249
actions/apitimelinehome.php
Normal file
249
actions/apitimelinehome.php
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Show the home timeline
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @author Jeffery To <jeffery.to@gmail.com>
|
||||||
|
* @author mac65 <mac65@mac65.com>
|
||||||
|
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||||
|
* @author Robin Millette <robin@millette.info>
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @copyright 2009 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/lib/apibareauth.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the most recent notices (default 20) posted by the target user.
|
||||||
|
* This is the equivalent of 'You and friends' page accessed via Web.
|
||||||
|
*
|
||||||
|
* @category API
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @author Jeffery To <jeffery.to@gmail.com>
|
||||||
|
* @author mac65 <mac65@mac65.com>
|
||||||
|
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||||
|
* @author Robin Millette <robin@millette.info>
|
||||||
|
* @author Zach Copley <zach@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ApiTimelineHomeAction extends ApiBareAuthAction
|
||||||
|
{
|
||||||
|
var $notices = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take arguments for running
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST args
|
||||||
|
*
|
||||||
|
* @return boolean success flag
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($args)
|
||||||
|
{
|
||||||
|
parent::prepare($args);
|
||||||
|
common_debug("api home_timeline");
|
||||||
|
$this->user = $this->getTargetUser($this->arg('id'));
|
||||||
|
|
||||||
|
if (empty($this->user)) {
|
||||||
|
$this->clientError(_('No such user.'), 404, $this->format);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->notices = $this->getNotices();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the request
|
||||||
|
*
|
||||||
|
* Just show the notices
|
||||||
|
*
|
||||||
|
* @param array $args $_REQUEST data (unused)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
$this->showTimeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the timeline of notices
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showTimeline()
|
||||||
|
{
|
||||||
|
$profile = $this->user->getProfile();
|
||||||
|
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||||
|
$sitename = common_config('site', 'name');
|
||||||
|
$title = sprintf(_("%s and friends"), $this->user->nickname);
|
||||||
|
$taguribase = common_config('integration', 'taguri');
|
||||||
|
$id = "tag:$taguribase:HomeTimeline:" . $this->user->id;
|
||||||
|
$link = common_local_url(
|
||||||
|
'all', array('nickname' => $this->user->nickname)
|
||||||
|
);
|
||||||
|
$subtitle = sprintf(
|
||||||
|
_('Updates from %1$s and friends on %2$s!'),
|
||||||
|
$this->user->nickname, $sitename
|
||||||
|
);
|
||||||
|
$logo = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
|
||||||
|
|
||||||
|
switch($this->format) {
|
||||||
|
case 'xml':
|
||||||
|
$this->showXmlTimeline($this->notices);
|
||||||
|
break;
|
||||||
|
case 'rss':
|
||||||
|
$this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo);
|
||||||
|
break;
|
||||||
|
case 'atom':
|
||||||
|
|
||||||
|
$target_id = $this->arg('id');
|
||||||
|
|
||||||
|
if (isset($target_id)) {
|
||||||
|
$selfuri = common_root_url() .
|
||||||
|
'api/statuses/home_timeline/' .
|
||||||
|
$target_id . '.atom';
|
||||||
|
} else {
|
||||||
|
$selfuri = common_root_url() .
|
||||||
|
'api/statuses/home_timeline.atom';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->showAtomTimeline(
|
||||||
|
$this->notices, $title, $id, $link,
|
||||||
|
$subtitle, null, $selfuri, $logo
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'json':
|
||||||
|
$this->showJsonTimeline($this->notices);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$this->clientError(_('API method not found!'), $code = 404);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get notices
|
||||||
|
*
|
||||||
|
* @return array notices
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getNotices()
|
||||||
|
{
|
||||||
|
$notices = array();
|
||||||
|
|
||||||
|
if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
|
||||||
|
$notice = $this->user->noticeInbox(
|
||||||
|
($this->page-1) * $this->count,
|
||||||
|
$this->count, $this->since_id,
|
||||||
|
$this->max_id, $this->since
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$notice = $this->user->noticesWithFriends(
|
||||||
|
($this->page-1) * $this->count,
|
||||||
|
$this->count, $this->since_id,
|
||||||
|
$this->max_id, $this->since
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($notice->fetch()) {
|
||||||
|
$notices[] = clone($notice);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $notices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this action read only?
|
||||||
|
*
|
||||||
|
* @param array $args other arguments
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When was this feed last modified?
|
||||||
|
*
|
||||||
|
* @return string datestamp of the latest notice in the stream
|
||||||
|
*/
|
||||||
|
|
||||||
|
function lastModified()
|
||||||
|
{
|
||||||
|
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||||
|
return strtotime($this->notices[0]->created);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity tag for this stream
|
||||||
|
*
|
||||||
|
* Returns an Etag based on the action name, language, user ID, and
|
||||||
|
* timestamps of the first and last notice in the timeline
|
||||||
|
*
|
||||||
|
* @return string etag
|
||||||
|
*/
|
||||||
|
|
||||||
|
function etag()
|
||||||
|
{
|
||||||
|
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||||
|
|
||||||
|
$last = count($this->notices) - 1;
|
||||||
|
|
||||||
|
return '"' . implode(
|
||||||
|
':',
|
||||||
|
array($this->arg('action'),
|
||||||
|
common_language(),
|
||||||
|
$this->user->id,
|
||||||
|
strtotime($this->notices[0]->created),
|
||||||
|
strtotime($this->notices[$last]->created))
|
||||||
|
)
|
||||||
|
. '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -96,7 +96,7 @@ class FeaturedAction extends Action
|
|||||||
|
|
||||||
function getInstructions()
|
function getInstructions()
|
||||||
{
|
{
|
||||||
return sprintf(_('A selection of some of the great users on %s'),
|
return sprintf(_('A selection of some great users on %s'),
|
||||||
common_config('site', 'name'));
|
common_config('site', 'name'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,15 +31,15 @@ class FileAction extends Action
|
|||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
$this->id = $this->trimmed('notice');
|
$this->id = $this->trimmed('notice');
|
||||||
if (empty($this->id)) {
|
if (empty($this->id)) {
|
||||||
$this->clientError(_('No notice id'));
|
$this->clientError(_('No notice ID.'));
|
||||||
}
|
}
|
||||||
$notice = Notice::staticGet('id', $this->id);
|
$notice = Notice::staticGet('id', $this->id);
|
||||||
if (empty($notice)) {
|
if (empty($notice)) {
|
||||||
$this->clientError(_('No notice'));
|
$this->clientError(_('No notice.'));
|
||||||
}
|
}
|
||||||
$atts = $notice->attachments();
|
$atts = $notice->attachments();
|
||||||
if (empty($atts)) {
|
if (empty($atts)) {
|
||||||
$this->clientError(_('No attachments'));
|
$this->clientError(_('No attachments.'));
|
||||||
}
|
}
|
||||||
foreach ($atts as $att) {
|
foreach ($atts as $att) {
|
||||||
if (!empty($att->filename)) {
|
if (!empty($att->filename)) {
|
||||||
@ -48,7 +48,7 @@ class FileAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (empty($this->filerec)) {
|
if (empty($this->filerec)) {
|
||||||
$this->clientError(_('No uploaded attachments'));
|
$this->clientError(_('No uploaded attachments.'));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -88,14 +88,14 @@ class groupRssAction extends Rss10Action
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$nickname) {
|
if (!$nickname) {
|
||||||
$this->clientError(_('No nickname'), 404);
|
$this->clientError(_('No nickname.'), 404);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->group = User_group::staticGet('nickname', $nickname);
|
$this->group = User_group::staticGet('nickname', $nickname);
|
||||||
|
|
||||||
if (!$this->group) {
|
if (!$this->group) {
|
||||||
$this->clientError(_('No such group'), 404);
|
$this->clientError(_('No such group.'), 404);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ class NewmessageAction extends Action
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->notify($user, $this->other, $message);
|
$message->notify();
|
||||||
|
|
||||||
if ($this->boolean('ajax')) {
|
if ($this->boolean('ajax')) {
|
||||||
$this->startHTML('text/xml;charset=utf-8');
|
$this->startHTML('text/xml;charset=utf-8');
|
||||||
@ -247,12 +247,6 @@ class NewmessageAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function notify($from, $to, $message)
|
|
||||||
{
|
|
||||||
mail_notify_message($message, $from, $to);
|
|
||||||
// XXX: Jabber, SMS notifications... probably queued
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do nothing (override)
|
// Do nothing (override)
|
||||||
|
|
||||||
function showNoticeForm()
|
function showNoticeForm()
|
||||||
|
@ -169,6 +169,14 @@ class NewnoticeAction extends Action
|
|||||||
$location_id = $this->trimmed('location_id');
|
$location_id = $this->trimmed('location_id');
|
||||||
$location_ns = $this->trimmed('location_ns');
|
$location_ns = $this->trimmed('location_ns');
|
||||||
|
|
||||||
|
if (!empty($lat) && !empty($lon) && empty($location_id)) {
|
||||||
|
$location = Location::fromLatLon($lat, $lon);
|
||||||
|
if (!empty($location)) {
|
||||||
|
$location_id = $location->location_id;
|
||||||
|
$location_ns = $location->location_ns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$upload = null;
|
$upload = null;
|
||||||
$upload = MediaFile::fromUpload('attach');
|
$upload = MediaFile::fromUpload('attach');
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ class PathsadminpanelAction extends AdminPanelAction
|
|||||||
function saveSettings()
|
function saveSettings()
|
||||||
{
|
{
|
||||||
static $settings = array(
|
static $settings = array(
|
||||||
'site' => array('path', 'locale_path'),
|
'site' => array('path', 'locale_path', 'ssl', 'sslserver'),
|
||||||
'theme' => array('server', 'dir', 'path'),
|
'theme' => array('server', 'dir', 'path'),
|
||||||
'avatar' => array('server', 'dir', 'path'),
|
'avatar' => array('server', 'dir', 'path'),
|
||||||
'background' => array('server', 'dir', 'path')
|
'background' => array('server', 'dir', 'path')
|
||||||
@ -160,6 +160,11 @@ class PathsadminpanelAction extends AdminPanelAction
|
|||||||
$this->clientError(sprintf(_("Locales directory not readable: %s"), $values['site']['locale_path']));
|
$this->clientError(sprintf(_("Locales directory not readable: %s"), $values['site']['locale_path']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate SSL setup
|
||||||
|
|
||||||
|
if (mb_strlen($values['site']['sslserver']) > 255) {
|
||||||
|
$this->clientError(_("Invalid SSL server. The maximum length is 255 characters."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -283,6 +288,29 @@ class PathsAdminPanelForm extends AdminForm
|
|||||||
|
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
$this->out->elementEnd('fieldset');
|
$this->out->elementEnd('fieldset');
|
||||||
|
|
||||||
|
$this->out->elementStart('fieldset', array('id' => 'settings_admin_ssl'));
|
||||||
|
$this->out->element('legend', null, _('SSL'));
|
||||||
|
$this->out->elementStart('ul', 'form_data');
|
||||||
|
$this->li();
|
||||||
|
$ssl = array('never' => _('Never'),
|
||||||
|
'sometimes' => _('Sometimes'),
|
||||||
|
'always' => _('Always'));
|
||||||
|
|
||||||
|
common_debug("site ssl = " . $this->value('site', 'ssl'));
|
||||||
|
|
||||||
|
$this->out->dropdown('site-ssl', _('Use SSL'),
|
||||||
|
$ssl, _('When to use SSL'),
|
||||||
|
false, $this->value('ssl', 'site'));
|
||||||
|
$this->unli();
|
||||||
|
|
||||||
|
$this->li();
|
||||||
|
$this->input('sslserver', _('SSL Server'),
|
||||||
|
_('Server to direct SSL requests to'), 'site');
|
||||||
|
$this->unli();
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
$this->out->elementEnd('fieldset');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -297,7 +325,6 @@ class PathsAdminPanelForm extends AdminForm
|
|||||||
'save', _('Save paths'));
|
'save', _('Save paths'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to simplify some of the duplicated code around
|
* Utility to simplify some of the duplicated code around
|
||||||
* params and settings. Overriding the input() in the base class
|
* params and settings. Overriding the input() in the base class
|
||||||
|
@ -106,13 +106,17 @@ class RepeatAction extends Action
|
|||||||
{
|
{
|
||||||
$repeat = $this->notice->repeat($this->user->id, 'web');
|
$repeat = $this->notice->repeat($this->user->id, 'web');
|
||||||
|
|
||||||
|
common_broadcast_notice($repeat);
|
||||||
|
|
||||||
if ($this->boolean('ajax')) {
|
if ($this->boolean('ajax')) {
|
||||||
$this->startHTML('text/xml;charset=utf-8');
|
$this->startHTML('text/xml;charset=utf-8');
|
||||||
$this->elementStart('head');
|
$this->elementStart('head');
|
||||||
$this->element('title', null, _('Repeated'));
|
$this->element('title', null, _('Repeated'));
|
||||||
$this->elementEnd('head');
|
$this->elementEnd('head');
|
||||||
$this->elementStart('body');
|
$this->elementStart('body');
|
||||||
$this->element('p', array('id' => 'repeat_response'), _('Repeated!'));
|
$this->element('p', array('id' => 'repeat_response',
|
||||||
|
'class' => 'repeated'),
|
||||||
|
_('Repeated!'));
|
||||||
$this->elementEnd('body');
|
$this->elementEnd('body');
|
||||||
$this->elementEnd('html');
|
$this->elementEnd('html');
|
||||||
} else {
|
} else {
|
||||||
|
@ -92,8 +92,7 @@ class SiteadminpanelAction extends AdminPanelAction
|
|||||||
{
|
{
|
||||||
static $settings = array('site' => array('name', 'broughtby', 'broughtbyurl',
|
static $settings = array('site' => array('name', 'broughtby', 'broughtbyurl',
|
||||||
'email', 'timezone', 'language',
|
'email', 'timezone', 'language',
|
||||||
'ssl', 'sslserver', 'site',
|
'site', 'textlimit', 'dupelimit'),
|
||||||
'textlimit', 'dupelimit'),
|
|
||||||
'snapshot' => array('run', 'reporturl', 'frequency'));
|
'snapshot' => array('run', 'reporturl', 'frequency'));
|
||||||
|
|
||||||
static $booleans = array('site' => array('private', 'inviteonly', 'closed', 'fancy'));
|
static $booleans = array('site' => array('private', 'inviteonly', 'closed', 'fancy'));
|
||||||
@ -192,18 +191,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
|||||||
$this->clientError(_("Snapshot frequency must be a number."));
|
$this->clientError(_("Snapshot frequency must be a number."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate SSL setup
|
|
||||||
|
|
||||||
if (in_array($values['site']['ssl'], array('sometimes', 'always'))) {
|
|
||||||
if (empty($values['site']['sslserver'])) {
|
|
||||||
$this->clientError(_("You must set an SSL server when enabling SSL."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mb_strlen($values['site']['sslserver']) > 255) {
|
|
||||||
$this->clientError(_("Invalid SSL server. The maximum length is 255 characters."));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate text limit
|
// Validate text limit
|
||||||
|
|
||||||
if (!Validate::number($values['site']['textlimit'], array('min' => 140))) {
|
if (!Validate::number($values['site']['textlimit'], array('min' => 140))) {
|
||||||
@ -376,26 +363,6 @@ class SiteAdminPanelForm extends AdminForm
|
|||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
$this->out->elementEnd('fieldset');
|
$this->out->elementEnd('fieldset');
|
||||||
|
|
||||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_ssl'));
|
|
||||||
$this->out->element('legend', null, _('SSL'));
|
|
||||||
$this->out->elementStart('ul', 'form_data');
|
|
||||||
$this->li();
|
|
||||||
$ssl = array('never' => _('Never'),
|
|
||||||
'sometimes' => _('Sometimes'),
|
|
||||||
'always' => _('Always'));
|
|
||||||
|
|
||||||
$this->out->dropdown('ssl', _('Use SSL'),
|
|
||||||
$ssl, _('When to use SSL'),
|
|
||||||
false, $this->value('ssl', 'site'));
|
|
||||||
$this->unli();
|
|
||||||
|
|
||||||
$this->li();
|
|
||||||
$this->input('sslserver', _('SSL Server'),
|
|
||||||
_('Server to direct SSL requests to'));
|
|
||||||
$this->unli();
|
|
||||||
$this->out->elementEnd('ul');
|
|
||||||
$this->out->elementEnd('fieldset');
|
|
||||||
|
|
||||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_limits'));
|
$this->out->elementStart('fieldset', array('id' => 'settings_admin_limits'));
|
||||||
$this->out->element('legend', null, _('Limits'));
|
$this->out->element('legend', null, _('Limits'));
|
||||||
$this->out->elementStart('ul', 'form_data');
|
$this->out->elementStart('ul', 'form_data');
|
||||||
|
@ -30,13 +30,13 @@ class TagotherAction extends Action
|
|||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
if (!common_logged_in()) {
|
if (!common_logged_in()) {
|
||||||
$this->clientError(_('Not logged in'), 403);
|
$this->clientError(_('Not logged in.'), 403);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$id = $this->trimmed('id');
|
$id = $this->trimmed('id');
|
||||||
if (!$id) {
|
if (!$id) {
|
||||||
$this->clientError(_('No id argument.'));
|
$this->clientError(_('No ID argument.'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class UserbyidAction extends Action
|
|||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
$id = $this->trimmed('id');
|
$id = $this->trimmed('id');
|
||||||
if (!$id) {
|
if (!$id) {
|
||||||
$this->clientError(_('No id.'));
|
$this->clientError(_('No ID.'));
|
||||||
}
|
}
|
||||||
$user = User::staticGet($id);
|
$user = User::staticGet($id);
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
@ -88,4 +88,3 @@ class UserbyidAction extends Action
|
|||||||
common_redirect($url, 303);
|
common_redirect($url, 303);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,29 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
|||||||
|
|
||||||
class Memcached_DataObject extends DB_DataObject
|
class Memcached_DataObject extends DB_DataObject
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Destructor to free global memory resources associated with
|
||||||
|
* this data object when it's unset or goes out of scope.
|
||||||
|
* DB_DataObject doesn't do this yet by itself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __destruct()
|
||||||
|
{
|
||||||
|
$this->free();
|
||||||
|
if (method_exists('DB_DataObject', '__destruct')) {
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for DB_DataObject's static lookup using memcached
|
||||||
|
* as backing instead of an in-process cache array.
|
||||||
|
*
|
||||||
|
* @param string $cls classname of object type to load
|
||||||
|
* @param mixed $k key field name, or value for primary key
|
||||||
|
* @param mixed $v key field value, or leave out for primary key lookup
|
||||||
|
* @return mixed Memcached_DataObject subtype or false
|
||||||
|
*/
|
||||||
function &staticGet($cls, $k, $v=null)
|
function &staticGet($cls, $k, $v=null)
|
||||||
{
|
{
|
||||||
if (is_null($v)) {
|
if (is_null($v)) {
|
||||||
@ -39,6 +62,13 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
} else {
|
} else {
|
||||||
$i = DB_DataObject::staticGet($cls, $k, $v);
|
$i = DB_DataObject::staticGet($cls, $k, $v);
|
||||||
if ($i) {
|
if ($i) {
|
||||||
|
// DB_DataObject's in-process lookup cache interferes with GC
|
||||||
|
// to cause massive memory leaks in long-running processes.
|
||||||
|
if (php_sapi_name() == 'cli') {
|
||||||
|
$i->_clear_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now store it into the shared memcached, if present...
|
||||||
$i->encache();
|
$i->encache();
|
||||||
}
|
}
|
||||||
return $i;
|
return $i;
|
||||||
@ -93,6 +123,11 @@ class Memcached_DataObject extends DB_DataObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
static function cacheKey($cls, $k, $v) {
|
static function cacheKey($cls, $k, $v) {
|
||||||
|
if (is_object($cls) || is_object($j) || is_object($v)) {
|
||||||
|
$e = new Exception();
|
||||||
|
common_log(LOG_ERR, __METHOD__ . ' object in param: ' .
|
||||||
|
str_replace("\n", " ", $e->getTraceAsString()));
|
||||||
|
}
|
||||||
return common_cache_key(strtolower($cls).':'.$k.':'.$v);
|
return common_cache_key(strtolower($cls).':'.$k.':'.$v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,4 +89,12 @@ class Message extends Memcached_DataObject
|
|||||||
$contentlimit = self::maxContent();
|
$contentlimit = self::maxContent();
|
||||||
return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit));
|
return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function notify()
|
||||||
|
{
|
||||||
|
$from = User::staticGet('id', $this->from_profile);
|
||||||
|
$to = User::staticGet('id', $this->to_profile);
|
||||||
|
|
||||||
|
mail_notify_message($this, $from, $to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,13 +175,43 @@ class Notice extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save a new notice and push it out to subscribers' inboxes.
|
||||||
|
* Poster's permissions are checked before sending.
|
||||||
|
*
|
||||||
|
* @param int $profile_id Profile ID of the poster
|
||||||
|
* @param string $content source message text; links may be shortened
|
||||||
|
* per current user's preference
|
||||||
|
* @param string $source source key ('web', 'api', etc)
|
||||||
|
* @param array $options Associative array of optional properties:
|
||||||
|
* string 'created' timestamp of notice; defaults to now
|
||||||
|
* int 'is_local' source/gateway ID, one of:
|
||||||
|
* Notice::LOCAL_PUBLIC - Local, ok to appear in public timeline
|
||||||
|
* Notice::REMOTE_OMB - Sent from a remote OMB service;
|
||||||
|
* hide from public timeline but show in
|
||||||
|
* local "and friends" timelines
|
||||||
|
* Notice::LOCAL_NONPUBLIC - Local, but hide from public timeline
|
||||||
|
* Notice::GATEWAY - From another non-OMB service;
|
||||||
|
* will not appear in public views
|
||||||
|
* float 'lat' decimal latitude for geolocation
|
||||||
|
* float 'lon' decimal longitude for geolocation
|
||||||
|
* int 'location_id' geoname identifier
|
||||||
|
* int 'location_ns' geoname namespace to interpret location_id
|
||||||
|
* int 'reply_to'; notice ID this is a reply to
|
||||||
|
* int 'repeat_of'; notice ID this is a repeat of
|
||||||
|
* string 'uri' permalink to notice; defaults to local notice URL
|
||||||
|
*
|
||||||
|
* @return Notice
|
||||||
|
* @throws ClientException
|
||||||
|
*/
|
||||||
static function saveNew($profile_id, $content, $source, $options=null) {
|
static function saveNew($profile_id, $content, $source, $options=null) {
|
||||||
|
$defaults = array('uri' => null,
|
||||||
|
'reply_to' => null,
|
||||||
|
'repeat_of' => null);
|
||||||
|
|
||||||
if (!empty($options)) {
|
if (!empty($options)) {
|
||||||
|
$options = $options + $defaults;
|
||||||
extract($options);
|
extract($options);
|
||||||
if (!isset($reply_to)) {
|
|
||||||
$reply_to = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($is_local)) {
|
if (empty($is_local)) {
|
||||||
@ -530,8 +560,18 @@ class Notice extends Memcached_DataObject
|
|||||||
if ($member->find()) {
|
if ($member->find()) {
|
||||||
while ($member->fetch()) {
|
while ($member->fetch()) {
|
||||||
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id));
|
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id));
|
||||||
|
$cache->delete(common_cache_key('notice_inbox:by_user_own:' . $member->profile_id));
|
||||||
|
if (empty($this->repeat_of)) {
|
||||||
|
$cache->delete(common_cache_key('user:friends_timeline:' . $member->profile_id));
|
||||||
|
$cache->delete(common_cache_key('user:friends_timeline_own:' . $member->profile_id));
|
||||||
|
}
|
||||||
if ($blowLast) {
|
if ($blowLast) {
|
||||||
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id . ';last'));
|
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id . ';last'));
|
||||||
|
$cache->delete(common_cache_key('notice_inbox:by_user_own:' . $member->profile_id . ';last'));
|
||||||
|
if (empty($this->repeat_of)) {
|
||||||
|
$cache->delete(common_cache_key('user:friends_timeline:' . $member->profile_id . ';last'));
|
||||||
|
$cache->delete(common_cache_key('user:friends_timeline_own:' . $member->profile_id . ';last'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -579,9 +619,17 @@ class Notice extends Memcached_DataObject
|
|||||||
while ($user->fetch()) {
|
while ($user->fetch()) {
|
||||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id));
|
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id));
|
||||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id));
|
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id));
|
||||||
|
if (empty($this->repeat_of)) {
|
||||||
|
$cache->delete(common_cache_key('user:friends_timeline:'.$user->id));
|
||||||
|
$cache->delete(common_cache_key('user:friends_timeline_own:'.$user->id));
|
||||||
|
}
|
||||||
if ($blowLast) {
|
if ($blowLast) {
|
||||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id.';last'));
|
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id.';last'));
|
||||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id.';last'));
|
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id.';last'));
|
||||||
|
if (empty($this->repeat_of)) {
|
||||||
|
$cache->delete(common_cache_key('user:friends_timeline:'.$user->id.';last'));
|
||||||
|
$cache->delete(common_cache_key('user:friends_timeline_own:'.$user->id.';last'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$user->free();
|
$user->free();
|
||||||
@ -948,6 +996,9 @@ class Notice extends Memcached_DataObject
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array of integer profile IDs
|
||||||
|
*/
|
||||||
function saveReplies()
|
function saveReplies()
|
||||||
{
|
{
|
||||||
// Alternative reply format
|
// Alternative reply format
|
||||||
@ -1026,8 +1077,8 @@ class Notice extends Memcached_DataObject
|
|||||||
|
|
||||||
$recipientIds = array_keys($replied);
|
$recipientIds = array_keys($replied);
|
||||||
|
|
||||||
foreach ($recipientIds as $recipient) {
|
foreach ($recipientIds as $recipientId) {
|
||||||
$user = User::staticGet('id', $recipient);
|
$user = User::staticGet('id', $recipientId);
|
||||||
if ($user) {
|
if ($user) {
|
||||||
mail_notify_attn($user, $this);
|
mail_notify_attn($user, $this);
|
||||||
}
|
}
|
||||||
|
@ -180,6 +180,27 @@ class User extends Memcached_DataObject
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new user account and profile and set up default subscriptions.
|
||||||
|
* If a new-user welcome message is configured, this will be sent.
|
||||||
|
*
|
||||||
|
* @param array $fields associative array of optional properties
|
||||||
|
* string 'bio'
|
||||||
|
* string 'email'
|
||||||
|
* bool 'email_confirmed' pass true to mark email as pre-confirmed
|
||||||
|
* string 'fullname'
|
||||||
|
* string 'homepage'
|
||||||
|
* string 'location' informal string description of geolocation
|
||||||
|
* float 'lat' decimal latitude for geolocation
|
||||||
|
* float 'lon' decimal longitude for geolocation
|
||||||
|
* int 'location_id' geoname identifier
|
||||||
|
* int 'location_ns' geoname namespace to interpret location_id
|
||||||
|
* string 'nickname' REQUIRED
|
||||||
|
* string 'password' (may be missing for eg OpenID registrations)
|
||||||
|
* string 'code' invite code
|
||||||
|
* ?string 'uri' permalink to notice; defaults to local notice URL
|
||||||
|
* @return mixed User object or false on failure
|
||||||
|
*/
|
||||||
static function register($fields) {
|
static function register($fields) {
|
||||||
|
|
||||||
// MAGICALLY put fields into current scope
|
// MAGICALLY put fields into current scope
|
||||||
@ -329,7 +350,7 @@ class User extends Memcached_DataObject
|
|||||||
|
|
||||||
$profile->query('COMMIT');
|
$profile->query('COMMIT');
|
||||||
|
|
||||||
if ($email && !$user->email) {
|
if (!empty($email) && !$user->email) {
|
||||||
mail_confirm_address($user, $confirm->code, $profile->nickname, $email);
|
mail_confirm_address($user, $confirm->code, $profile->nickname, $email);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,6 +494,77 @@ class User extends Memcached_DataObject
|
|||||||
return Notice::getStreamByIds($ids);
|
return Notice::getStreamByIds($ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function friendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
|
{
|
||||||
|
$ids = Notice::stream(array($this, '_friendsTimelineDirect'),
|
||||||
|
array(false),
|
||||||
|
'user:friends_timeline:'.$this->id,
|
||||||
|
$offset, $limit, $since_id, $before_id, $since);
|
||||||
|
|
||||||
|
return Notice::getStreamByIds($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ownFriendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||||
|
{
|
||||||
|
$ids = Notice::stream(array($this, '_friendsTimelineDirect'),
|
||||||
|
array(true),
|
||||||
|
'user:friends_timeline_own:'.$this->id,
|
||||||
|
$offset, $limit, $since_id, $before_id, $since);
|
||||||
|
|
||||||
|
return Notice::getStreamByIds($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _friendsTimelineDirect($own, $offset, $limit, $since_id, $max_id, $since)
|
||||||
|
{
|
||||||
|
$qry =
|
||||||
|
'SELECT notice.id AS id ' .
|
||||||
|
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
|
||||||
|
'WHERE notice_inbox.user_id = ' . $this->id . ' ' .
|
||||||
|
'AND notice.repeat_of IS NULL ';
|
||||||
|
|
||||||
|
if (!$own) {
|
||||||
|
// XXX: autoload notice inbox for constant
|
||||||
|
$inbox = new Notice_inbox();
|
||||||
|
|
||||||
|
$qry .= 'AND notice_inbox.source != ' . NOTICE_INBOX_SOURCE_GATEWAY . ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($since_id != 0) {
|
||||||
|
$qry .= 'AND notice.id > ' . $since_id . ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($max_id != 0) {
|
||||||
|
$qry .= 'AND notice.id <= ' . $max_id . ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($since)) {
|
||||||
|
$qry .= 'AND notice.modified > \'' . date('Y-m-d H:i:s', $since) . '\' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: we sort by fave time, not by notice time!
|
||||||
|
|
||||||
|
$qry .= 'ORDER BY notice_id DESC ';
|
||||||
|
|
||||||
|
if (!is_null($offset)) {
|
||||||
|
$qry .= "LIMIT $limit OFFSET $offset";
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
|
||||||
|
$notice = new Notice();
|
||||||
|
|
||||||
|
$notice->query($qry);
|
||||||
|
|
||||||
|
while ($notice->fetch()) {
|
||||||
|
$ids[] = $notice->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notice->free();
|
||||||
|
$notice = NULL;
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
function blowFavesCache()
|
function blowFavesCache()
|
||||||
{
|
{
|
||||||
$cache = common_memcache();
|
$cache = common_memcache();
|
||||||
|
@ -544,3 +544,24 @@ modified = 384
|
|||||||
|
|
||||||
[user_group__keys]
|
[user_group__keys]
|
||||||
id = N
|
id = N
|
||||||
|
|
||||||
|
[user_openid]
|
||||||
|
canonical = 130
|
||||||
|
display = 130
|
||||||
|
user_id = 129
|
||||||
|
created = 142
|
||||||
|
modified = 384
|
||||||
|
|
||||||
|
[user_openid__keys]
|
||||||
|
canonical = K
|
||||||
|
display = U
|
||||||
|
|
||||||
|
[user_openid_trustroot]
|
||||||
|
trustroot = 130
|
||||||
|
user_id = 129
|
||||||
|
created = 142
|
||||||
|
modified = 384
|
||||||
|
|
||||||
|
[user_openid__keys]
|
||||||
|
trustroot = K
|
||||||
|
user_id = K
|
@ -3,7 +3,7 @@
|
|||||||
based on the Free Software [StatusNet](http://status.net/) tool.
|
based on the Free Software [StatusNet](http://status.net/) tool.
|
||||||
|
|
||||||
If you [register](%%action.register%%) for an account,
|
If you [register](%%action.register%%) for an account,
|
||||||
you can post small (140 chars or less) text notices
|
you can post small (%%site.textlimit%% chars or less) text notices
|
||||||
about yourself, where you are, what you're doing, or practically
|
about yourself, where you are, what you're doing, or practically
|
||||||
anything you want. You can also subscribe to the notices of your
|
anything you want. You can also subscribe to the notices of your
|
||||||
friends, or other people you're interested in, and follow them on the
|
friends, or other people you're interested in, and follow them on the
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
%%site.name%% is a **microblogging service**. Users post short (140
|
%%site.name%% is a **microblogging service**. Users post short (%%site.textlimit%%
|
||||||
character) notices which are broadcast to their friends and fans using
|
character) notices which are broadcast to their friends and fans using
|
||||||
the Web, RSS, or instant messages.
|
the Web, RSS, or instant messages.
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ Sending updates
|
|||||||
---------------
|
---------------
|
||||||
|
|
||||||
You send updates by sending messages to %%xmpp.user%%@%%xmpp.server%%. Messages
|
You send updates by sending messages to %%xmpp.user%%@%%xmpp.server%%. Messages
|
||||||
should be less than 140 characters; longer messages will be truncated.
|
should be less than %%site.textlimit%% characters; longer messages will be truncated.
|
||||||
|
|
||||||
Commands
|
Commands
|
||||||
--------
|
--------
|
||||||
|
14
index.php
14
index.php
@ -278,6 +278,20 @@ function main()
|
|||||||
&& !preg_match('/rss$/', $action)
|
&& !preg_match('/rss$/', $action)
|
||||||
&& !preg_match('/^Api/', $action)
|
&& !preg_match('/^Api/', $action)
|
||||||
) {
|
) {
|
||||||
|
// set returnto
|
||||||
|
$rargs =& common_copy_args($args);
|
||||||
|
unset($rargs['action']);
|
||||||
|
if (common_config('site', 'fancy')) {
|
||||||
|
unset($rargs['p']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('submit', $rargs)) {
|
||||||
|
unset($rargs['submit']);
|
||||||
|
}
|
||||||
|
foreach (array_keys($_COOKIE) as $cookie) {
|
||||||
|
unset($rargs[$cookie]);
|
||||||
|
}
|
||||||
|
common_set_returnto(common_local_url($action, $rargs));
|
||||||
|
|
||||||
common_redirect(common_local_url('login'));
|
common_redirect(common_local_url('login'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
37
js/util.js
37
js/util.js
@ -316,7 +316,42 @@ var SN = { // StatusNet
|
|||||||
},
|
},
|
||||||
|
|
||||||
NoticeRepeat: function() {
|
NoticeRepeat: function() {
|
||||||
$('.form_repeat').each(function() { SN.U.FormXHR($(this)); });
|
$('.form_repeat').each(function() {
|
||||||
|
SN.U.FormXHR($(this));
|
||||||
|
SN.U.NoticeRepeatConfirmation($(this));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
NoticeRepeatConfirmation: function(form) {
|
||||||
|
function NRC() {
|
||||||
|
form.closest('.notice-options').addClass('opaque');
|
||||||
|
form.addClass('dialogbox');
|
||||||
|
|
||||||
|
form.append('<button class="close">×</button>');
|
||||||
|
form.find('button.close').click(function(){
|
||||||
|
$(this).remove();
|
||||||
|
|
||||||
|
form.closest('.notice-options').removeClass('opaque');
|
||||||
|
form.removeClass('dialogbox');
|
||||||
|
form.find('.submit_dialogbox').remove();
|
||||||
|
form.find('.submit').show();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
form.find('.submit').bind('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var submit = form.find('.submit').clone();
|
||||||
|
submit.addClass('submit_dialogbox');
|
||||||
|
submit.removeClass('submit');
|
||||||
|
form.append(submit);
|
||||||
|
|
||||||
|
$(this).hide();
|
||||||
|
|
||||||
|
NRC();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
NoticeAttachments: function() {
|
NoticeAttachments: function() {
|
||||||
|
19
lib/api.php
19
lib/api.php
@ -55,6 +55,7 @@ class ApiAction extends Action
|
|||||||
{
|
{
|
||||||
var $format = null;
|
var $format = null;
|
||||||
var $user = null;
|
var $user = null;
|
||||||
|
var $auth_user = null;
|
||||||
var $page = null;
|
var $page = null;
|
||||||
var $count = null;
|
var $count = null;
|
||||||
var $max_id = null;
|
var $max_id = null;
|
||||||
@ -190,13 +191,14 @@ class ApiAction extends Action
|
|||||||
$twitter_user['following'] = false;
|
$twitter_user['following'] = false;
|
||||||
$twitter_user['notifications'] = false;
|
$twitter_user['notifications'] = false;
|
||||||
|
|
||||||
if (isset($apidata['user'])) {
|
if (isset($this->auth_user)) {
|
||||||
|
|
||||||
$twitter_user['following'] = $apidata['user']->isSubscribed($profile);
|
$twitter_user['following'] = $this->auth_user->isSubscribed($profile);
|
||||||
|
|
||||||
// Notifications on?
|
// Notifications on?
|
||||||
$sub = Subscription::pkeyGet(array('subscriber' =>
|
$sub = Subscription::pkeyGet(array('subscriber' =>
|
||||||
$apidata['user']->id, 'subscribed' => $profile->id));
|
$this->auth_user->id,
|
||||||
|
'subscribed' => $profile->id));
|
||||||
|
|
||||||
if ($sub) {
|
if ($sub) {
|
||||||
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
|
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
|
||||||
@ -218,16 +220,17 @@ class ApiAction extends Action
|
|||||||
{
|
{
|
||||||
$base = $this->twitterSimpleStatusArray($notice, $include_user);
|
$base = $this->twitterSimpleStatusArray($notice, $include_user);
|
||||||
|
|
||||||
if (empty($notice->repeat_of)) {
|
if (!empty($notice->repeat_of)) {
|
||||||
return $base;
|
|
||||||
} else {
|
|
||||||
$original = Notice::staticGet('id', $notice->repeat_of);
|
$original = Notice::staticGet('id', $notice->repeat_of);
|
||||||
|
if (!empty($original)) {
|
||||||
$original_array = $this->twitterSimpleStatusArray($original, $include_user);
|
$original_array = $this->twitterSimpleStatusArray($original, $include_user);
|
||||||
$original_array['retweeted_status'] = $base;
|
$base['retweeted_status'] = $original_array;
|
||||||
return $original_array;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $base;
|
||||||
|
}
|
||||||
|
|
||||||
function twitterSimpleStatusArray($notice, $include_user=true)
|
function twitterSimpleStatusArray($notice, $include_user=true)
|
||||||
{
|
{
|
||||||
$profile = $notice->getProfile();
|
$profile = $notice->getProfile();
|
||||||
|
@ -53,8 +53,6 @@ require_once INSTALLDIR . '/lib/api.php';
|
|||||||
class ApiAuthAction extends ApiAction
|
class ApiAuthAction extends ApiAction
|
||||||
{
|
{
|
||||||
|
|
||||||
var $auth_user = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take arguments for running, and output basic auth header if needed
|
* Take arguments for running, and output basic auth header if needed
|
||||||
*
|
*
|
||||||
|
@ -372,6 +372,7 @@ class MessageCommand extends Command
|
|||||||
}
|
}
|
||||||
$message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source());
|
$message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source());
|
||||||
if ($message) {
|
if ($message) {
|
||||||
|
$message->notify();
|
||||||
$channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other));
|
$channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other));
|
||||||
} else {
|
} else {
|
||||||
$channel->error($this->user, _('Error sending direct message.'));
|
$channel->error($this->user, _('Error sending direct message.'));
|
||||||
@ -379,6 +380,65 @@ class MessageCommand extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RepeatCommand extends Command
|
||||||
|
{
|
||||||
|
var $other = null;
|
||||||
|
function __construct($user, $other)
|
||||||
|
{
|
||||||
|
parent::__construct($user);
|
||||||
|
$this->other = $other;
|
||||||
|
}
|
||||||
|
|
||||||
|
function execute($channel)
|
||||||
|
{
|
||||||
|
if(substr($this->other,0,1)=='#'){
|
||||||
|
//repeating a specific notice_id
|
||||||
|
|
||||||
|
$notice = Notice::staticGet(substr($this->other,1));
|
||||||
|
if (!$notice) {
|
||||||
|
$channel->error($this->user, _('Notice with that id does not exist'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$recipient = $notice->getProfile();
|
||||||
|
}else{
|
||||||
|
//repeating a given user's last notice
|
||||||
|
|
||||||
|
$recipient =
|
||||||
|
common_relative_profile($this->user, common_canonical_nickname($this->other));
|
||||||
|
|
||||||
|
if (!$recipient) {
|
||||||
|
$channel->error($this->user, _('No such user.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$notice = $recipient->getCurrentNotice();
|
||||||
|
if (!$notice) {
|
||||||
|
$channel->error($this->user, _('User has no last notice'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->user->id == $notice->profile_id)
|
||||||
|
{
|
||||||
|
$channel->error($this->user, _('Cannot repeat your own notice'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($recipient->hasRepeated($notice->id)) {
|
||||||
|
$channel->error($this->user, _('Already repeated that notice'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$repeat = $notice->repeat($this->user->id, $channel->source);
|
||||||
|
|
||||||
|
if ($repeat) {
|
||||||
|
common_broadcast_notice($repeat);
|
||||||
|
$channel->output($this->user, sprintf(_('Notice from %s repeated'), $recipient->nickname));
|
||||||
|
} else {
|
||||||
|
$channel->error($this->user, _('Error repeating notice.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ReplyCommand extends Command
|
class ReplyCommand extends Command
|
||||||
{
|
{
|
||||||
var $other = null;
|
var $other = null;
|
||||||
@ -696,6 +756,8 @@ class HelpCommand extends Command
|
|||||||
"whois <nickname> - get profile info on user\n".
|
"whois <nickname> - get profile info on user\n".
|
||||||
"fav <nickname> - add user's last notice as a 'fave'\n".
|
"fav <nickname> - add user's last notice as a 'fave'\n".
|
||||||
"fav #<notice_id> - add notice with the given id as a 'fave'\n".
|
"fav #<notice_id> - add notice with the given id as a 'fave'\n".
|
||||||
|
"repeat #<notice_id> - repeat a notice with a given id\n".
|
||||||
|
"repeat <nickname> - repeat the last notice from user\n".
|
||||||
"reply #<notice_id> - reply to notice with a given id\n".
|
"reply #<notice_id> - reply to notice with a given id\n".
|
||||||
"reply <nickname> - reply to the last notice from user\n".
|
"reply <nickname> - reply to the last notice from user\n".
|
||||||
"join <group> - join group\n".
|
"join <group> - join group\n".
|
||||||
|
@ -169,6 +169,19 @@ class CommandInterpreter
|
|||||||
} else {
|
} else {
|
||||||
return new ReplyCommand($user, $other, $extra);
|
return new ReplyCommand($user, $other, $extra);
|
||||||
}
|
}
|
||||||
|
case 'repeat':
|
||||||
|
case 'rp':
|
||||||
|
case 'rt':
|
||||||
|
case 'rd':
|
||||||
|
if (!$arg) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
|
if ($extra) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return new RepeatCommand($user, $other);
|
||||||
|
}
|
||||||
case 'whois':
|
case 'whois':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -22,7 +22,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
|||||||
//exit with 200 response, if this is checking fancy from the installer
|
//exit with 200 response, if this is checking fancy from the installer
|
||||||
if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
|
if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
|
||||||
|
|
||||||
define('STATUSNET_VERSION', '0.9.0dev');
|
define('STATUSNET_VERSION', '0.9.0rc2');
|
||||||
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
|
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
|
||||||
|
|
||||||
define('STATUSNET_CODENAME', 'Stand');
|
define('STATUSNET_CODENAME', 'Stand');
|
||||||
|
36
lib/curry.php
Normal file
36
lib/curry.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHP 5.3 implementation of function currying, using native closures.
|
||||||
|
* On 5.2 and lower we use the fallback implementation in util.php
|
||||||
|
*
|
||||||
|
* @param callback $fn
|
||||||
|
* @param ... any remaining arguments will be appended to call-time params
|
||||||
|
* @return callback
|
||||||
|
*/
|
||||||
|
function curry($fn) {
|
||||||
|
$extra_args = func_get_args();
|
||||||
|
array_shift($extra_args);
|
||||||
|
return function() use ($fn, $extra_args) {
|
||||||
|
$args = func_get_args();
|
||||||
|
return call_user_func_array($fn,
|
||||||
|
array_merge($args, $extra_args));
|
||||||
|
};
|
||||||
|
}
|
@ -229,4 +229,6 @@ $default =
|
|||||||
array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth
|
array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth
|
||||||
'omb' =>
|
'omb' =>
|
||||||
array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates
|
array('timeout' => 5), // HTTP request timeout in seconds when contacting remote hosts for OMB updates
|
||||||
|
'logincommand' =>
|
||||||
|
array('disabled' => true),
|
||||||
);
|
);
|
||||||
|
@ -32,6 +32,21 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Locale category constants are usually predefined, but may not be
|
||||||
|
// on some systems such as Win32.
|
||||||
|
$LC_CATEGORIES = array('LC_CTYPE',
|
||||||
|
'LC_NUMERIC',
|
||||||
|
'LC_TIME',
|
||||||
|
'LC_COLLATE',
|
||||||
|
'LC_MONETARY',
|
||||||
|
'LC_MESSAGES',
|
||||||
|
'LC_ALL');
|
||||||
|
foreach ($LC_CATEGORIES as $key => $name) {
|
||||||
|
if (!defined($name)) {
|
||||||
|
define($name, $key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!function_exists('gettext')) {
|
if (!function_exists('gettext')) {
|
||||||
require_once("php-gettext/gettext.inc");
|
require_once("php-gettext/gettext.inc");
|
||||||
}
|
}
|
||||||
@ -283,10 +298,12 @@ function get_all_languages() {
|
|||||||
'en' => array('q' => 1, 'lang' => 'en', 'name' => 'English (US)', 'direction' => 'ltr'),
|
'en' => array('q' => 1, 'lang' => 'en', 'name' => 'English (US)', 'direction' => 'ltr'),
|
||||||
'es' => array('q' => 1, 'lang' => 'es', 'name' => 'Spanish', 'direction' => 'ltr'),
|
'es' => array('q' => 1, 'lang' => 'es', 'name' => 'Spanish', 'direction' => 'ltr'),
|
||||||
'fi' => array('q' => 1, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'),
|
'fi' => array('q' => 1, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'),
|
||||||
|
'fa' => array('q' => 1, 'lang' => 'fa', 'name' => 'Persian', 'direction' => 'rtl'),
|
||||||
'fr-fr' => array('q' => 1, 'lang' => 'fr', 'name' => 'French', 'direction' => 'ltr'),
|
'fr-fr' => array('q' => 1, 'lang' => 'fr', 'name' => 'French', 'direction' => 'ltr'),
|
||||||
'ga' => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Galician', 'direction' => 'ltr'),
|
'ga' => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Galician', 'direction' => 'ltr'),
|
||||||
'he' => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'),
|
'he' => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'),
|
||||||
'hsb' => array('q' => 0.8, 'lang' => 'hsb', 'name' => 'Upper Sorbian', 'direction' => 'ltr'),
|
'hsb' => array('q' => 0.8, 'lang' => 'hsb', 'name' => 'Upper Sorbian', 'direction' => 'ltr'),
|
||||||
|
'ia' => array('q' => 0.8, 'lang' => 'ia', 'name' => 'Interlingua', 'direction' => 'ltr'),
|
||||||
'is' => array('q' => 0.1, 'lang' => 'is', 'name' => 'Icelandic', 'direction' => 'ltr'),
|
'is' => array('q' => 0.1, 'lang' => 'is', 'name' => 'Icelandic', 'direction' => 'ltr'),
|
||||||
'it' => array('q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'),
|
'it' => array('q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'),
|
||||||
'jp' => array('q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', 'direction' => 'ltr'),
|
'jp' => array('q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', 'direction' => 'ltr'),
|
||||||
|
@ -599,6 +599,10 @@ function mail_notify_attn($user, $notice)
|
|||||||
|
|
||||||
$sender = $notice->getProfile();
|
$sender = $notice->getProfile();
|
||||||
|
|
||||||
|
if ($sender->id == $user->id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$sender->hasRight(Right::EMAILONREPLY)) {
|
if (!$sender->hasRight(Right::EMAILONREPLY)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -243,8 +243,9 @@ class NoticeListItem extends Widget
|
|||||||
{
|
{
|
||||||
// XXX: RDFa
|
// XXX: RDFa
|
||||||
// TODO: add notice_type class e.g., notice_video, notice_image
|
// TODO: add notice_type class e.g., notice_video, notice_image
|
||||||
|
$id = (empty($this->repeat)) ? $this->notice->id : $this->repeat->id;
|
||||||
$this->out->elementStart('li', array('class' => 'hentry notice',
|
$this->out->elementStart('li', array('class' => 'hentry notice',
|
||||||
'id' => 'notice-' . $this->notice->id));
|
'id' => 'notice-' . $id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -542,29 +543,17 @@ class NoticeListItem extends Widget
|
|||||||
$attrs['title'] = $repeater->fullname . ' (' . $repeater->nickname . ')';
|
$attrs['title'] = $repeater->fullname . ' (' . $repeater->nickname . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementStart('span', 'repeat');
|
$this->out->elementStart('span', 'repeat vcard');
|
||||||
|
|
||||||
$this->out->elementStart('a', $attrs);
|
$this->out->raw(_('Repeated by'));
|
||||||
|
|
||||||
$avatar = $repeater->getAvatar(AVATAR_MINI_SIZE);
|
$avatar = $repeater->getAvatar(AVATAR_MINI_SIZE);
|
||||||
|
|
||||||
$this->out->element('img', array('src' => ($avatar) ?
|
$this->out->elementStart('a', $attrs);
|
||||||
$avatar->displayUrl() :
|
|
||||||
Avatar::defaultImage(AVATAR_MINI_SIZE),
|
|
||||||
'class' => 'avatar photo',
|
|
||||||
'width' => AVATAR_MINI_SIZE,
|
|
||||||
'height' => AVATAR_MINI_SIZE,
|
|
||||||
'alt' =>
|
|
||||||
($repeater->fullname) ?
|
|
||||||
$repeater->fullname :
|
|
||||||
$repeater->nickname));
|
|
||||||
|
|
||||||
|
$this->out->element('span', 'nickname', $repeater->nickname);
|
||||||
$this->out->elementEnd('a');
|
$this->out->elementEnd('a');
|
||||||
|
|
||||||
$text_link = XMLStringer::estring('a', $attrs, $repeater->nickname);
|
|
||||||
|
|
||||||
$this->out->raw(sprintf(_('Repeated by %s'), $text_link));
|
|
||||||
|
|
||||||
$this->out->elementEnd('span');
|
$this->out->elementEnd('span');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -602,11 +591,13 @@ class NoticeListItem extends Widget
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
|
|
||||||
|
$todel = (empty($this->repeat)) ? $this->notice : $this->repeat;
|
||||||
|
|
||||||
if (!empty($user) &&
|
if (!empty($user) &&
|
||||||
($this->notice->profile_id == $user->id || $user->hasRight(Right::DELETEOTHERSNOTICE))) {
|
($todel->profile_id == $user->id || $user->hasRight(Right::DELETEOTHERSNOTICE))) {
|
||||||
|
|
||||||
$deleteurl = common_local_url('deletenotice',
|
$deleteurl = common_local_url('deletenotice',
|
||||||
array('notice' => $this->notice->id));
|
array('notice' => $todel->id));
|
||||||
$this->out->element('a', array('href' => $deleteurl,
|
$this->out->element('a', array('href' => $deleteurl,
|
||||||
'class' => 'notice_delete',
|
'class' => 'notice_delete',
|
||||||
'title' => _('Delete this notice')), _('Delete'));
|
'title' => _('Delete this notice')), _('Delete'));
|
||||||
@ -625,7 +616,9 @@ class NoticeListItem extends Widget
|
|||||||
if ($user && $user->id != $this->notice->profile_id) {
|
if ($user && $user->id != $this->notice->profile_id) {
|
||||||
$profile = $user->getProfile();
|
$profile = $user->getProfile();
|
||||||
if ($profile->hasRepeated($this->notice->id)) {
|
if ($profile->hasRepeated($this->notice->id)) {
|
||||||
$this->out->text(_('Repeated'));
|
$this->out->element('span', array('class' => 'repeated',
|
||||||
|
'title' => _('Notice repeated')),
|
||||||
|
_('Repeated'));
|
||||||
} else {
|
} else {
|
||||||
$rf = new RepeatForm($this->out, $this->notice);
|
$rf = new RepeatForm($this->out, $this->notice);
|
||||||
$rf->show();
|
$rf->show();
|
||||||
|
@ -120,7 +120,7 @@ class ProfileFormAction extends Action
|
|||||||
if ($action) {
|
if ($action) {
|
||||||
common_redirect(common_local_url($action, $args), 303);
|
common_redirect(common_local_url($action, $args), 303);
|
||||||
} else {
|
} else {
|
||||||
$this->clientError(_("No return-to arguments"));
|
$this->clientError(_("No return-to arguments."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,6 +134,6 @@ class ProfileFormAction extends Action
|
|||||||
|
|
||||||
function handlePost()
|
function handlePost()
|
||||||
{
|
{
|
||||||
$this->serverError(_("unimplemented method"));
|
$this->serverError(_("Unimplemented method."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ class RepeatForm extends Form
|
|||||||
*/
|
*/
|
||||||
function formLegend()
|
function formLegend()
|
||||||
{
|
{
|
||||||
$this->out->element('legend', null, _('Repeat this notice'));
|
$this->out->element('legend', null, _('Repeat this notice?'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -129,7 +129,7 @@ class RepeatForm extends Form
|
|||||||
function formActions()
|
function formActions()
|
||||||
{
|
{
|
||||||
$this->out->submit('repeat-submit-' . $this->notice->id,
|
$this->out->submit('repeat-submit-' . $this->notice->id,
|
||||||
_('Repeat'), 'submit', null, _('Repeat this notice'));
|
_('Yes'), 'submit', null, _('Repeat this notice'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -283,12 +283,13 @@ class Router
|
|||||||
array('action' => 'ApiTimelineFriends',
|
array('action' => 'ApiTimelineFriends',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => '[a-zA-Z0-9]+',
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/home_timeline.:format',
|
$m->connect('api/statuses/home_timeline.:format',
|
||||||
array('action' => 'ApiTimelineFriends',
|
array('action' => 'ApiTimelineHome',
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
$m->connect('api/statuses/home_timeline/:id.:format',
|
$m->connect('api/statuses/home_timeline/:id.:format',
|
||||||
array('action' => 'ApiTimelineFriends',
|
array('action' => 'ApiTimelineHome',
|
||||||
'id' => '[a-zA-Z0-9]+',
|
'id' => '[a-zA-Z0-9]+',
|
||||||
'format' => '(xml|json|rss|atom)'));
|
'format' => '(xml|json|rss|atom)'));
|
||||||
|
|
||||||
|
45
lib/util.php
45
lib/util.php
@ -91,9 +91,17 @@ function common_language()
|
|||||||
if (_have_config() && common_logged_in()) {
|
if (_have_config() && common_logged_in()) {
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
$user_language = $user->language;
|
$user_language = $user->language;
|
||||||
if ($user_language)
|
|
||||||
|
if ($user->language) {
|
||||||
|
// Validate -- we don't want to end up with a bogus code
|
||||||
|
// left over from some old junk.
|
||||||
|
foreach (common_config('site', 'languages') as $code => $info) {
|
||||||
|
if ($info['lang'] == $user_language) {
|
||||||
return $user_language;
|
return $user_language;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, find the best match for the languages requested by the
|
// Otherwise, find the best match for the languages requested by the
|
||||||
// user's browser...
|
// user's browser...
|
||||||
@ -523,8 +531,11 @@ function callback_helper($matches, $callback, $notice_id) {
|
|||||||
return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
|
return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version_compare(PHP_VERSION, '5.3.0', 'ge')) {
|
||||||
|
// lambda implementation in a separate file; PHP 5.2 won't parse it.
|
||||||
|
require_once INSTALLDIR . "/lib/curry.php";
|
||||||
|
} else {
|
||||||
function curry($fn) {
|
function curry($fn) {
|
||||||
//TODO switch to a PHP 5.3 function closure based approach if PHP 5.3 is used
|
|
||||||
$args = func_get_args();
|
$args = func_get_args();
|
||||||
array_shift($args);
|
array_shift($args);
|
||||||
$id = uniqid('_partial');
|
$id = uniqid('_partial');
|
||||||
@ -537,6 +548,7 @@ function curry($fn) {
|
|||||||
'$args,'.
|
'$args,'.
|
||||||
'$GLOBALS["'.$id.'"][1]));');
|
'$GLOBALS["'.$id.'"][1]));');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function common_linkify($url) {
|
function common_linkify($url) {
|
||||||
// It comes in special'd, so we unspecial it before passing to the stringifying
|
// It comes in special'd, so we unspecial it before passing to the stringifying
|
||||||
@ -1240,8 +1252,12 @@ function common_copy_args($from)
|
|||||||
return $to;
|
return $to;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neutralise the evil effects of magic_quotes_gpc in the current request.
|
/**
|
||||||
// This is used before handing a request off to OAuthRequest::from_request.
|
* Neutralise the evil effects of magic_quotes_gpc in the current request.
|
||||||
|
* This is used before handing a request off to OAuthRequest::from_request.
|
||||||
|
* @fixme Doesn't consider vars other than _POST and _GET?
|
||||||
|
* @fixme Can't be undone and could corrupt data if run twice.
|
||||||
|
*/
|
||||||
function common_remove_magic_from_request()
|
function common_remove_magic_from_request()
|
||||||
{
|
{
|
||||||
if(get_magic_quotes_gpc()) {
|
if(get_magic_quotes_gpc()) {
|
||||||
@ -1443,6 +1459,17 @@ function common_database_tablename($tablename)
|
|||||||
return $tablename;
|
return $tablename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorten a URL with the current user's configured shortening service,
|
||||||
|
* or ur1.ca if configured, or not at all if no shortening is set up.
|
||||||
|
* Length is not considered.
|
||||||
|
*
|
||||||
|
* @param string $long_url
|
||||||
|
* @return string may return the original URL if shortening failed
|
||||||
|
*
|
||||||
|
* @fixme provide a way to specify a particular shortener
|
||||||
|
* @fixme provide a way to specify to use a given user's shortening preferences
|
||||||
|
*/
|
||||||
function common_shorten_url($long_url)
|
function common_shorten_url($long_url)
|
||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
@ -1463,6 +1490,16 @@ function common_shorten_url($long_url)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed array($proxy, $ip) for web requests; proxy may be null
|
||||||
|
* null if not a web request
|
||||||
|
*
|
||||||
|
* @fixme X-Forwarded-For can be chained by multiple proxies;
|
||||||
|
we should parse the list and provide a cleaner array
|
||||||
|
* @fixme X-Forwarded-For can be forged by clients; only use them if trusted
|
||||||
|
* @fixme X_Forwarded_For headers will override X-Forwarded-For read through $_SERVER;
|
||||||
|
* use function to get exact request headers from Apache if possible.
|
||||||
|
*/
|
||||||
function common_client_ip()
|
function common_client_ip()
|
||||||
{
|
{
|
||||||
if (!isset($_SERVER) || !array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
if (!isset($_SERVER) || !array_key_exists('REQUEST_METHOD', $_SERVER)) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
5371
locale/fa/LC_MESSAGES/statusnet.po
Normal file
5371
locale/fa/LC_MESSAGES/statusnet.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
5478
locale/ia/LC_MESSAGES/statusnet.po
Normal file
5478
locale/ia/LC_MESSAGES/statusnet.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
134
plugins/CasAuthentication/CasAuthenticationPlugin.php
Normal file
134
plugins/CasAuthentication/CasAuthenticationPlugin.php
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Plugin to enable Single Sign On via CAS (Central Authentication Service)
|
||||||
|
*
|
||||||
|
* 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 StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We bundle the phpCAS library...
|
||||||
|
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/CAS');
|
||||||
|
|
||||||
|
class CasAuthenticationPlugin extends AuthenticationPlugin
|
||||||
|
{
|
||||||
|
public $server;
|
||||||
|
public $port = 443;
|
||||||
|
public $path = '';
|
||||||
|
|
||||||
|
function checkPassword($username, $password)
|
||||||
|
{
|
||||||
|
global $casTempPassword;
|
||||||
|
return ($casTempPassword == $password);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAutoload($cls)
|
||||||
|
{
|
||||||
|
switch ($cls)
|
||||||
|
{
|
||||||
|
case 'phpCAS':
|
||||||
|
require_once(INSTALLDIR.'/plugins/CasAuthentication/extlib/CAS.php');
|
||||||
|
return false;
|
||||||
|
case 'CasloginAction':
|
||||||
|
require_once(INSTALLDIR.'/plugins/CasAuthentication/' . strtolower(mb_substr($cls, 0, -6)) . '.php');
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return parent::onAutoload($cls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartInitializeRouter($m)
|
||||||
|
{
|
||||||
|
$m->connect('main/cas', array('action' => 'caslogin'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEndLoginGroupNav(&$action)
|
||||||
|
{
|
||||||
|
$action_name = $action->trimmed('action');
|
||||||
|
|
||||||
|
$action->menuItem(common_local_url('caslogin'),
|
||||||
|
_m('CAS'),
|
||||||
|
_m('Login or register with CAS'),
|
||||||
|
$action_name === 'caslogin');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEndShowPageNotice($action)
|
||||||
|
{
|
||||||
|
$name = $action->trimmed('action');
|
||||||
|
|
||||||
|
switch ($name)
|
||||||
|
{
|
||||||
|
case 'login':
|
||||||
|
$instr = '(Have an account with CAS? ' .
|
||||||
|
'Try our [CAS login]'.
|
||||||
|
'(%%action.caslogin%%)!)';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = common_markup_to_html($instr);
|
||||||
|
$action->raw($output);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLoginAction($action, &$login)
|
||||||
|
{
|
||||||
|
switch ($action)
|
||||||
|
{
|
||||||
|
case 'caslogin':
|
||||||
|
$login = true;
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInitializePlugin(){
|
||||||
|
parent::onInitializePlugin();
|
||||||
|
if(!isset($this->server)){
|
||||||
|
throw new Exception("must specify a server");
|
||||||
|
}
|
||||||
|
if(!isset($this->port)){
|
||||||
|
throw new Exception("must specify a port");
|
||||||
|
}
|
||||||
|
if(!isset($this->path)){
|
||||||
|
throw new Exception("must specify a path");
|
||||||
|
}
|
||||||
|
//These values need to be accessible to a action object
|
||||||
|
//I can't think of any other way than global variables
|
||||||
|
//to allow the action instance to be able to see values :-(
|
||||||
|
global $casSettings;
|
||||||
|
$casSettings = array();
|
||||||
|
$casSettings['server']=$this->server;
|
||||||
|
$casSettings['port']=$this->port;
|
||||||
|
$casSettings['path']=$this->path;
|
||||||
|
}
|
||||||
|
}
|
38
plugins/CasAuthentication/README
Normal file
38
plugins/CasAuthentication/README
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
The CAS Authentication plugin allows for StatusNet to handle authentication
|
||||||
|
through CAS (Central Authentication Service).
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
add "addPlugin('casAuthentication',
|
||||||
|
array('setting'=>'value', 'setting2'=>'value2', ...);"
|
||||||
|
to the bottom of your config.php
|
||||||
|
|
||||||
|
Settings
|
||||||
|
========
|
||||||
|
provider_name*: a unique name for this authentication provider.
|
||||||
|
authoritative (false): Set to true if CAS's responses are authoritative
|
||||||
|
(if authorative and CAS fails, no other password checking will be done).
|
||||||
|
autoregistration (false): Set to true if users should be automatically created
|
||||||
|
when they attempt to login.
|
||||||
|
email_changeable (true): Are users allowed to change their email address?
|
||||||
|
(true or false)
|
||||||
|
password_changeable*: must be set to false. This plugin does not support changing passwords.
|
||||||
|
|
||||||
|
server*: CAS server to authentication against
|
||||||
|
port (443): Port the CAS server listens on. Almost always 443
|
||||||
|
path (): Path on the server to CAS. Usually blank.
|
||||||
|
|
||||||
|
* required
|
||||||
|
default values are in (parenthesis)
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
addPlugin('casAuthentication', array(
|
||||||
|
'provider_name'=>'Example',
|
||||||
|
'authoritative'=>true,
|
||||||
|
'autoregistration'=>true,
|
||||||
|
'server'=>'sso-cas.univ-rennes1.fr',
|
||||||
|
'port'=>443,
|
||||||
|
'path'=>''
|
||||||
|
));
|
||||||
|
|
66
plugins/CasAuthentication/caslogin.php
Normal file
66
plugins/CasAuthentication/caslogin.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||||
|
|
||||||
|
class CasloginAction extends Action
|
||||||
|
{
|
||||||
|
function handle($args)
|
||||||
|
{
|
||||||
|
parent::handle($args);
|
||||||
|
if (common_is_real_login()) {
|
||||||
|
$this->clientError(_m('Already logged in.'));
|
||||||
|
} else {
|
||||||
|
global $casSettings;
|
||||||
|
phpCAS::client(CAS_VERSION_2_0,$casSettings['server'],$casSettings['port'],$casSettings['path']);
|
||||||
|
phpCAS::setNoCasServerValidation();
|
||||||
|
phpCAS::handleLogoutRequests();
|
||||||
|
phpCAS::forceAuthentication();
|
||||||
|
global $casTempPassword;
|
||||||
|
$casTempPassword = common_good_rand(16);
|
||||||
|
$user = common_check_user(phpCAS::getUser(), $casTempPassword);
|
||||||
|
if (!$user) {
|
||||||
|
$this->serverError(_('Incorrect username or password.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// success!
|
||||||
|
if (!common_set_user($user)) {
|
||||||
|
$this->serverError(_('Error setting user. You are probably not authorized.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_real_login(true);
|
||||||
|
|
||||||
|
$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' =>
|
||||||
|
$user->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
common_redirect($url, 303);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1471
plugins/CasAuthentication/extlib/CAS.php
Normal file
1471
plugins/CasAuthentication/extlib/CAS.php
Normal file
File diff suppressed because it is too large
Load Diff
190
plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-db.php
Normal file
190
plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-db.php
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file CAS/PGTStorage/pgt-db.php
|
||||||
|
* Basic class for PGT database storage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PGTStorageDB
|
||||||
|
* The PGTStorageDB class is a class for PGT database storage. An instance of
|
||||||
|
* this class is returned by CASClient::SetPGTStorageDB().
|
||||||
|
*
|
||||||
|
* @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
|
||||||
|
*
|
||||||
|
* @ingroup internalPGTStorageDB
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PGTStorageDB extends PGTStorage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @addtogroup internalPGTStorageDB
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a string representing a PEAR DB URL to connect to the database. Written by
|
||||||
|
* PGTStorageDB::PGTStorageDB(), read by getURL().
|
||||||
|
*
|
||||||
|
* @hideinitializer
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var $_url='';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the PEAR DB URL to use to connect to the database.
|
||||||
|
*
|
||||||
|
* @return a PEAR DB URL
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getURL()
|
||||||
|
{
|
||||||
|
return $this->_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The handle of the connection to the database where PGT's are stored. Written by
|
||||||
|
* PGTStorageDB::init(), read by getLink().
|
||||||
|
*
|
||||||
|
* @hideinitializer
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var $_link = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the handle of the connection to the database where PGT's are
|
||||||
|
* stored.
|
||||||
|
*
|
||||||
|
* @return a handle of connection.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getLink()
|
||||||
|
{
|
||||||
|
return $this->_link;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the table where PGT's are stored. Written by
|
||||||
|
* PGTStorageDB::PGTStorageDB(), read by getTable().
|
||||||
|
*
|
||||||
|
* @hideinitializer
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var $_table = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the name of the table where PGT's are stored.
|
||||||
|
*
|
||||||
|
* @return the name of a table.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getTable()
|
||||||
|
{
|
||||||
|
return $this->_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// DEBUGGING
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an informational string giving the type of storage
|
||||||
|
* used by the object (used for debugging purposes).
|
||||||
|
*
|
||||||
|
* @return an informational string.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function getStorageType()
|
||||||
|
{
|
||||||
|
return "database";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an informational string giving informations on the
|
||||||
|
* parameters of the storage.(used for debugging purposes).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function getStorageInfo()
|
||||||
|
{
|
||||||
|
return 'url=`'.$this->getURL().'\', table=`'.$this->getTable().'\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// CONSTRUCTOR
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class constructor, called by CASClient::SetPGTStorageDB().
|
||||||
|
*
|
||||||
|
* @param $cas_parent the CASClient instance that creates the object.
|
||||||
|
* @param $user the user to access the data with
|
||||||
|
* @param $password the user's password
|
||||||
|
* @param $database_type the type of the database hosting the data
|
||||||
|
* @param $hostname the server hosting the database
|
||||||
|
* @param $port the port the server is listening on
|
||||||
|
* @param $database the name of the database
|
||||||
|
* @param $table the name of the table storing the data
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function PGTStorageDB($cas_parent,$user,$password,$database_type,$hostname,$port,$database,$table)
|
||||||
|
{
|
||||||
|
phpCAS::traceBegin();
|
||||||
|
|
||||||
|
// call the ancestor's constructor
|
||||||
|
$this->PGTStorage($cas_parent);
|
||||||
|
|
||||||
|
if ( empty($database_type) ) $database_type = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE;
|
||||||
|
if ( empty($hostname) ) $hostname = CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME;
|
||||||
|
if ( $port==0 ) $port = CAS_PGT_STORAGE_DB_DEFAULT_PORT;
|
||||||
|
if ( empty($database) ) $database = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE;
|
||||||
|
if ( empty($table) ) $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE;
|
||||||
|
|
||||||
|
// build and store the PEAR DB URL
|
||||||
|
$this->_url = $database_type.':'.'//'.$user.':'.$password.'@'.$hostname.':'.$port.'/'.$database;
|
||||||
|
|
||||||
|
// XXX should use setURL and setTable
|
||||||
|
phpCAS::traceEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// INITIALIZATION
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is used to initialize the storage. Halts on error.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
phpCAS::traceBegin();
|
||||||
|
// if the storage has already been initialized, return immediatly
|
||||||
|
if ( $this->isInitialized() )
|
||||||
|
return;
|
||||||
|
// call the ancestor's method (mark as initialized)
|
||||||
|
parent::init();
|
||||||
|
|
||||||
|
//include phpDB library (the test was introduced in release 0.4.8 for
|
||||||
|
//the integration into Tikiwiki).
|
||||||
|
if (!class_exists('DB')) {
|
||||||
|
include_once('DB.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to connect to the database
|
||||||
|
$this->_link = DB::connect($this->getURL());
|
||||||
|
if ( DB::isError($this->_link) ) {
|
||||||
|
phpCAS::error('could not connect to database ('.DB::errorMessage($this->_link).')');
|
||||||
|
}
|
||||||
|
var_dump($this->_link);
|
||||||
|
phpCAS::traceBEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
249
plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-file.php
Normal file
249
plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-file.php
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file CAS/PGTStorage/pgt-file.php
|
||||||
|
* Basic class for PGT file storage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PGTStorageFile
|
||||||
|
* The PGTStorageFile class is a class for PGT file storage. An instance of
|
||||||
|
* this class is returned by CASClient::SetPGTStorageFile().
|
||||||
|
*
|
||||||
|
* @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
|
||||||
|
*
|
||||||
|
* @ingroup internalPGTStorageFile
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PGTStorageFile extends PGTStorage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @addtogroup internalPGTStorageFile
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a string telling where PGT's should be stored on the filesystem. Written by
|
||||||
|
* PGTStorageFile::PGTStorageFile(), read by getPath().
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var $_path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the name of the directory where PGT's should be stored
|
||||||
|
* on the filesystem.
|
||||||
|
*
|
||||||
|
* @return the name of a directory (with leading and trailing '/')
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getPath()
|
||||||
|
{
|
||||||
|
return $this->_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a string telling the format to use to store PGT's (plain or xml). Written by
|
||||||
|
* PGTStorageFile::PGTStorageFile(), read by getFormat().
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var $_format;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the format to use when storing PGT's on the filesystem.
|
||||||
|
*
|
||||||
|
* @return a string corresponding to the format used (plain or xml).
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getFormat()
|
||||||
|
{
|
||||||
|
return $this->_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// DEBUGGING
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an informational string giving the type of storage
|
||||||
|
* used by the object (used for debugging purposes).
|
||||||
|
*
|
||||||
|
* @return an informational string.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function getStorageType()
|
||||||
|
{
|
||||||
|
return "file";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an informational string giving informations on the
|
||||||
|
* parameters of the storage.(used for debugging purposes).
|
||||||
|
*
|
||||||
|
* @return an informational string.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function getStorageInfo()
|
||||||
|
{
|
||||||
|
return 'path=`'.$this->getPath().'\', format=`'.$this->getFormat().'\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// CONSTRUCTOR
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class constructor, called by CASClient::SetPGTStorageFile().
|
||||||
|
*
|
||||||
|
* @param $cas_parent the CASClient instance that creates the object.
|
||||||
|
* @param $format the format used to store the PGT's (`plain' and `xml' allowed).
|
||||||
|
* @param $path the path where the PGT's should be stored
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function PGTStorageFile($cas_parent,$format,$path)
|
||||||
|
{
|
||||||
|
phpCAS::traceBegin();
|
||||||
|
// call the ancestor's constructor
|
||||||
|
$this->PGTStorage($cas_parent);
|
||||||
|
|
||||||
|
if (empty($format) ) $format = CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT;
|
||||||
|
if (empty($path) ) $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH;
|
||||||
|
|
||||||
|
// check that the path is an absolute path
|
||||||
|
if (getenv("OS")=="Windows_NT"){
|
||||||
|
|
||||||
|
if (!preg_match('`^[a-zA-Z]:`', $path)) {
|
||||||
|
phpCAS::error('an absolute path is needed for PGT storage to file');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( $path[0] != '/' ) {
|
||||||
|
phpCAS::error('an absolute path is needed for PGT storage to file');
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the path (with a leading and trailing '/')
|
||||||
|
$path = preg_replace('|[/]*$|','/',$path);
|
||||||
|
$path = preg_replace('|^[/]*|','/',$path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_path = $path;
|
||||||
|
// check the format and store it
|
||||||
|
switch ($format) {
|
||||||
|
case CAS_PGT_STORAGE_FILE_FORMAT_PLAIN:
|
||||||
|
case CAS_PGT_STORAGE_FILE_FORMAT_XML:
|
||||||
|
$this->_format = $format;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
phpCAS::error('unknown PGT file storage format (`'.CAS_PGT_STORAGE_FILE_FORMAT_PLAIN.'\' and `'.CAS_PGT_STORAGE_FILE_FORMAT_XML.'\' allowed)');
|
||||||
|
}
|
||||||
|
phpCAS::traceEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// INITIALIZATION
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is used to initialize the storage. Halts on error.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
phpCAS::traceBegin();
|
||||||
|
// if the storage has already been initialized, return immediatly
|
||||||
|
if ( $this->isInitialized() )
|
||||||
|
return;
|
||||||
|
// call the ancestor's method (mark as initialized)
|
||||||
|
parent::init();
|
||||||
|
phpCAS::traceEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// PGT I/O
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the filename corresponding to a PGT Iou.
|
||||||
|
*
|
||||||
|
* @param $pgt_iou the PGT iou.
|
||||||
|
*
|
||||||
|
* @return a filename
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getPGTIouFilename($pgt_iou)
|
||||||
|
{
|
||||||
|
phpCAS::traceBegin();
|
||||||
|
$filename = $this->getPath().$pgt_iou.'.'.$this->getFormat();
|
||||||
|
phpCAS::traceEnd($filename);
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method stores a PGT and its corresponding PGT Iou into a file. Echoes a
|
||||||
|
* warning on error.
|
||||||
|
*
|
||||||
|
* @param $pgt the PGT
|
||||||
|
* @param $pgt_iou the PGT iou
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function write($pgt,$pgt_iou)
|
||||||
|
{
|
||||||
|
phpCAS::traceBegin();
|
||||||
|
$fname = $this->getPGTIouFilename($pgt_iou);
|
||||||
|
if ( $f=fopen($fname,"w") ) {
|
||||||
|
if ( fputs($f,$pgt) === FALSE ) {
|
||||||
|
phpCAS::error('could not write PGT to `'.$fname.'\'');
|
||||||
|
}
|
||||||
|
fclose($f);
|
||||||
|
} else {
|
||||||
|
phpCAS::error('could not open `'.$fname.'\'');
|
||||||
|
}
|
||||||
|
phpCAS::traceEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method reads a PGT corresponding to a PGT Iou and deletes the
|
||||||
|
* corresponding file.
|
||||||
|
*
|
||||||
|
* @param $pgt_iou the PGT iou
|
||||||
|
*
|
||||||
|
* @return the corresponding PGT, or FALSE on error
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function read($pgt_iou)
|
||||||
|
{
|
||||||
|
phpCAS::traceBegin();
|
||||||
|
$pgt = FALSE;
|
||||||
|
$fname = $this->getPGTIouFilename($pgt_iou);
|
||||||
|
if ( !($f=fopen($fname,"r")) ) {
|
||||||
|
phpCAS::trace('could not open `'.$fname.'\'');
|
||||||
|
} else {
|
||||||
|
if ( ($pgt=fgets($f)) === FALSE ) {
|
||||||
|
phpCAS::trace('could not read PGT from `'.$fname.'\'');
|
||||||
|
}
|
||||||
|
fclose($f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the PGT file
|
||||||
|
@unlink($fname);
|
||||||
|
|
||||||
|
phpCAS::traceEnd($pgt);
|
||||||
|
return $pgt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
188
plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-main.php
Normal file
188
plugins/CasAuthentication/extlib/CAS/PGTStorage/pgt-main.php
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file CAS/PGTStorage/pgt-main.php
|
||||||
|
* Basic class for PGT storage
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PGTStorage
|
||||||
|
* The PGTStorage class is a generic class for PGT storage. This class should
|
||||||
|
* not be instanciated itself but inherited by specific PGT storage classes.
|
||||||
|
*
|
||||||
|
* @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
|
||||||
|
*
|
||||||
|
* @ingroup internalPGTStorage
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PGTStorage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @addtogroup internalPGTStorage
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// CONSTRUCTOR
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The constructor of the class, should be called only by inherited classes.
|
||||||
|
*
|
||||||
|
* @param $cas_parent the CASclient instance that creates the current object.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
function PGTStorage($cas_parent)
|
||||||
|
{
|
||||||
|
phpCAS::traceBegin();
|
||||||
|
if ( !$cas_parent->isProxy() ) {
|
||||||
|
phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy');
|
||||||
|
}
|
||||||
|
phpCAS::traceEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// DEBUGGING
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This virtual method returns an informational string giving the type of storage
|
||||||
|
* used by the object (used for debugging purposes).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function getStorageType()
|
||||||
|
{
|
||||||
|
phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This virtual method returns an informational string giving informations on the
|
||||||
|
* parameters of the storage.(used for debugging purposes).
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
function getStorageInfo()
|
||||||
|
{
|
||||||
|
phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// ERROR HANDLING
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string used to store an error message. Written by PGTStorage::setErrorMessage(),
|
||||||
|
* read by PGTStorage::getErrorMessage().
|
||||||
|
*
|
||||||
|
* @hideinitializer
|
||||||
|
* @private
|
||||||
|
* @deprecated not used.
|
||||||
|
*/
|
||||||
|
var $_error_message=FALSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets en error message, which can be read later by
|
||||||
|
* PGTStorage::getErrorMessage().
|
||||||
|
*
|
||||||
|
* @param $error_message an error message
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* @deprecated not used.
|
||||||
|
*/
|
||||||
|
function setErrorMessage($error_message)
|
||||||
|
{
|
||||||
|
$this->_error_message = $error_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an error message set by PGTStorage::setErrorMessage().
|
||||||
|
*
|
||||||
|
* @return an error message when set by PGTStorage::setErrorMessage(), FALSE
|
||||||
|
* otherwise.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @deprecated not used.
|
||||||
|
*/
|
||||||
|
function getErrorMessage()
|
||||||
|
{
|
||||||
|
return $this->_error_message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// INITIALIZATION
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a boolean telling if the storage has already been initialized. Written by
|
||||||
|
* PGTStorage::init(), read by PGTStorage::isInitialized().
|
||||||
|
*
|
||||||
|
* @hideinitializer
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
var $_initialized = FALSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method tells if the storage has already been intialized.
|
||||||
|
*
|
||||||
|
* @return a boolean
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
function isInitialized()
|
||||||
|
{
|
||||||
|
return $this->_initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This virtual method initializes the object.
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
$this->_initialized = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ########################################################################
|
||||||
|
// PGT I/O
|
||||||
|
// ########################################################################
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This virtual method stores a PGT and its corresponding PGT Iuo.
|
||||||
|
* @note Should never be called.
|
||||||
|
*
|
||||||
|
* @param $pgt the PGT
|
||||||
|
* @param $pgt_iou the PGT iou
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
function write($pgt,$pgt_iou)
|
||||||
|
{
|
||||||
|
phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This virtual method reads a PGT corresponding to a PGT Iou and deletes
|
||||||
|
* the corresponding storage entry.
|
||||||
|
* @note Should never be called.
|
||||||
|
*
|
||||||
|
* @param $pgt_iou the PGT iou
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
function read($pgt_iou)
|
||||||
|
{
|
||||||
|
phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// include specific PGT storage classes
|
||||||
|
include_once(dirname(__FILE__).'/pgt-file.php');
|
||||||
|
include_once(dirname(__FILE__).'/pgt-db.php');
|
||||||
|
|
||||||
|
?>
|
2297
plugins/CasAuthentication/extlib/CAS/client.php
Normal file
2297
plugins/CasAuthentication/extlib/CAS/client.php
Normal file
File diff suppressed because it is too large
Load Diff
277
plugins/CasAuthentication/extlib/CAS/domxml-php4-php5.php
Normal file
277
plugins/CasAuthentication/extlib/CAS/domxml-php4-php5.php
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @file domxml-php4-php5.php
|
||||||
|
* Require PHP5, uses built-in DOM extension.
|
||||||
|
* To be used in PHP4 scripts using DOMXML extension.
|
||||||
|
* Allows PHP4/DOMXML scripts to run on PHP5/DOM.
|
||||||
|
* (Requires PHP5/XSL extension for domxml_xslt functions)
|
||||||
|
*
|
||||||
|
* Typical use:
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* if (version_compare(PHP_VERSION,'5','>='))
|
||||||
|
* require_once('domxml-php4-to-php5.php');
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Version 1.5.5, 2005-01-18, http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------------<br>
|
||||||
|
* Written by Alexandre Alapetite, http://alexandre.alapetite.net/cv/
|
||||||
|
*
|
||||||
|
* Copyright 2004, Licence: Creative Commons "Attribution-ShareAlike 2.0 France" BY-SA (FR),
|
||||||
|
* http://creativecommons.org/licenses/by-sa/2.0/fr/
|
||||||
|
* http://alexandre.alapetite.net/divers/apropos/#by-sa
|
||||||
|
* - Attribution. You must give the original author credit
|
||||||
|
* - Share Alike. If you alter, transform, or build upon this work,
|
||||||
|
* you may distribute the resulting work only under a license identical to this one
|
||||||
|
* - The French law is authoritative
|
||||||
|
* - Any of these conditions can be waived if you get permission from Alexandre Alapetite
|
||||||
|
* - Please send to Alexandre Alapetite the modifications you make,
|
||||||
|
* in order to improve this file for the benefit of everybody
|
||||||
|
*
|
||||||
|
* If you want to distribute this code, please do it as a link to:
|
||||||
|
* http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/
|
||||||
|
*/
|
||||||
|
|
||||||
|
function domxml_new_doc($version) {return new php4DOMDocument('');}
|
||||||
|
function domxml_open_file($filename) {return new php4DOMDocument($filename);}
|
||||||
|
function domxml_open_mem($str)
|
||||||
|
{
|
||||||
|
$dom=new php4DOMDocument('');
|
||||||
|
$dom->myDOMNode->loadXML($str);
|
||||||
|
return $dom;
|
||||||
|
}
|
||||||
|
function xpath_eval($xpath_context,$eval_str,$contextnode=null) {return $xpath_context->query($eval_str,$contextnode);}
|
||||||
|
function xpath_new_context($dom_document) {return new php4DOMXPath($dom_document);}
|
||||||
|
|
||||||
|
class php4DOMAttr extends php4DOMNode
|
||||||
|
{
|
||||||
|
function php4DOMAttr($aDOMAttr) {$this->myDOMNode=$aDOMAttr;}
|
||||||
|
function Name() {return $this->myDOMNode->name;}
|
||||||
|
function Specified() {return $this->myDOMNode->specified;}
|
||||||
|
function Value() {return $this->myDOMNode->value;}
|
||||||
|
}
|
||||||
|
|
||||||
|
class php4DOMDocument extends php4DOMNode
|
||||||
|
{
|
||||||
|
function php4DOMDocument($filename='')
|
||||||
|
{
|
||||||
|
$this->myDOMNode=new DOMDocument();
|
||||||
|
if ($filename!='') $this->myDOMNode->load($filename);
|
||||||
|
}
|
||||||
|
function create_attribute($name,$value)
|
||||||
|
{
|
||||||
|
$myAttr=$this->myDOMNode->createAttribute($name);
|
||||||
|
$myAttr->value=$value;
|
||||||
|
return new php4DOMAttr($myAttr,$this);
|
||||||
|
}
|
||||||
|
function create_cdata_section($content) {return new php4DOMNode($this->myDOMNode->createCDATASection($content),$this);}
|
||||||
|
function create_comment($data) {return new php4DOMNode($this->myDOMNode->createComment($data),$this);}
|
||||||
|
function create_element($name) {return new php4DOMElement($this->myDOMNode->createElement($name),$this);}
|
||||||
|
function create_text_node($content) {return new php4DOMNode($this->myDOMNode->createTextNode($content),$this);}
|
||||||
|
function document_element() {return new php4DOMElement($this->myDOMNode->documentElement,$this);}
|
||||||
|
function dump_file($filename,$compressionmode=false,$format=false) {return $this->myDOMNode->save($filename);}
|
||||||
|
function dump_mem($format=false,$encoding=false) {return $this->myDOMNode->saveXML();}
|
||||||
|
function get_element_by_id($id) {return new php4DOMElement($this->myDOMNode->getElementById($id),$this);}
|
||||||
|
function get_elements_by_tagname($name)
|
||||||
|
{
|
||||||
|
$myDOMNodeList=$this->myDOMNode->getElementsByTagName($name);
|
||||||
|
$nodeSet=array();
|
||||||
|
$i=0;
|
||||||
|
if (isset($myDOMNodeList))
|
||||||
|
while ($node=$myDOMNodeList->item($i))
|
||||||
|
{
|
||||||
|
$nodeSet[]=new php4DOMElement($node,$this);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return $nodeSet;
|
||||||
|
}
|
||||||
|
function html_dump_mem() {return $this->myDOMNode->saveHTML();}
|
||||||
|
function root() {return new php4DOMElement($this->myDOMNode->documentElement,$this);}
|
||||||
|
}
|
||||||
|
|
||||||
|
class php4DOMElement extends php4DOMNode
|
||||||
|
{
|
||||||
|
function get_attribute($name) {return $this->myDOMNode->getAttribute($name);}
|
||||||
|
function get_elements_by_tagname($name)
|
||||||
|
{
|
||||||
|
$myDOMNodeList=$this->myDOMNode->getElementsByTagName($name);
|
||||||
|
$nodeSet=array();
|
||||||
|
$i=0;
|
||||||
|
if (isset($myDOMNodeList))
|
||||||
|
while ($node=$myDOMNodeList->item($i))
|
||||||
|
{
|
||||||
|
$nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return $nodeSet;
|
||||||
|
}
|
||||||
|
function has_attribute($name) {return $this->myDOMNode->hasAttribute($name);}
|
||||||
|
function remove_attribute($name) {return $this->myDOMNode->removeAttribute($name);}
|
||||||
|
function set_attribute($name,$value) {return $this->myDOMNode->setAttribute($name,$value);}
|
||||||
|
function tagname() {return $this->myDOMNode->tagName;}
|
||||||
|
}
|
||||||
|
|
||||||
|
class php4DOMNode
|
||||||
|
{
|
||||||
|
var $myDOMNode;
|
||||||
|
var $myOwnerDocument;
|
||||||
|
function php4DOMNode($aDomNode,$aOwnerDocument)
|
||||||
|
{
|
||||||
|
$this->myDOMNode=$aDomNode;
|
||||||
|
$this->myOwnerDocument=$aOwnerDocument;
|
||||||
|
}
|
||||||
|
function __get($name)
|
||||||
|
{
|
||||||
|
if ($name=='type') return $this->myDOMNode->nodeType;
|
||||||
|
elseif ($name=='tagname') return $this->myDOMNode->tagName;
|
||||||
|
elseif ($name=='content') return $this->myDOMNode->textContent;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$myErrors=debug_backtrace();
|
||||||
|
trigger_error('Undefined property: '.get_class($this).'::$'.$name.' ['.$myErrors[0]['file'].':'.$myErrors[0]['line'].']',E_USER_NOTICE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function append_child($newnode) {return new php4DOMElement($this->myDOMNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);}
|
||||||
|
function append_sibling($newnode) {return new php4DOMElement($this->myDOMNode->parentNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);}
|
||||||
|
function attributes()
|
||||||
|
{
|
||||||
|
$myDOMNodeList=$this->myDOMNode->attributes;
|
||||||
|
$nodeSet=array();
|
||||||
|
$i=0;
|
||||||
|
if (isset($myDOMNodeList))
|
||||||
|
while ($node=$myDOMNodeList->item($i))
|
||||||
|
{
|
||||||
|
$nodeSet[]=new php4DOMAttr($node,$this->myOwnerDocument);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return $nodeSet;
|
||||||
|
}
|
||||||
|
function child_nodes()
|
||||||
|
{
|
||||||
|
$myDOMNodeList=$this->myDOMNode->childNodes;
|
||||||
|
$nodeSet=array();
|
||||||
|
$i=0;
|
||||||
|
if (isset($myDOMNodeList))
|
||||||
|
while ($node=$myDOMNodeList->item($i))
|
||||||
|
{
|
||||||
|
$nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return $nodeSet;
|
||||||
|
}
|
||||||
|
function children() {return $this->child_nodes();}
|
||||||
|
function clone_node($deep=false) {return new php4DOMElement($this->myDOMNode->cloneNode($deep),$this->myOwnerDocument);}
|
||||||
|
function first_child() {return new php4DOMElement($this->myDOMNode->firstChild,$this->myOwnerDocument);}
|
||||||
|
function get_content() {return $this->myDOMNode->textContent;}
|
||||||
|
function has_attributes() {return $this->myDOMNode->hasAttributes();}
|
||||||
|
function has_child_nodes() {return $this->myDOMNode->hasChildNodes();}
|
||||||
|
function insert_before($newnode,$refnode) {return new php4DOMElement($this->myDOMNode->insertBefore($newnode->myDOMNode,$refnode->myDOMNode),$this->myOwnerDocument);}
|
||||||
|
function is_blank_node()
|
||||||
|
{
|
||||||
|
$myDOMNodeList=$this->myDOMNode->childNodes;
|
||||||
|
$i=0;
|
||||||
|
if (isset($myDOMNodeList))
|
||||||
|
while ($node=$myDOMNodeList->item($i))
|
||||||
|
{
|
||||||
|
if (($node->nodeType==XML_ELEMENT_NODE)||
|
||||||
|
(($node->nodeType==XML_TEXT_NODE)&&!ereg('^([[:cntrl:]]|[[:space:]])*$',$node->nodeValue)))
|
||||||
|
return false;
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function last_child() {return new php4DOMElement($this->myDOMNode->lastChild,$this->myOwnerDocument);}
|
||||||
|
function new_child($name,$content)
|
||||||
|
{
|
||||||
|
$mySubNode=$this->myDOMNode->ownerDocument->createElement($name);
|
||||||
|
$mySubNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($content));
|
||||||
|
$this->myDOMNode->appendChild($mySubNode);
|
||||||
|
return new php4DOMElement($mySubNode,$this->myOwnerDocument);
|
||||||
|
}
|
||||||
|
function next_sibling() {return new php4DOMElement($this->myDOMNode->nextSibling,$this->myOwnerDocument);}
|
||||||
|
function node_name() {return $this->myDOMNode->localName;}
|
||||||
|
function node_type() {return $this->myDOMNode->nodeType;}
|
||||||
|
function node_value() {return $this->myDOMNode->nodeValue;}
|
||||||
|
function owner_document() {return $this->myOwnerDocument;}
|
||||||
|
function parent_node() {return new php4DOMElement($this->myDOMNode->parentNode,$this->myOwnerDocument);}
|
||||||
|
function prefix() {return $this->myDOMNode->prefix;}
|
||||||
|
function previous_sibling() {return new php4DOMElement($this->myDOMNode->previousSibling,$this->myOwnerDocument);}
|
||||||
|
function remove_child($oldchild) {return new php4DOMElement($this->myDOMNode->removeChild($oldchild->myDOMNode),$this->myOwnerDocument);}
|
||||||
|
function replace_child($oldnode,$newnode) {return new php4DOMElement($this->myDOMNode->replaceChild($oldnode->myDOMNode,$newnode->myDOMNode),$this->myOwnerDocument);}
|
||||||
|
function set_content($text)
|
||||||
|
{
|
||||||
|
if (($this->myDOMNode->hasChildNodes())&&($this->myDOMNode->firstChild->nodeType==XML_TEXT_NODE))
|
||||||
|
$this->myDOMNode->removeChild($this->myDOMNode->firstChild);
|
||||||
|
return $this->myDOMNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class php4DOMNodelist
|
||||||
|
{
|
||||||
|
var $myDOMNodelist;
|
||||||
|
var $nodeset;
|
||||||
|
function php4DOMNodelist($aDOMNodelist,$aOwnerDocument)
|
||||||
|
{
|
||||||
|
$this->myDOMNodelist=$aDOMNodelist;
|
||||||
|
$this->nodeset=array();
|
||||||
|
$i=0;
|
||||||
|
if (isset($this->myDOMNodelist))
|
||||||
|
while ($node=$this->myDOMNodelist->item($i))
|
||||||
|
{
|
||||||
|
$this->nodeset[]=new php4DOMElement($node,$aOwnerDocument);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class php4DOMXPath
|
||||||
|
{
|
||||||
|
var $myDOMXPath;
|
||||||
|
var $myOwnerDocument;
|
||||||
|
function php4DOMXPath($dom_document)
|
||||||
|
{
|
||||||
|
$this->myOwnerDocument=$dom_document;
|
||||||
|
$this->myDOMXPath=new DOMXPath($dom_document->myDOMNode);
|
||||||
|
}
|
||||||
|
function query($eval_str,$contextnode)
|
||||||
|
{
|
||||||
|
if (isset($contextnode)) return new php4DOMNodelist($this->myDOMXPath->query($eval_str,$contextnode->myDOMNode),$this->myOwnerDocument);
|
||||||
|
else return new php4DOMNodelist($this->myDOMXPath->query($eval_str),$this->myOwnerDocument);
|
||||||
|
}
|
||||||
|
function xpath_register_ns($prefix,$namespaceURI) {return $this->myDOMXPath->registerNamespace($prefix,$namespaceURI);}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extension_loaded('xsl'))
|
||||||
|
{//See also: http://alexandre.alapetite.net/doc-alex/xslt-php4-php5/
|
||||||
|
function domxml_xslt_stylesheet($xslstring) {return new php4DomXsltStylesheet(DOMDocument::loadXML($xslstring));}
|
||||||
|
function domxml_xslt_stylesheet_doc($dom_document) {return new php4DomXsltStylesheet($dom_document);}
|
||||||
|
function domxml_xslt_stylesheet_file($xslfile) {return new php4DomXsltStylesheet(DOMDocument::load($xslfile));}
|
||||||
|
class php4DomXsltStylesheet
|
||||||
|
{
|
||||||
|
var $myxsltProcessor;
|
||||||
|
function php4DomXsltStylesheet($dom_document)
|
||||||
|
{
|
||||||
|
$this->myxsltProcessor=new xsltProcessor();
|
||||||
|
$this->myxsltProcessor->importStyleSheet($dom_document);
|
||||||
|
}
|
||||||
|
function process($dom_document,$xslt_parameters=array(),$param_is_xpath=false)
|
||||||
|
{
|
||||||
|
foreach ($xslt_parameters as $param=>$value)
|
||||||
|
$this->myxsltProcessor->setParameter('',$param,$value);
|
||||||
|
$myphp4DOMDocument=new php4DOMDocument();
|
||||||
|
$myphp4DOMDocument->myDOMNode=$this->myxsltProcessor->transformToDoc($dom_document->myDOMNode);
|
||||||
|
return $myphp4DOMDocument;
|
||||||
|
}
|
||||||
|
function result_dump_file($dom_document,$filename)
|
||||||
|
{
|
||||||
|
$html=$dom_document->myDOMNode->saveHTML();
|
||||||
|
file_put_contents($filename,$html);
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
function result_dump_mem($dom_document) {return $dom_document->myDOMNode->saveHTML();}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
27
plugins/CasAuthentication/extlib/CAS/languages/catalan.php
Normal file
27
plugins/CasAuthentication/extlib/CAS/languages/catalan.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file languages/spanish.php
|
||||||
|
* @author Iván-Benjamín García Torà <ivaniclixx AT gmail DOT com>
|
||||||
|
* @sa @link internalLang Internationalization @endlink
|
||||||
|
* @ingroup internalLang
|
||||||
|
*/
|
||||||
|
|
||||||
|
$this->_strings = array(
|
||||||
|
CAS_STR_USING_SERVER
|
||||||
|
=> 'usant servidor',
|
||||||
|
CAS_STR_AUTHENTICATION_WANTED
|
||||||
|
=> 'Autentificació CAS necessària!',
|
||||||
|
CAS_STR_LOGOUT
|
||||||
|
=> 'Sortida de CAS necessària!',
|
||||||
|
CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
|
||||||
|
=> 'Ja hauria d\ haver estat redireccionat al servidor CAS. Feu click <a href="%s">aquí</a> per a continuar.',
|
||||||
|
CAS_STR_AUTHENTICATION_FAILED
|
||||||
|
=> 'Autentificació CAS fallida!',
|
||||||
|
CAS_STR_YOU_WERE_NOT_AUTHENTICATED
|
||||||
|
=> '<p>No estàs autentificat.</p><p>Pots tornar a intentar-ho fent click <a href="%s">aquí</a>.</p><p>Si el problema persisteix hauría de contactar amb l\'<a href="mailto:%s">administrador d\'aquest llocc</a>.</p>',
|
||||||
|
CAS_STR_SERVICE_UNAVAILABLE
|
||||||
|
=> 'El servei `<b>%s</b>\' no està disponible (<b>%s</b>).'
|
||||||
|
);
|
||||||
|
|
||||||
|
?>
|
27
plugins/CasAuthentication/extlib/CAS/languages/english.php
Normal file
27
plugins/CasAuthentication/extlib/CAS/languages/english.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file languages/english.php
|
||||||
|
* @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
|
||||||
|
* @sa @link internalLang Internationalization @endlink
|
||||||
|
* @ingroup internalLang
|
||||||
|
*/
|
||||||
|
|
||||||
|
$this->_strings = array(
|
||||||
|
CAS_STR_USING_SERVER
|
||||||
|
=> 'using server',
|
||||||
|
CAS_STR_AUTHENTICATION_WANTED
|
||||||
|
=> 'CAS Authentication wanted!',
|
||||||
|
CAS_STR_LOGOUT
|
||||||
|
=> 'CAS logout wanted!',
|
||||||
|
CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
|
||||||
|
=> 'You should already have been redirected to the CAS server. Click <a href="%s">here</a> to continue.',
|
||||||
|
CAS_STR_AUTHENTICATION_FAILED
|
||||||
|
=> 'CAS Authentication failed!',
|
||||||
|
CAS_STR_YOU_WERE_NOT_AUTHENTICATED
|
||||||
|
=> '<p>You were not authenticated.</p><p>You may submit your request again by clicking <a href="%s">here</a>.</p><p>If the problem persists, you may contact <a href="mailto:%s">the administrator of this site</a>.</p>',
|
||||||
|
CAS_STR_SERVICE_UNAVAILABLE
|
||||||
|
=> 'The service `<b>%s</b>\' is not available (<b>%s</b>).'
|
||||||
|
);
|
||||||
|
|
||||||
|
?>
|
28
plugins/CasAuthentication/extlib/CAS/languages/french.php
Normal file
28
plugins/CasAuthentication/extlib/CAS/languages/french.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file languages/english.php
|
||||||
|
* @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
|
||||||
|
* @sa @link internalLang Internationalization @endlink
|
||||||
|
* @ingroup internalLang
|
||||||
|
*/
|
||||||
|
|
||||||
|
$this->_strings = array(
|
||||||
|
CAS_STR_USING_SERVER
|
||||||
|
=> 'utilisant le serveur',
|
||||||
|
CAS_STR_AUTHENTICATION_WANTED
|
||||||
|
=> 'Authentication CAS nécessaire !',
|
||||||
|
CAS_STR_LOGOUT
|
||||||
|
=> 'Déconnexion demandée !',
|
||||||
|
CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
|
||||||
|
=> 'Vous auriez du etre redirigé(e) vers le serveur CAS. Cliquez <a href="%s">ici</a> pour continuer.',
|
||||||
|
CAS_STR_AUTHENTICATION_FAILED
|
||||||
|
=> 'Authentification CAS infructueuse !',
|
||||||
|
CAS_STR_YOU_WERE_NOT_AUTHENTICATED
|
||||||
|
=> '<p>Vous n\'avez pas été authentifié(e).</p><p>Vous pouvez soumettre votre requete à nouveau en cliquant <a href="%s">ici</a>.</p><p>Si le problème persiste, vous pouvez contacter <a href="mailto:%s">l\'administrateur de ce site</a>.</p>',
|
||||||
|
CAS_STR_SERVICE_UNAVAILABLE
|
||||||
|
=> 'Le service `<b>%s</b>\' est indisponible (<b>%s</b>)'
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
?>
|
27
plugins/CasAuthentication/extlib/CAS/languages/german.php
Normal file
27
plugins/CasAuthentication/extlib/CAS/languages/german.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file languages/german.php
|
||||||
|
* @author Henrik Genssen <hg at mediafactory.de>
|
||||||
|
* @sa @link internalLang Internationalization @endlink
|
||||||
|
* @ingroup internalLang
|
||||||
|
*/
|
||||||
|
|
||||||
|
$this->_strings = array(
|
||||||
|
CAS_STR_USING_SERVER
|
||||||
|
=> 'via Server',
|
||||||
|
CAS_STR_AUTHENTICATION_WANTED
|
||||||
|
=> 'CAS Authentifizierung erforderlich!',
|
||||||
|
CAS_STR_LOGOUT
|
||||||
|
=> 'CAS Abmeldung!',
|
||||||
|
CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
|
||||||
|
=> 'eigentlich häten Sie zum CAS Server weitergeleitet werden sollen. Drücken Sie <a href="%s">hier</a> um fortzufahren.',
|
||||||
|
CAS_STR_AUTHENTICATION_FAILED
|
||||||
|
=> 'CAS Anmeldung fehlgeschlagen!',
|
||||||
|
CAS_STR_YOU_WERE_NOT_AUTHENTICATED
|
||||||
|
=> '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href="%s">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontkatieren Sie den <a href="mailto:%s">Administrator</a> dieser Seite.</p>',
|
||||||
|
CAS_STR_SERVICE_UNAVAILABLE
|
||||||
|
=> 'Der Dienst `<b>%s</b>\' ist nicht verfügbar (<b>%s</b>).'
|
||||||
|
);
|
||||||
|
|
||||||
|
?>
|
27
plugins/CasAuthentication/extlib/CAS/languages/greek.php
Normal file
27
plugins/CasAuthentication/extlib/CAS/languages/greek.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file languages/greek.php
|
||||||
|
* @author Vangelis Haniotakis <haniotak at ucnet.uoc.gr>
|
||||||
|
* @sa @link internalLang Internationalization @endlink
|
||||||
|
* @ingroup internalLang
|
||||||
|
*/
|
||||||
|
|
||||||
|
$this->_strings = array(
|
||||||
|
CAS_STR_USING_SERVER
|
||||||
|
=> '÷ñçóéìïðïéåßôáé ï åîõðçñåôçôÞò',
|
||||||
|
CAS_STR_AUTHENTICATION_WANTED
|
||||||
|
=> 'Áðáéôåßôáé ç ôáõôïðïßçóç CAS!',
|
||||||
|
CAS_STR_LOGOUT
|
||||||
|
=> 'Áðáéôåßôáé ç áðïóýíäåóç áðü CAS!',
|
||||||
|
CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
|
||||||
|
=> 'Èá Ýðñåðå íá åß÷áôå áíáêáôåõèõíèåß óôïí åîõðçñåôçôÞ CAS. ÊÜíôå êëßê <a href="%s">åäþ</a> ãéá íá óõíå÷ßóåôå.',
|
||||||
|
CAS_STR_AUTHENTICATION_FAILED
|
||||||
|
=> 'Ç ôáõôïðïßçóç CAS áðÝôõ÷å!',
|
||||||
|
CAS_STR_YOU_WERE_NOT_AUTHENTICATED
|
||||||
|
=> '<p>Äåí ôáõôïðïéçèÞêáôå.</p><p>Ìðïñåßôå íá îáíáðñïóðáèÞóåôå, êÜíïíôáò êëßê <a href="%s">åäþ</a>.</p><p>Åáí ôï ðñüâëçìá åðéìåßíåé, åëÜôå óå åðáöÞ ìå ôïí <a href="mailto:%s">äéá÷åéñéóôÞ</a>.</p>',
|
||||||
|
CAS_STR_SERVICE_UNAVAILABLE
|
||||||
|
=> 'Ç õðçñåóßá `<b>%s</b>\' äåí åßíáé äéáèÝóéìç (<b>%s</b>).'
|
||||||
|
);
|
||||||
|
|
||||||
|
?>
|
27
plugins/CasAuthentication/extlib/CAS/languages/japanese.php
Normal file
27
plugins/CasAuthentication/extlib/CAS/languages/japanese.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file languages/japanese.php
|
||||||
|
* @author fnorif (fnorif@yahoo.co.jp)
|
||||||
|
*
|
||||||
|
* Now Encoding is EUC-JP and LF
|
||||||
|
**/
|
||||||
|
|
||||||
|
$this->_strings = array(
|
||||||
|
CAS_STR_USING_SERVER
|
||||||
|
=> 'using server',
|
||||||
|
CAS_STR_AUTHENTICATION_WANTED
|
||||||
|
=> 'CASによる認証を行います',
|
||||||
|
CAS_STR_LOGOUT
|
||||||
|
=> 'CASからログアウトします!',
|
||||||
|
CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
|
||||||
|
=> 'CASサーバに行く必要があります。自動的に転送されない場合は <a href="%s">こちら</a> をクリックして続行します。',
|
||||||
|
CAS_STR_AUTHENTICATION_FAILED
|
||||||
|
=> 'CASによる認証に失敗しました',
|
||||||
|
CAS_STR_YOU_WERE_NOT_AUTHENTICATED
|
||||||
|
=> '<p>認証できませんでした.</p><p>もう一度リクエストを送信する場合は<a href="%s">こちら</a>をクリック.</p><p>問題が解決しない場合は <a href="mailto:%s">このサイトの管理者</a>に問い合わせてください.</p>',
|
||||||
|
CAS_STR_SERVICE_UNAVAILABLE
|
||||||
|
=> 'サービス `<b>%s</b>\' は利用できません (<b>%s</b>).'
|
||||||
|
);
|
||||||
|
|
||||||
|
?>
|
24
plugins/CasAuthentication/extlib/CAS/languages/languages.php
Normal file
24
plugins/CasAuthentication/extlib/CAS/languages/languages.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file languages/languages.php
|
||||||
|
* Internationalization constants
|
||||||
|
* @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
|
||||||
|
* @sa @link internalLang Internationalization @endlink
|
||||||
|
* @ingroup internalLang
|
||||||
|
*/
|
||||||
|
|
||||||
|
//@{
|
||||||
|
/**
|
||||||
|
* a phpCAS string index
|
||||||
|
*/
|
||||||
|
define("CAS_STR_USING_SERVER", 1);
|
||||||
|
define("CAS_STR_AUTHENTICATION_WANTED", 2);
|
||||||
|
define("CAS_STR_LOGOUT", 3);
|
||||||
|
define("CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED", 4);
|
||||||
|
define("CAS_STR_AUTHENTICATION_FAILED", 5);
|
||||||
|
define("CAS_STR_YOU_WERE_NOT_AUTHENTICATED", 6);
|
||||||
|
define("CAS_STR_SERVICE_UNAVAILABLE", 7);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
?>
|
27
plugins/CasAuthentication/extlib/CAS/languages/spanish.php
Normal file
27
plugins/CasAuthentication/extlib/CAS/languages/spanish.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file languages/spanish.php
|
||||||
|
* @author Iván-Benjamín García Torà <ivaniclixx AT gmail DOT com>
|
||||||
|
* @sa @link internalLang Internationalization @endlink
|
||||||
|
* @ingroup internalLang
|
||||||
|
*/
|
||||||
|
|
||||||
|
$this->_strings = array(
|
||||||
|
CAS_STR_USING_SERVER
|
||||||
|
=> 'usando servidor',
|
||||||
|
CAS_STR_AUTHENTICATION_WANTED
|
||||||
|
=> '¡Autentificación CAS necesaria!',
|
||||||
|
CAS_STR_LOGOUT
|
||||||
|
=> '¡Salida CAS necesaria!',
|
||||||
|
CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED
|
||||||
|
=> 'Ya debería haber sido redireccionado al servidor CAS. Haga click <a href="%s">aquí</a> para continuar.',
|
||||||
|
CAS_STR_AUTHENTICATION_FAILED
|
||||||
|
=> '¡Autentificación CAS fallida!',
|
||||||
|
CAS_STR_YOU_WERE_NOT_AUTHENTICATED
|
||||||
|
=> '<p>No estás autentificado.</p><p>Puedes volver a intentarlo haciendo click <a href="%s">aquí</a>.</p><p>Si el problema persiste debería contactar con el <a href="mailto:%s">administrador de este sitio</a>.</p>',
|
||||||
|
CAS_STR_SERVICE_UNAVAILABLE
|
||||||
|
=> 'El servicio `<b>%s</b>\' no está disponible (<b>%s</b>).'
|
||||||
|
);
|
||||||
|
|
||||||
|
?>
|
@ -76,27 +76,25 @@ class GeonamesPlugin extends Plugin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$client = HTTPClient::start();
|
try {
|
||||||
|
$geonames = $this->getGeonames('search',
|
||||||
// XXX: break down a name by commas, narrow by each
|
|
||||||
|
|
||||||
$result = $client->get($this->wsUrl('search',
|
|
||||||
array('maxRows' => 1,
|
array('maxRows' => 1,
|
||||||
'q' => $name,
|
'q' => $name,
|
||||||
'lang' => $language,
|
'lang' => $language,
|
||||||
'type' => 'json')));
|
'type' => 'xml'));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->log(LOG_WARNING, "Error for $name: " . $e->getMessage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if ($result->isOk()) {
|
$n = $geonames[0];
|
||||||
$rj = json_decode($result->getBody());
|
|
||||||
if (count($rj->geonames) > 0) {
|
|
||||||
$n = $rj->geonames[0];
|
|
||||||
|
|
||||||
$location = new Location();
|
$location = new Location();
|
||||||
|
|
||||||
$location->lat = $n->lat;
|
$location->lat = (string)$n->lat;
|
||||||
$location->lon = $n->lng;
|
$location->lon = (string)$n->lng;
|
||||||
$location->names[$language] = $n->name;
|
$location->names[$language] = (string)$n->name;
|
||||||
$location->location_id = $n->geonameId;
|
$location->location_id = (string)$n->geonameId;
|
||||||
$location->location_ns = self::LOCATION_NS;
|
$location->location_ns = self::LOCATION_NS;
|
||||||
|
|
||||||
$this->setCache(array('name' => $name,
|
$this->setCache(array('name' => $name,
|
||||||
@ -106,11 +104,6 @@ class GeonamesPlugin extends Plugin
|
|||||||
// handled, don't continue processing!
|
// handled, don't continue processing!
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Continue processing; we don't have the answer
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert an id into a Location object
|
* convert an id into a Location object
|
||||||
@ -137,46 +130,41 @@ class GeonamesPlugin extends Plugin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$client = HTTPClient::start();
|
try {
|
||||||
|
$geonames = $this->getGeonames('hierarchy',
|
||||||
$result = $client->get($this->wsUrl('hierarchyJSON',
|
|
||||||
array('geonameId' => $id,
|
array('geonameId' => $id,
|
||||||
'lang' => $language)));
|
'lang' => $language));
|
||||||
|
} catch (Exception $e) {
|
||||||
if ($result->isOk()) {
|
$this->log(LOG_WARNING, "Error for ID $id: " . $e->getMessage());
|
||||||
|
return false;
|
||||||
$rj = json_decode($result->getBody());
|
}
|
||||||
|
|
||||||
if (count($rj->geonames) > 0) {
|
|
||||||
|
|
||||||
$parts = array();
|
$parts = array();
|
||||||
|
|
||||||
foreach ($rj->geonames as $level) {
|
foreach ($geonames as $level) {
|
||||||
if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
|
if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
|
||||||
$parts[] = $level->name;
|
$parts[] = (string)$level->name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$last = $rj->geonames[count($rj->geonames)-1];
|
$last = $geonames[count($geonames)-1];
|
||||||
|
|
||||||
if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
|
if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
|
||||||
$parts[] = $last->name;
|
$parts[] = (string)$last->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
$location = new Location();
|
$location = new Location();
|
||||||
|
|
||||||
$location->location_id = $last->geonameId;
|
$location->location_id = (string)$last->geonameId;
|
||||||
$location->location_ns = self::LOCATION_NS;
|
$location->location_ns = self::LOCATION_NS;
|
||||||
$location->lat = $last->lat;
|
$location->lat = (string)$last->lat;
|
||||||
$location->lon = $last->lng;
|
$location->lon = (string)$last->lng;
|
||||||
$location->names[$language] = implode(', ', array_reverse($parts));
|
$location->names[$language] = implode(', ', array_reverse($parts));
|
||||||
|
|
||||||
$this->setCache(array('id' => $last->geonameId),
|
$this->setCache(array('id' => (string)$last->geonameId),
|
||||||
$location);
|
$location);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're responsible for this NAMESPACE; nobody else
|
// We're responsible for this namespace; nobody else
|
||||||
// can resolve it
|
// can resolve it
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -209,40 +197,36 @@ class GeonamesPlugin extends Plugin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$client = HTTPClient::start();
|
try {
|
||||||
|
$geonames = $this->getGeonames('findNearbyPlaceName',
|
||||||
$result =
|
|
||||||
$client->get($this->wsUrl('findNearbyPlaceNameJSON',
|
|
||||||
array('lat' => $lat,
|
array('lat' => $lat,
|
||||||
'lng' => $lon,
|
'lng' => $lon,
|
||||||
'lang' => $language)));
|
'lang' => $language));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->log(LOG_WARNING, "Error for coords $lat, $lon: " . $e->getMessage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if ($result->isOk()) {
|
$n = $geonames[0];
|
||||||
|
|
||||||
$rj = json_decode($result->getBody());
|
|
||||||
|
|
||||||
if (count($rj->geonames) > 0) {
|
|
||||||
|
|
||||||
$n = $rj->geonames[0];
|
|
||||||
|
|
||||||
$parts = array();
|
$parts = array();
|
||||||
|
|
||||||
$location = new Location();
|
$location = new Location();
|
||||||
|
|
||||||
$parts[] = $n->name;
|
$parts[] = (string)$n->name;
|
||||||
|
|
||||||
if (!empty($n->adminName1)) {
|
if (!empty($n->adminName1)) {
|
||||||
$parts[] = $n->adminName1;
|
$parts[] = (string)$n->adminName1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($n->countryName)) {
|
if (!empty($n->countryName)) {
|
||||||
$parts[] = $n->countryName;
|
$parts[] = (string)$n->countryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
$location->location_id = $n->geonameId;
|
$location->location_id = (string)$n->geonameId;
|
||||||
$location->location_ns = self::LOCATION_NS;
|
$location->location_ns = self::LOCATION_NS;
|
||||||
$location->lat = $lat;
|
$location->lat = (string)$lat;
|
||||||
$location->lon = $lon;
|
$location->lon = (string)$lon;
|
||||||
|
|
||||||
$location->names[$language] = implode(', ', $parts);
|
$location->names[$language] = implode(', ', $parts);
|
||||||
|
|
||||||
@ -254,12 +238,6 @@ class GeonamesPlugin extends Plugin
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// For some reason we don't know, so pass.
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Human-readable name for a location
|
* Human-readable name for a location
|
||||||
@ -281,7 +259,9 @@ class GeonamesPlugin extends Plugin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$n = $this->getCache(array('id' => $location->location_id,
|
$id = $location->location_id;
|
||||||
|
|
||||||
|
$n = $this->getCache(array('id' => $id,
|
||||||
'language' => $language));
|
'language' => $language));
|
||||||
|
|
||||||
if (!empty($n)) {
|
if (!empty($n)) {
|
||||||
@ -289,47 +269,41 @@ class GeonamesPlugin extends Plugin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$client = HTTPClient::start();
|
try {
|
||||||
|
$geonames = $this->getGeonames('hierarchy',
|
||||||
$result = $client->get($this->wsUrl('hierarchyJSON',
|
array('geonameId' => $id,
|
||||||
array('geonameId' => $location->location_id,
|
'lang' => $language));
|
||||||
'lang' => $language)));
|
} catch (Exception $e) {
|
||||||
|
$this->log(LOG_WARNING, "Error for ID $id: " . $e->getMessage());
|
||||||
if ($result->isOk()) {
|
return false;
|
||||||
|
}
|
||||||
$rj = json_decode($result->getBody());
|
|
||||||
|
|
||||||
if (count($rj->geonames) > 0) {
|
|
||||||
|
|
||||||
$parts = array();
|
$parts = array();
|
||||||
|
|
||||||
foreach ($rj->geonames as $level) {
|
foreach ($geonames as $level) {
|
||||||
if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
|
if (in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
|
||||||
$parts[] = $level->name;
|
$parts[] = (string)$level->name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$last = $rj->geonames[count($rj->geonames)-1];
|
$last = $geonames[count($geonames)-1];
|
||||||
|
|
||||||
if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
|
if (!in_array($level->fcode, array('PCLI', 'ADM1', 'PPL'))) {
|
||||||
$parts[] = $last->name;
|
$parts[] = (string)$last->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($parts)) {
|
if (count($parts)) {
|
||||||
$name = implode(', ', array_reverse($parts));
|
$name = implode(', ', array_reverse($parts));
|
||||||
$this->setCache(array('id' => $location->location_id,
|
$this->setCache(array('id' => $id,
|
||||||
'language' => $language),
|
'language' => $language),
|
||||||
$name);
|
$name);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Human-readable name for a location
|
* Human-readable URL for a location
|
||||||
*
|
*
|
||||||
* Given a location, we try to retrieve a geonames.org URL.
|
* Given a location, we try to retrieve a geonames.org URL.
|
||||||
*
|
*
|
||||||
@ -423,8 +397,33 @@ class GeonamesPlugin extends Plugin
|
|||||||
$params['token'] = $this->token;
|
$params['token'] = $this->token;
|
||||||
}
|
}
|
||||||
|
|
||||||
$str = http_build_query($params);
|
$str = http_build_query($params, null, '&');
|
||||||
|
|
||||||
return 'http://'.$this->host.'/'.$method.'?'.$str;
|
return 'http://'.$this->host.'/'.$method.'?'.$str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGeonames($method, $params)
|
||||||
|
{
|
||||||
|
$client = HTTPClient::start();
|
||||||
|
|
||||||
|
$result = $client->get($this->wsUrl($method, $params));
|
||||||
|
|
||||||
|
if (!$result->isOk()) {
|
||||||
|
throw new Exception("HTTP error code " . $result->code);
|
||||||
|
}
|
||||||
|
|
||||||
|
$document = new SimpleXMLElement($result->getBody());
|
||||||
|
|
||||||
|
if (empty($document)) {
|
||||||
|
throw new Exception("No results in response");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($document->status)) {
|
||||||
|
throw new Exception("Error #".$document->status['value']." ('".$document->status['message']."')");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array of elements
|
||||||
|
|
||||||
|
return $document->geoname;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,18 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onAutoload($cls)
|
||||||
|
{
|
||||||
|
switch ($cls)
|
||||||
|
{
|
||||||
|
case 'MemcacheSchemaCache':
|
||||||
|
require_once(INSTALLDIR.'/plugins/LdapAuthentication/MemcacheSchemaCache.php');
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return parent::onAutoload($cls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---interface implementation---//
|
//---interface implementation---//
|
||||||
|
|
||||||
function checkPassword($username, $password)
|
function checkPassword($username, $password)
|
||||||
@ -174,6 +186,14 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if($config == null) $this->default_ldap=$ldap;
|
if($config == null) $this->default_ldap=$ldap;
|
||||||
|
|
||||||
|
$c = common_memcache();
|
||||||
|
if (!empty($c)) {
|
||||||
|
$cacheObj = new MemcacheSchemaCache(
|
||||||
|
array('c'=>$c,
|
||||||
|
'cacheKey' => common_cache_key('ldap_schema:' . crc32(serialize($config)))));
|
||||||
|
$ldap->registerSchemaCache($cacheObj);
|
||||||
|
}
|
||||||
return $ldap;
|
return $ldap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,20 +212,21 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
|
|||||||
$options = array(
|
$options = array(
|
||||||
'attributes' => $attributes
|
'attributes' => $attributes
|
||||||
);
|
);
|
||||||
$search = $ldap->search(null,$filter,$options);
|
$search = $ldap->search($this->basedn, $filter, $options);
|
||||||
|
|
||||||
if (PEAR::isError($search)) {
|
if (PEAR::isError($search)) {
|
||||||
common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
|
common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($search->count()==0){
|
$searchcount = $search->count();
|
||||||
|
if($searchcount == 0) {
|
||||||
return false;
|
return false;
|
||||||
}else if($search->count()==1){
|
}else if($searchcount == 1) {
|
||||||
$entry = $search->shiftEntry();
|
$entry = $search->shiftEntry();
|
||||||
return $entry;
|
return $entry;
|
||||||
}else{
|
}else{
|
||||||
common_log(LOG_WARNING, 'Found ' . $search->count() . ' ldap user with the username: ' . $username);
|
common_log(LOG_WARNING, 'Found ' . $searchcount . ' ldap user with the username: ' . $username);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
75
plugins/LdapAuthentication/MemcacheSchemaCache.php
Normal file
75
plugins/LdapAuthentication/MemcacheSchemaCache.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet, the distributed open-source microblogging tool
|
||||||
|
*
|
||||||
|
* Cache the LDAP schema in memcache to improve performance
|
||||||
|
*
|
||||||
|
* 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 StatusNet
|
||||||
|
* @author Craig Andrews <candrews@integralblue.com>
|
||||||
|
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
class MemcacheSchemaCache implements Net_LDAP2_SchemaCache
|
||||||
|
{
|
||||||
|
protected $c;
|
||||||
|
protected $cacheKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the simple cache
|
||||||
|
*
|
||||||
|
* Config is as following:
|
||||||
|
* memcache memcache instance
|
||||||
|
* cachekey the key in the cache to look at
|
||||||
|
*
|
||||||
|
* @param array $cfg Config array
|
||||||
|
*/
|
||||||
|
public function MemcacheSchemaCache($cfg)
|
||||||
|
{
|
||||||
|
$this->c = $cfg['c'];
|
||||||
|
$this->cacheKey = $cfg['cacheKey'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the schema object from the cache
|
||||||
|
*
|
||||||
|
* @return Net_LDAP2_Schema|Net_LDAP2_Error|false
|
||||||
|
*/
|
||||||
|
public function loadSchema()
|
||||||
|
{
|
||||||
|
return $this->c->get($this->cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a schema object in the cache
|
||||||
|
*
|
||||||
|
* This method will be called, if Net_LDAP2 has fetched a fresh
|
||||||
|
* schema object from LDAP and wants to init or refresh the cache.
|
||||||
|
*
|
||||||
|
* To invalidate the cache and cause Net_LDAP2 to refresh the cache,
|
||||||
|
* you can call this method with null or false as value.
|
||||||
|
* The next call to $ldap->schema() will then refresh the caches object.
|
||||||
|
*
|
||||||
|
* @param mixed $schema The object that should be cached
|
||||||
|
* @return true|Net_LDAP2_Error|false
|
||||||
|
*/
|
||||||
|
public function storeSchema($schema) {
|
||||||
|
return $this->c->set($this->cacheKey, $schema);
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,8 @@ filter: Default search filter.
|
|||||||
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
|
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
|
||||||
scope: Default search scope.
|
scope: Default search scope.
|
||||||
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
|
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
|
||||||
|
schema_cachefile: File location to store ldap schema.
|
||||||
|
schema_maxage: TTL for cache file.
|
||||||
|
|
||||||
attributes: an array that relates StatusNet user attributes to LDAP ones
|
attributes: an array that relates StatusNet user attributes to LDAP ones
|
||||||
username*: LDAP attribute value entered when authenticating to StatusNet
|
username*: LDAP attribute value entered when authenticating to StatusNet
|
||||||
|
@ -316,6 +316,10 @@ class MobileProfilePlugin extends WAP20Plugin
|
|||||||
$action->menuItem(common_local_url($connect),
|
$action->menuItem(common_local_url($connect),
|
||||||
_('Connect'));
|
_('Connect'));
|
||||||
}
|
}
|
||||||
|
if ($user->hasRight(Right::CONFIGURESITE)) {
|
||||||
|
$action->menuItem(common_local_url('siteadminpanel'),
|
||||||
|
_('Admin'), _('Change site configuration'), false, 'nav_admin');
|
||||||
|
}
|
||||||
if (common_config('invite', 'enabled')) {
|
if (common_config('invite', 'enabled')) {
|
||||||
$action->menuItem(common_local_url('invite'),
|
$action->menuItem(common_local_url('invite'),
|
||||||
_('Invite'));
|
_('Invite'));
|
||||||
|
@ -179,11 +179,11 @@ padding-bottom:4px;
|
|||||||
}
|
}
|
||||||
.notice div.entry-content {
|
.notice div.entry-content {
|
||||||
margin-left:0;
|
margin-left:0;
|
||||||
width:65%;
|
width:62.5%;
|
||||||
}
|
}
|
||||||
.notice-options {
|
.notice-options {
|
||||||
width:30%;
|
width:34%;
|
||||||
margin-right:2%;
|
margin-right:1%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice-options form {
|
.notice-options form {
|
||||||
|
@ -103,7 +103,7 @@ class OpenidserverAction extends Action
|
|||||||
$response = $this->generateDenyResponse($request);
|
$response = $this->generateDenyResponse($request);
|
||||||
} else {
|
} else {
|
||||||
//invalid
|
//invalid
|
||||||
$this->clientError(sprintf(_m('You are not authorized to use the identity %s'),$request->identity),$code=403);
|
$this->clientError(sprintf(_m('You are not authorized to use the identity %s.'),$request->identity),$code=403);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$response = $this->oserver->handleRequest($request);
|
$response = $this->oserver->handleRequest($request);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user