Merge branch '0.9.x' into userflag

This commit is contained in:
Evan Prodromou 2009-11-01 13:04:23 -05:00
commit 5f5413624d
199 changed files with 9363 additions and 2102 deletions

2
.gitignore vendored
View File

@ -24,4 +24,4 @@ config-*.php
good-config.php good-config.php
lac08.log lac08.log
php.log php.log
.DS_Store

View File

@ -129,6 +129,9 @@ StartSubGroupNav: Showing the subscriptions group nav menu
EndSubGroupNav: At the end of the subscriptions group nav menu EndSubGroupNav: At the end of the subscriptions group nav menu
- $action: the current action - $action: the current action
StartInitializeRouter: Before the router instance has been initialized; good place to add routes
- $m: the Net_URL_Mapper that has just been set up
RouterInitialized: After the router instance has been initialized RouterInitialized: After the router instance has been initialized
- $m: the Net_URL_Mapper that has just been set up - $m: the Net_URL_Mapper that has just been set up
@ -390,3 +393,84 @@ EndProfilePageProfileTags: after showing the tags on the profile page
- $action: the current action - $action: the current action
- &$profile: the profile being shown - &$profile: the profile being shown
StartProfileList: when starting a list of profiles (before <ul>)
- $profilelist: ProfileList widget, with $profile, $action, and $out
EndProfileList: when ending a list of profiles (after </ul>)
- $profilelist: ProfileList widget
StartProfileListItem: when starting to show a profile list item
- $item: ProfileListItem widget
EndProfileListItem: after showing a profile list item
- $item: ProfileListItem widget
StartProfileListItemProfile: the profile data part of the item
- $item: ProfileListItem widget
EndProfileListItemProfile: the profile data part of the item
- $item: ProfileListItem widget
StartProfileListItemActions: the actions (buttons) for an item
- $item: ProfileListItem widget
EndProfileListItemActions: the actions (buttons) for an item
- $item: ProfileListItem widget
StartProfileListItemProfileElements: inside the <div>
- $item: ProfileListItem widget
EndProfileListItemProfileElements: inside the <div>
- $item: ProfileListItem widget
StartProfileListItemAvatar: Showing a profile list avatar
- $item: ProfileListItem widget
EndProfileListItemAvatar: Showing a profile list avatar
- $item: ProfileListItem widget
StartProfileListItemFullName: Showing the profile list full name
- $item: ProfileListItem widget
EndProfileListItemFullName: Showing the profile list full name
- $item: ProfileListItem widget
StartProfileListItemLocation: Showing the profile list location
- $item: ProfileListItem widget
EndProfileListItemLocation: Showing the profile list location
- $item: ProfileListItem widget
StartProfileListItemHomepage: Showing the profile list homepage
- $item: ProfileListItem widget
EndProfileListItemHomepage: Showing the profile list homepage
- $item: ProfileListItem widget
StartProfileListItemBio: Showing the profile list bio
- $item: ProfileListItem widget
EndProfileListItemBio: Showing the profile list bio
- $item: ProfileListItem widget
StartProfileListItemActionElements: Showing the profile list actions (prepend a button here, or replace all buttons)
- $item: ProfileListItem widget
EndProfileListItemActionElements: Showing profile list actions (append a button here)
- $item: ProfileListItem widget
StartUserXRDS: Start XRDS output (right after the opening XRDS tag)
- $action: the current action
- &$xrdsoutputter - XRDSOutputter object to write to
EndUserXRDS: End XRDS output (right before the closing XRDS tag)
- $action: the current action
- &$xrdsoutputter - XRDSOutputter object to write to
StartPublicXRDS: Start XRDS output (right after the opening XRDS tag)
- $action: the current action
- &$xrdsoutputter - XRDSOutputter object to write to
EndPublicXRDS: End XRDS output (right before the closing XRDS tag)
- $action: the current action
- &$xrdsoutputter - XRDSOutputter object to write to

263
README
View File

@ -2,8 +2,8 @@
README README
------ ------
StatusNet 0.8.1 ("Second Guessing") StatusNet 0.8.2 ("Life and How to Live It")
26 Aug 2009 1 Nov 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,
@ -77,49 +77,80 @@ for additional terms.
New this version New this version
================ ================
This is a minor feature and bugfix release since version 0.8.0, This is a minor feature and bugfix release since version 0.8.1,
released Jul 15 2009. Notable changes this version: released Aug 26 2009. Notable changes this version:
- Laconica has been renamed StatusNet. With a few minor compatibility - New script for deleting user accounts. Not particularly safe or
exceptions, all references to "Laconica" in code, documentation community-friendly. Better for deleting abusive accounts than for
and comments were changed to "StatusNet". users who are 'retiring'.
- A new plugin to support "infinite scroll". - Improved detection of URLs in notices, specifically for punctuation
- A new plugin to support reCaptcha <http://recaptcha.net>. chars like ~, :, $, _, -, +, !, @, and %.
- Better logging of server errors. - Removed some extra <dl> semantic HTML code.
- Add an Openid-only mode for authentication. - Correct error in status-network database ini file (having multiple
- 'lite' parameter for some Twitter API methods. statusnet sites with a single codebase)
- A new plugin to auto-complete nicknames for @-replies. - Fixed error output for Twitter posting failures.
- Configuration options to disable OpenID, SMS, Twitter, post-by-email, and IM. - Fixed bug in Twitter queue handler that requeued inapplicable
- Support for lighttpd <http://lighttpd.org/> using 404-based notices ad infinitum.
rewrites. - Improve FOAF output for remote users.
- Support for using Twitter's OAuth authentication as a client. - new commands to join and leave groups.
- First version of the groups API. - Fixed bug in which you cannot turn off importing friends timelines
- Can configure a site-wide design, including background image and flag.
colors. - Better error handling in Twitter posting.
- Improved algorithm for replies and conversations, making - Show oEmbed data for XHTML files as well as plain HTML.
conversation trees more accurate and useful. - Updated bug database link in README.
- Add a script to create a simulation database for testing/debugging. - require HTML tidy extension.
- Sanitize HTML for OEmbed. - add support for HTTP Basic Auth in PHP CGI or FastCGI (e.g. GoDaddy).
- Improved queue management for DB-based queuing. - autofocus input to selected entry elements depending on page.
- More complete URL detection. - updated layout for filter-by-tag form.
- Hashtags now support full Unicode character set. - better layout for inbox and outbox pages.
- Notice inboxes are now garbage-collected on a regular basis - fix highlighting search terms in attributes of notice list elements.
at notice-write time. - Correctly handle errors in linkback plugin.
- PiwikAnalyticsPlugin updated for latest Piwik interface. - Updated biz theme.
- Attachment and notice pages can be embedded with OEmbed - Updated cloudy theme.
<http://www.oembed.com>. - Don't match '::' as an IPv6 address.
- Failed authentication is logged. - Use the same decision logic for deciding whether to mark an
- PostgreSQL schema and support brought up-to-date with 0.8.x features. attachment as an enclosure in RSS or as a paperclip item in Web
- The installer works with PostgreSQL as well as MySQL. output.
- RSS 1.0 feeds use HTTP Basic authentication in private mode. - Fixed a bug in the Piwik plugin that hard-coded the site ID.
- Many, many bug fixes, particularly with performance. - Add a param, inreplyto, to notice/new to allow an explicit response
- Better (=working) garbage collection for old sessions. to another notice.
- Better (=working) search queries. - Show username in subject of emails.
- Some cleanup of HTML output. - Check if avatar exists before trying to delete it.
- Better error handling when updating Facebook. - Correctly add omb_version to response for request token in OMB.
- Considerably better performance when using replication for API - Add a few more SMS carriers.
calls. - Add a few more notice sources.
- Initial unit tests. - Vary: header.
- Improvements to the AutoCompletePlugin.
- Check for 'dl' before using it.
- Make it impossible to delete self-subscriptions via the API.
- Fix pagination of tagged user pages.
- Make PiwikAnalyticsPlugin work with addPlugin().
- Removed trailing single space in user nicknames in notice lists.
- Show context link if a notice starts a conversation.
- blacklist all files and directories in install dir.
- handle GoDaddy-style PATH_INFO, including script name.
- add home_timeline synonym for friends_timeline.
- Add a popup window for the realtime plugin.
- Add some more streams for the realtime plugin.
- Fix a bug that overwrote group creation timestamp on every edit.
- Moved HTTP error code strings to a class variable.
- The Twitter API now returns server errors in the correct format.
- Reset the doctype for HTML output.
- Fixed a number of notices.
- Don't show search suggestions for private sites.
- Some corrections to FBConnect nav overrides.
- Slightly less database-intensive session management.
- Updated name of software in installer script.
- Include long-form attachment URLs if url-shortener is disabled.
- Include updated localisations for Polish, Greek, Hebrew, Icelandic,
Norwegian, and Chinese.
- Include upstream fixes to gettext.php.
- Correct for regression in Facebook API for updates.
- Ignore "Sent from my iPhone" (and similar) in mail updates.
- Use the NICKNAME_FMT constant for detecting nicknames.
- Check for site servername config'd.
- Compatibility fix for empty status updates with Twitter API.
- Option to show files privately (EXPERIMENTAL! Use with caution.)
Prerequisites Prerequisites
============= =============
@ -225,9 +256,9 @@ especially if you've previously installed PHP/MySQL packages.
1. Unpack the tarball you downloaded on your Web server. Usually a 1. Unpack the tarball you downloaded on your Web server. Usually a
command like this will work: command like this will work:
tar zxf statusnet-0.8.1.tar.gz tar zxf statusnet-0.8.2.tar.gz
...which will make a statusnet-0.8.1 subdirectory in your current ...which will make a statusnet-0.8.2 subdirectory in your current
directory. (If you don't have shell access on your Web server, you directory. (If you don't have shell access on your Web server, you
may have to unpack the tarball on your local computer and FTP the may have to unpack the tarball on your local computer and FTP the
files to the server.) files to the server.)
@ -235,7 +266,7 @@ especially if you've previously installed PHP/MySQL packages.
2. Move the tarball to a directory of your choosing in your Web root 2. Move the tarball to a directory of your choosing in your Web root
directory. Usually something like this will work: directory. Usually something like this will work:
mv statusnet-0.8.1 /var/www/mublog mv statusnet-0.8.2 /var/www/mublog
This will make your StatusNet instance available in the mublog path of This will make your StatusNet instance available in the mublog path of
your server, like "http://example.net/mublog". "microblog" or your server, like "http://example.net/mublog". "microblog" or
@ -526,10 +557,6 @@ This will run eight (for now) queue handlers:
of registered users. of registered users.
* xmppconfirmhandler.php - sends confirmation messages to registered * xmppconfirmhandler.php - sends confirmation messages to registered
users. users.
* twitterqueuehandler.php - sends queued notices to Twitter for user
who have opted to set up Twitter bridging.
* facebookqueuehandler.php - sends queued notices to Facebook for users
of the built-in Facebook application.
Note that these queue daemons are pretty raw, and need your care. In Note that these queue daemons are pretty raw, and need your care. In
particular, they leak memory, and you may want to restart them on a particular, they leak memory, and you may want to restart them on a
@ -547,101 +574,6 @@ our kind of hacky home-grown DB-based queue solution. See the "queues"
config section below for how to configure to use STOMP. As of this config section below for how to configure to use STOMP. As of this
writing, the software has been tested with ActiveMQ ( writing, the software has been tested with ActiveMQ (
Twitter Bridge
--------------
* OAuth
As of 0.8.1, OAuth is used to to access protected resources on Twitter
instead of HTTP Basic Auth. To use Twitter bridging you will need
to register your instance of StatusNet as an application on Twitter
(http://twitter.com/apps), and update the following variables in your
config.php with the consumer key and secret Twitter generates for you:
$config['twitter']['consumer_key'] = 'YOURKEY';
$config['twitter']['consumer_secret'] = 'YOURSECRET';
When registering your application with Twitter set the type to "Browser"
and your Callback URL to:
http://example.org/mublog/twitter/authorization
The default access type should be, "Read & Write".
* Importing statuses from Twitter
To allow your users to import their friends' Twitter statuses, you will
need to enable the bidirectional Twitter bridge in config.php:
$config['twitterbridge']['enabled'] = true;
and run the TwitterStatusFetcher daemon (scripts/twitterstatusfetcher.php).
Additionally, you will want to set the integration source variable,
which will keep notices posted to Twitter via StatusNet from looping
back. The integration source should be set to the name of your
application, exactly as you specified it on the settings page for your
StatusNet application on Twitter, e.g.:
$config['integration']['source'] = 'YourApp';
* Twitter Friends Syncing
Users may set a flag in their settings ("Subscribe to my Twitter friends
here" under the Twitter tab) to have StatusNet attempt to locate and
subscribe to "friends" (people they "follow") on Twitter who also have
accounts on your StatusNet system, and who have previously set up a link
for automatically posting notices to Twitter.
As of 0.8.0, this is no longer accomplished via a cron job. Instead you
must run the SyncTwitterFriends daemon (scripts/synctwitterfreinds.php).
Built-in Facebook Application
-----------------------------
StatusNet's Facebook application allows your users to automatically
update their Facebook statuses with their latest notices, invite
their friends to use the app (and thus your site), view their notice
timelines, and post notices -- all from within Facebook. The application
is built into StatusNet and runs on your host. For automatic Facebook
status updating to work you will need to enable queuing and run the
facebookqueuehandler.php daemon (see the "Queues and daemons" section
above).
Quick setup instructions*:
Install the Facebook Developer application on Facebook:
http://www.facebook.com/developers/
Use it to create a new application and generate an API key and secret.
Uncomment the Facebook app section of your config.php and copy in the
key and secret, e.g.:
# Config section for the built-in Facebook application
$config['facebook']['apikey'] = 'APIKEY';
$config['facebook']['secret'] = 'SECRET';
In Facebook's application editor, specify the following URLs for your app:
- Canvas Callback URL: http://example.net/mublog/facebook/
- Post-Remove Callback URL: http://example.net/mublog/facebook/remove
- Post-Add Redirect URL: http://apps.facebook.com/yourapp/
- Canvas Page URL: http://apps.facebook.com/yourapp/
(Replace 'example.net' with your host's URL, 'mublog' with the path
to your StatusNet installation, and 'yourapp' with the name of the
Facebook application you created.)
Additionally, Choose "Web" for Application type in the Advanced tab.
In the "Canvas setting" section, choose the "FBML" for Render Method,
"Smart Size" for IFrame size, and "Full width (760px)" for Canvas Width.
Everything else can be left with default values.
*For more detailed instructions please see the installation guide on the
StatusNet wiki:
http://status.net/trac/wiki/FacebookApplication
Sitemaps Sitemaps
-------- --------
@ -755,6 +687,16 @@ private site, but users of the private site may be able to subscribe
to users on a remote site. (Or not... it's not well tested.) The to users on a remote site. (Or not... it's not well tested.) The
"proper behaviour" hasn't been defined here, so handle with care. "proper behaviour" hasn't been defined here, so handle with care.
If fancy URLs is enabled, access to file attachments can also be
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
not work if you are using a virtual server for attachments, so consider
the performance/security tradeoff.)
=======
rule in .htaccess or your server's httpd.conf.
>>>>>>> 446de62... Revert "Added some explanatory text to README":README
Upgrading Upgrading
========= =========
@ -768,7 +710,7 @@ with this situation.
If you've been using StatusNet 0.7, 0.6, 0.5 or lower, or if you've If you've been using StatusNet 0.7, 0.6, 0.5 or lower, or if you've
been tracking the "git" version of the software, you will probably been tracking the "git" version of the software, you will probably
want to upgrade and keep your existing data. There is no automated want to upgrade and keep your existing data. There is no automated
upgrade procedure in StatusNet 0.8.1. Try these step-by-step upgrade procedure in StatusNet 0.8.2. Try these step-by-step
instructions; read to the end first before trying them. instructions; read to the end first before trying them.
0. Download StatusNet and set up all the prerequisites as if you were 0. Download StatusNet and set up all the prerequisites as if you were
@ -789,7 +731,7 @@ instructions; read to the end first before trying them.
5. Once all writing processes to your site are turned off, make a 5. Once all writing processes to your site are turned off, make a
final backup of the Web directory and database. final backup of the Web directory and database.
6. Move your StatusNet directory to a backup spot, like "mublog.bak". 6. Move your StatusNet directory to a backup spot, like "mublog.bak".
7. Unpack your StatusNet 0.8.1 tarball and move it to "mublog" or 7. Unpack your StatusNet 0.8.2 tarball and move it to "mublog" or
wherever your code used to be. wherever your code used to be.
8. Copy the config.php file and avatar directory from your old 8. Copy the config.php file and avatar directory from your old
directory to your new directory. directory to your new directory.
@ -1251,24 +1193,11 @@ For SMS integration.
enabled: Whether to enable SMS integration. Defaults to true. Queues enabled: Whether to enable SMS integration. Defaults to true. Queues
should also be enabled. should also be enabled.
twitter
-------
For Twitter integration
enabled: Whether to enable Twitter integration. Defaults to true.
Queues should also be enabled.
integration integration
----------- -----------
A catch-all for integration with other systems. A catch-all for integration with other systems.
source: The name to use for the source of posts to Twitter. Defaults
to 'statusnet', but if you request your own source name from
Twitter <http://twitter.com/help/request_source>, you can use
that here instead. Status updates on Twitter will then have
links to your site.
taguri: base for tag:// URIs. Defaults to site-server + ',2009'. taguri: base for tag:// URIs. Defaults to site-server + ',2009'.
inboxes inboxes
@ -1446,15 +1375,6 @@ dir: directory to write backgrounds too. Default is '/background/'
path: path to backgrounds. Default is sub-path of install path; note path: path to backgrounds. Default is sub-path of install path; note
that you may need to change this if you change site-path too. that you may need to change this if you change site-path too.
twitterbridge
-------------
A bi-direction bridge to Twitter (http://twitter.com/).
enabled: default false. If true, will show user's Twitter friends'
notices in their inbox and faves pages, only to the user. You
must also run the twitterstatusfetcher.php script.
ping ping
---- ----
@ -1553,7 +1473,7 @@ repository (see below), and you get a compilation error ("unexpected
T_STRING") in the browser, check to see that you don't have any T_STRING") in the browser, check to see that you don't have any
conflicts in your code. conflicts in your code.
If you upgraded to StatusNet 0.8.1 without reading the "Notice If you upgraded to StatusNet 0.8.2 without reading the "Notice
inboxes" section above, and all your users' 'Personal' tabs are empty, inboxes" section above, and all your users' 'Personal' tabs are empty,
read the "Notice inboxes" section above. read the "Notice inboxes" section above.
@ -1661,6 +1581,7 @@ if anyone's been overlooked in error.
* Jeffery To * Jeffery To
* Federico Marani * Federico Marani
* Craig Andrews * Craig Andrews
* mEDI
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,

View File

@ -99,19 +99,17 @@ class AllAction extends ProfileAction
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
new Feed(Feed::RSS2, new Feed(Feed::RSS2,
common_local_url( common_local_url(
'api', array( 'ApiTimelineFriends', array(
'apiaction' => 'statuses', 'format' => 'rss',
'method' => 'friends_timeline', 'id' => $this->user->nickname
'argument' => $this->user->nickname.'.rss'
) )
), ),
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
new Feed(Feed::ATOM, new Feed(Feed::ATOM,
common_local_url( common_local_url(
'api', array( 'ApiTimelineFriends', array(
'apiaction' => 'statuses', 'format' => 'atom',
'method' => 'friends_timeline', 'id' => $this->user->nickname
'argument' => $this->user->nickname.'.atom'
) )
), ),
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)) sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))

View File

@ -157,7 +157,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
// Note: sending msgs to yourself is allowed by Twitter // Note: sending msgs to yourself is allowed by Twitter
$errmsg = 'Don\'t send a message to yourself; ' . $errmsg = 'Don\'t send a message to yourself; ' .
'just say it to yourself quietly instead.' 'just say it to yourself quietly instead.';
$this->clientError(_($errmsg), 403, $this->format); $this->clientError(_($errmsg), 403, $this->format);
return; return;

View File

@ -127,7 +127,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
if (empty($fave)) { if (empty($fave)) {
$this->clientError( $this->clientError(
_('Could not create favorite.') _('Could not create favorite.'),
403, 403,
$this->format $this->format
); );

View File

@ -38,6 +38,7 @@ if (!defined('STATUSNET')) {
} }
require_once INSTALLDIR . '/lib/apiauth.php'; require_once INSTALLDIR . '/lib/apiauth.php';
require_once INSTALLDIR . '/lib/mediafile.php';
/** /**
* Updates the authenticating user's status (posts a notice). * Updates the authenticating user's status (posts a notice).
@ -60,7 +61,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
var $source = null; var $source = null;
var $status = null; var $status = null;
var $in_reply_to_status_id = null; var $in_reply_to_status_id = null;
static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
/** /**
@ -76,25 +76,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction
{ {
parent::prepare($args); parent::prepare($args);
$this->user = $this->auth_user; $this->user = $this->auth_user;
if (empty($this->user)) {
$this->clientError(_('No such user!'), 404, $this->format);
return false;
}
$this->status = $this->trimmed('status'); $this->status = $this->trimmed('status');
if (empty($this->status)) {
$this->clientError(
'Client must provide a \'status\' parameter with a value.',
400,
$this->format
);
return false;
}
$this->source = $this->trimmed('source'); $this->source = $this->trimmed('source');
if (empty($this->source) || in_array($source, $this->reserved_sources)) { if (empty($this->source) || in_array($source, $this->reserved_sources)) {
@ -129,6 +112,27 @@ class ApiStatusesUpdateAction extends ApiAuthAction
return; return;
} }
if (empty($this->status)) {
$this->clientError(
'Client must provide a \'status\' parameter with a value.',
400,
$this->format
);
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user!'), 404, $this->format);
return;
}
// Workaround for PHP returning empty $_FILES when POST length > PHP settings
if (empty($_POST) && ($_SERVER['CONTENT_LENGTH'] > 0)) {
$this->clientError(_('Unable to handle that much POST data!'));
return;
}
$status_shortened = common_shorten_links($this->status); $status_shortened = common_shorten_links($this->status);
if (Notice::contentTooLong($status_shortened)) { if (Notice::contentTooLong($status_shortened)) {
@ -187,14 +191,40 @@ class ApiStatusesUpdateAction extends ApiAuthAction
} }
} }
$upload = null;
try {
$upload = MediaFile::fromUpload('media', $this->user);
} catch (ClientException $ce) {
$this->clientError($ce->getMessage());
return;
}
if (isset($upload)) {
$status_shortened .= ' ' . $upload->shortUrl();
if (Notice::contentTooLong($status_shortened)) {
$upload->delete();
$msg = _(
'Max notice size is %d chars, ' .
'including attachment URL.'
);
$this->clientError(sprintf($msg, Notice::maxContent()));
}
}
$this->notice = Notice::saveNew( $this->notice = Notice::saveNew(
$this->user->id, $this->user->id,
html_entity_decode($this->status, ENT_NOQUOTES, 'UTF-8'), html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8'),
$this->source, $this->source,
1, 1,
$reply_to $reply_to
); );
if (isset($upload)) {
$upload->attachToNotice($this->notice);
}
common_broadcast_notice($this->notice); common_broadcast_notice($this->notice);
} }

75
actions/bookmarklet.php Normal file
View File

@ -0,0 +1,75 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Handler for posting new notices
*
* 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 Bookmarklet
* @package StatusNet
* @author Sarven Capadisli <csarven@status.net>
* @copyright 2008-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') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR . '/actions/newnotice.php';
/**
* Action for posting a notice
*
* @category Bookmarklet
* @package StatusNet
* @author Sarven Capadisli <csarven@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 BookmarkletAction extends NewnoticeAction
{
function showTitle()
{
$this->element('title', null, _('Post to ').common_config('site', 'name'));
}
function showHeader()
{
$this->elementStart('div', array('id' => 'header'));
$this->elementStart('address');
$this->element('a', array('class' => 'url',
'href' => common_local_url('public')),
'');
$this->elementEnd('address');
if (common_logged_in()) {
$this->showNoticeForm();
}
$this->elementEnd('div');
}
function showCore()
{
}
function showFooter()
{
}
}

View File

@ -326,7 +326,7 @@ class EmailsettingsAction extends AccountSettingsAction
$this->showForm(_('Cannot normalize that email address')); $this->showForm(_('Cannot normalize that email address'));
return; return;
} }
if (!Validate::email($email, true)) { if (!Validate::email($email, common_config('email', 'check_domain'))) {
$this->showForm(_('Not a valid email address')); $this->showForm(_('Not a valid email address'));
return; return;
} else if ($user->email == $email) { } else if ($user->email == $email) {

145
actions/getfile.php Normal file
View File

@ -0,0 +1,145 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Returns a given file attachment, allowing private sites to only allow
* access to file attachments after login.
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
* @package StatusNet
* @author Jeffery To <jeffery.to@gmail.com>
* @copyright 2008-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') && !defined('LACONICA')) {
exit(1);
}
require_once 'MIME/Type.php';
/**
* Action for getting a file attachment
*
* @category Personal
* @package StatusNet
* @author Jeffery To <jeffery.to@gmail.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 GetfileAction extends Action
{
/**
* Path of file to return
*/
var $path = null;
/**
* Get file name
*
* @param array $args $_REQUEST array
*
* @return success flag
*/
function prepare($args)
{
parent::prepare($args);
$filename = $this->trimmed('filename');
$path = null;
if ($filename) {
$path = common_config('attachments', 'dir') . $filename;
}
if (empty($path) or !file_exists($path)) {
$this->clientError(_('No such file.'), 404);
return false;
}
if (!is_readable($path)) {
$this->clientError(_('Cannot read file.'), 403);
return false;
}
$this->path = $path;
return true;
}
/**
* Is this page read-only?
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* Last-modified date for file
*
* @return int last-modified date as unix timestamp
*/
function lastModified()
{
return filemtime($this->path);
}
/**
* etag for file
*
* This returns the same data (inode, size, mtime) as Apache would,
* but in decimal instead of hex.
*
* @return string etag http header
*/
function etag()
{
$stat = stat($this->path);
return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
}
/**
* Handle input, produce output
*
* @param array $args $_REQUEST contents
*
* @return void
*/
function handle($args)
{
// undo headers set by PHP sessions
$sec = session_cache_expire() * 60;
header('Expires: ' . date(DATE_RFC1123, time() + $sec));
header('Cache-Control: public, max-age=' . $sec);
header('Pragma: public');
parent::handle($args);
$path = $this->path;
header('Content-Type: ' . MIME_Type::autoDetect($path));
readfile($path);
}
}

View File

@ -179,9 +179,12 @@ class GroupMemberListItem extends ProfileListItem
function showActions() function showActions()
{ {
$this->startActions(); $this->startActions();
$this->showSubscribeButton(); if (Event::handle('StartProfileListItemActionElements', array($this))) {
$this->showMakeAdminForm(); $this->showSubscribeButton();
$this->showGroupBlockForm(); $this->showMakeAdminForm();
$this->showGroupBlockForm();
Event::handle('EndProfileListItemActionElements', array($this));
}
$this->endActions(); $this->endActions();
} }

View File

@ -68,7 +68,7 @@ class InviteAction extends CurrentUserDesignAction
foreach ($addresses as $email) { foreach ($addresses as $email) {
$email = trim($email); $email = trim($email);
if (!Validate::email($email, true)) { if (!Validate::email($email, common_config('email', 'check_domain'))) {
$this->showForm(sprintf(_('Invalid email address: %s'), $email)); $this->showForm(sprintf(_('Invalid email address: %s'), $email));
return; return;
} }

View File

@ -99,7 +99,9 @@ class NewmessageAction extends Action
$user = common_current_user(); $user = common_current_user();
if (!$user) { if (!$user) {
$this->clientError(_('Only logged-in users can send direct messages.'), 403); /* Go log in, and then come back. */
common_set_returnto($_SERVER['REQUEST_URI']);
common_redirect(common_local_url('login'));
return false; return false;
} }
@ -221,7 +223,22 @@ class NewmessageAction extends Action
} }
$this->msg = $msg; $this->msg = $msg;
$this->showPage(); if ($this->trimmed('ajax')) {
$this->startHTML('text/xml;charset=UTF-8');
$this->elementStart('head');
$this->element('title', null, _('New message'));
$this->elementEnd('head');
$this->elementStart('body');
if (common_logged_in()) {
$this->showNoticeForm();
}
$this->elementEnd('div');
$this->elementEnd('body');
$this->endHTML();
}
else {
$this->showPage();
}
} }
function showPageNotice() function showPageNotice()

View File

@ -33,7 +33,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1); exit(1);
} }
require_once INSTALLDIR.'/lib/noticelist.php'; require_once INSTALLDIR . '/lib/noticelist.php';
require_once INSTALLDIR . '/lib/mediafile.php';
/** /**
* Action for posting new notices * Action for posting new notices
@ -113,33 +114,6 @@ class NewnoticeAction extends Action
} }
} }
function getUploadedFileType() {
require_once 'MIME/Type.php';
$cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
$cmd = common_config('attachments', 'filecommand');
$filetype = MIME_Type::autoDetect($_FILES['attach']['tmp_name']);
if (in_array($filetype, common_config('attachments', 'supported'))) {
return $filetype;
}
$media = MIME_Type::getMedia($filetype);
if ('application' !== $media) {
$hint = sprintf(_(' Try using another %s format.'), $media);
} else {
$hint = '';
}
$this->clientError(sprintf(
_('%s is not a supported filetype on this server.'), $filetype) . $hint);
}
function isRespectsQuota($user) {
$file = new File;
$ret = $file->isRespectsQuota($user,$_FILES['attach']['size']);
if (true === $ret) return true;
$this->clientError($ret);
}
/** /**
* Save a new notice, based on arguments * Save a new notice, based on arguments
* *
@ -160,18 +134,12 @@ class NewnoticeAction extends Action
if (!$content) { if (!$content) {
$this->clientError(_('No content!')); $this->clientError(_('No content!'));
} else { return;
$content_shortened = common_shorten_links($content);
if (Notice::contentTooLong($content_shortened)) {
$this->clientError(sprintf(_('That\'s too long. '.
'Max notice size is %d chars.'),
Notice::maxContent()));
}
} }
$inter = new CommandInterpreter(); $inter = new CommandInterpreter();
$cmd = $inter->handle_command($user, $content_shortened); $cmd = $inter->handle_command($user, $content);
if ($cmd) { if ($cmd) {
if ($this->boolean('ajax')) { if ($this->boolean('ajax')) {
@ -182,6 +150,13 @@ class NewnoticeAction extends Action
return; return;
} }
$content_shortened = common_shorten_links($content);
if (Notice::contentTooLong($content_shortened)) {
$this->clientError(sprintf(_('That\'s too long. '.
'Max notice size is %d chars.'),
Notice::maxContent()));
}
$replyto = $this->trimmed('inreplyto'); $replyto = $this->trimmed('inreplyto');
#If an ID of 0 is wrongly passed here, it will cause a database error, #If an ID of 0 is wrongly passed here, it will cause a database error,
#so override it... #so override it...
@ -189,84 +164,37 @@ class NewnoticeAction extends Action
$replyto = 'false'; $replyto = 'false';
} }
if (isset($_FILES['attach']['error'])) { $upload = null;
switch ($_FILES['attach']['error']) { $upload = MediaFile::fromUpload('attach');
case UPLOAD_ERR_NO_FILE:
// no file uploaded, nothing to do
break;
case UPLOAD_ERR_OK: if (isset($upload)) {
$mimetype = $this->getUploadedFileType();
if (!$this->isRespectsQuota($user)) {
die('clientError() should trigger an exception before reaching here.');
}
break;
case UPLOAD_ERR_INI_SIZE: $content_shortened .= ' ' . $upload->shortUrl();
$this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
case UPLOAD_ERR_FORM_SIZE:
$this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
case UPLOAD_ERR_PARTIAL:
$this->clientError(_('The uploaded file was only partially uploaded.'));
case UPLOAD_ERR_NO_TMP_DIR:
$this->clientError(_('Missing a temporary folder.'));
case UPLOAD_ERR_CANT_WRITE:
$this->clientError(_('Failed to write file to disk.'));
case UPLOAD_ERR_EXTENSION:
$this->clientError(_('File upload stopped by extension.'));
default:
die('Should never reach here.');
}
}
if (isset($mimetype)) {
$filename = $this->saveFile($mimetype);
if (empty($filename)) {
$this->clientError(_('Couldn\'t save file.'));
}
$fileRecord = $this->storeFile($filename, $mimetype);
$fileurl = common_local_url('attachment',
array('attachment' => $fileRecord->id));
// not sure this is necessary -- Zach
$this->maybeAddRedir($fileRecord->id, $fileurl);
$short_fileurl = common_shorten_url($fileurl);
if (!$short_fileurl) {
// todo -- Consider forcing default shortener if none selected?
$short_fileurl = $fileurl;
}
$content_shortened .= ' ' . $short_fileurl;
if (Notice::contentTooLong($content_shortened)) { if (Notice::contentTooLong($content_shortened)) {
$this->deleteFile($filename); $upload->delete();
$this->clientError(sprintf(_('Max notice size is %d chars, including attachment URL.'), $this->clientError(
Notice::maxContent())); sprintf(
_('Max notice size is %d chars, including attachment URL.'),
Notice::maxContent()
)
);
} }
// Also, not sure this is necessary -- Zach
$this->maybeAddRedir($fileRecord->id, $short_fileurl);
} }
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
($replyto == 'false') ? null : $replyto); ($replyto == 'false') ? null : $replyto);
if (isset($mimetype)) { if (isset($upload)) {
$this->attachFile($notice, $fileRecord); $upload->attachToNotice($notice);
} }
common_broadcast_notice($notice); common_broadcast_notice($notice);
if ($this->boolean('ajax')) { if ($this->boolean('ajax')) {
$this->startHTML('text/xml;charset=utf-8'); header('Content-Type: text/xml;charset=utf-8');
$this->xw->startDocument('1.0', 'UTF-8');
$this->elementStart('html');
$this->elementStart('head'); $this->elementStart('head');
$this->element('title', null, _('Notice posted')); $this->element('title', null, _('Notice posted'));
$this->elementEnd('head'); $this->elementEnd('head');
@ -288,87 +216,6 @@ class NewnoticeAction extends Action
} }
} }
function saveFile($mimetype) {
$cur = common_current_user();
if (empty($cur)) {
$this->serverError(_('Somehow lost the login in saveFile'));
}
$basename = basename($_FILES['attach']['name']);
$filename = File::filename($cur->getProfile(), $basename, $mimetype);
$filepath = File::path($filename);
if (move_uploaded_file($_FILES['attach']['tmp_name'], $filepath)) {
return $filename;
} else {
$this->clientError(_('File could not be moved to destination directory.'));
}
}
function deleteFile($filename)
{
$filepath = File::path($filename);
@unlink($filepath);
}
function storeFile($filename, $mimetype) {
$file = new File;
$file->filename = $filename;
$file->url = File::url($filename);
$filepath = File::path($filename);
$file->size = filesize($filepath);
$file->date = time();
$file->mimetype = $mimetype;
$file_id = $file->insert();
if (!$file_id) {
common_log_db_error($file, "INSERT", __FILE__);
$this->clientError(_('There was a database error while saving your file. Please try again.'));
}
return $file;
}
function rememberFile($file, $short)
{
$this->maybeAddRedir($file->id, $short);
}
function maybeAddRedir($file_id, $url)
{
$file_redir = File_redirection::staticGet('url', $url);
if (empty($file_redir)) {
$file_redir = new File_redirection;
$file_redir->url = $url;
$file_redir->file_id = $file_id;
$result = $file_redir->insert();
if (!$result) {
common_log_db_error($file_redir, "INSERT", __FILE__);
$this->clientError(_('There was a database error while saving your file. Please try again.'));
}
}
}
function attachFile($notice, $filerec)
{
File_to_post::processNew($filerec->id, $notice->id);
$this->maybeAddRedir($filerec->id,
common_local_url('file', array('notice' => $notice->id)));
}
/** /**
* Show an Ajax-y error message * Show an Ajax-y error message
* *

View File

@ -103,7 +103,7 @@ class OthersettingsAction extends AccountSettingsAction
foreach($_shorteners as $name=>$value) foreach($_shorteners as $name=>$value)
{ {
$services[$name]=$name; $services[$name]=$name;
if($value['info']['freeService']){ if(!empty($value['info']['freeService'])){
// I18N // I18N
$services[$name].=' (free service)'; $services[$name].=' (free service)';
} }

View File

@ -306,6 +306,16 @@ class ProfilesettingsAction extends AccountSettingsAction
$profile->homepage = $homepage; $profile->homepage = $homepage;
$profile->bio = $bio; $profile->bio = $bio;
$profile->location = $location; $profile->location = $location;
$loc = Location::fromName($location);
if (!empty($loc)) {
$profile->lat = $loc->lat;
$profile->lon = $loc->lon;
$profile->location_id = $loc->location_id;
$profile->location_ns = $loc->location_ns;
}
$profile->profileurl = common_profile_url($nickname); $profile->profileurl = common_profile_url($nickname);
common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__); common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__);

View File

@ -131,6 +131,13 @@ class PublicAction extends Action
return _('Public timeline'); return _('Public timeline');
} }
} }
function extraHead()
{
parent::extraHead();
$this->element('meta', array('http-equiv' => 'X-XRDS-Location',
'content' => common_local_url('publicxrds')));
}
/** /**
* Output <head> elements for RSS and Atom feeds * Output <head> elements for RSS and Atom feeds
@ -143,14 +150,12 @@ class PublicAction extends Action
return array(new Feed(Feed::RSS1, common_local_url('publicrss'), return array(new Feed(Feed::RSS1, common_local_url('publicrss'),
_('Public Stream Feed (RSS 1.0)')), _('Public Stream Feed (RSS 1.0)')),
new Feed(Feed::RSS2, new Feed(Feed::RSS2,
common_local_url('api', common_local_url('ApiTimelinePublic',
array('apiaction' => 'statuses', array('format' => 'rss')),
'method' => 'public_timeline.rss')),
_('Public Stream Feed (RSS 2.0)')), _('Public Stream Feed (RSS 2.0)')),
new Feed(Feed::ATOM, new Feed(Feed::ATOM,
common_local_url('api', common_local_url('ApiTimelinePublic',
array('apiaction' => 'statuses', array('format' => 'atom')),
'method' => 'public_timeline.atom')),
_('Public Stream Feed (Atom)'))); _('Public Stream Feed (Atom)')));
} }

81
actions/publicxrds.php Normal file
View File

@ -0,0 +1,81 @@
<?php
/**
* Public XRDS for OpenID
*
* PHP version 5
*
* @category Action
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*
* 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);
}
require_once INSTALLDIR.'/plugins/OpenID/openid.php';
require_once INSTALLDIR.'/lib/xrdsoutputter.php';
/**
* Public XRDS
*
* @category Action
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@status.net>
* @author Craig Andrews <candrews@integralblue.com>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*
* @todo factor out similarities with XrdsAction
*/
class PublicxrdsAction extends Action
{
/**
* Is read only?
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* Class handler.
*
* @param array $args array of arguments
*
* @return nothing
*/
function handle($args)
{
parent::handle($args);
$xrdsOutputter = new XRDSOutputter();
$xrdsOutputter->startXRDS();
Event::handle('StartPublicXRDS', array($this,&$xrdsOutputter));
Event::handle('EndPublicXRDS', array($this,&$xrdsOutputter));
$xrdsOutputter->endXRDS();
}
}

View File

@ -191,7 +191,7 @@ class RegisterAction extends Action
if (!$this->boolean('license')) { if (!$this->boolean('license')) {
$this->showForm(_('You can\'t register if you don\'t '. $this->showForm(_('You can\'t register if you don\'t '.
'agree to the license.')); 'agree to the license.'));
} else if ($email && !Validate::email($email, true)) { } else if ($email && !Validate::email($email, common_config('email', 'check_domain'))) {
$this->showForm(_('Not a valid email address.')); $this->showForm(_('Not a valid email address.'));
} else if (!Validate::string($nickname, array('min_length' => 1, } else if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64, 'max_length' => 64,

View File

@ -138,11 +138,25 @@ class RepliesAction extends OwnerDesignAction
function getFeeds() function getFeeds()
{ {
$rssurl = common_local_url('repliesrss', return array(new Feed(Feed::RSS1,
array('nickname' => $this->user->nickname)); common_local_url('repliesrss',
$rsstitle = sprintf(_('Feed for replies to %s'), $this->user->nickname); array('nickname' => $this->user->nickname)),
sprintf(_('Replies feed for %s (RSS 1.0)'),
return array(new Feed(Feed::RSS1, $rssurl, $rsstitle)); $this->user->nickname)),
new Feed(Feed::RSS2,
common_local_url('ApiTimelineMentions',
array(
'id' => $this->user->nickname,
'format' => 'rss')),
sprintf(_('Replies feed for %s (RSS 2.0)'),
$this->user->nickname)),
new Feed(Feed::ATOM,
common_local_url('ApiTimelineMentions',
array(
'id' => $this->user->nickname,
'format' => 'atom')),
sprintf(_('Replies feed for %s (Atom)'),
$this->user->nickname)));
} }
/** /**

View File

@ -164,13 +164,25 @@ class ShowfavoritesAction extends OwnerDesignAction
function getFeeds() function getFeeds()
{ {
$feedurl = common_local_url('favoritesrss', return array(new Feed(Feed::RSS1,
array('nickname' => common_local_url('favoritesrss',
$this->user->nickname)); array('nickname' => $this->user->nickname)),
$feedtitle = sprintf(_('Feed for favorites of %s'), sprintf(_('Feed for favorites of %s (RSS 1.0)'),
$this->user->nickname); $this->user->nickname)),
new Feed(Feed::RSS2,
return array(new Feed(Feed::RSS1, $feedurl, $feedtitle)); common_local_url('ApiTimelineFavorites',
array(
'id' => $this->user->nickname,
'format' => 'rss')),
sprintf(_('Feed for favorites of %s (RSS 2.0)'),
$this->user->nickname)),
new Feed(Feed::ATOM,
common_local_url('ApiTimelineFavorites',
array(
'id' => $this->user->nickname,
'format' => 'atom')),
sprintf(_('Feed for favorites of %s (Atom)'),
$this->user->nickname)));
} }
/** /**

View File

@ -328,17 +328,15 @@ class ShowgroupAction extends GroupDesignAction
sprintf(_('Notice feed for %s group (RSS 1.0)'), sprintf(_('Notice feed for %s group (RSS 1.0)'),
$this->group->nickname)), $this->group->nickname)),
new Feed(Feed::RSS2, new Feed(Feed::RSS2,
common_local_url('api', common_local_url('ApiTimelineGroup',
array('apiaction' => 'groups', array('format' => 'rss',
'method' => 'timeline', 'id' => $this->group->nickname)),
'argument' => $this->group->nickname.'.rss')),
sprintf(_('Notice feed for %s group (RSS 2.0)'), sprintf(_('Notice feed for %s group (RSS 2.0)'),
$this->group->nickname)), $this->group->nickname)),
new Feed(Feed::ATOM, new Feed(Feed::ATOM,
common_local_url('api', common_local_url('ApiTimelineGroup',
array('apiaction' => 'groups', array('format' => 'atom',
'method' => 'timeline', 'id' => $this->group->nickname)),
'argument' => $this->group->nickname.'.atom')),
sprintf(_('Notice feed for %s group (Atom)'), sprintf(_('Notice feed for %s group (Atom)'),
$this->group->nickname)), $this->group->nickname)),
new Feed(Feed::FOAF, new Feed(Feed::FOAF,

View File

@ -172,9 +172,9 @@ class ShownoticeAction extends OwnerDesignAction
function title() function title()
{ {
if (!empty($this->profile->fullname)) { if (!empty($this->profile->fullname)) {
$base = $this->profile->fullname . ' (' . $this->user->nickname . ') '; $base = $this->profile->fullname . ' (' . $this->profile->nickname . ') ';
} else { } else {
$base = $this->user->nickname; $base = $this->profile->nickname;
} }
return sprintf(_('%1$s\'s status on %2$s'), return sprintf(_('%1$s\'s status on %2$s'),

View File

@ -128,17 +128,17 @@ class ShowstreamAction extends ProfileAction
sprintf(_('Notice feed for %s (RSS 1.0)'), sprintf(_('Notice feed for %s (RSS 1.0)'),
$this->user->nickname)), $this->user->nickname)),
new Feed(Feed::RSS2, new Feed(Feed::RSS2,
common_local_url('api', common_local_url('ApiTimelineUser',
array('apiaction' => 'statuses', array(
'method' => 'user_timeline', 'id' => $this->user->nickname,
'argument' => $this->user->nickname.'.rss')), 'format' => 'rss')),
sprintf(_('Notice feed for %s (RSS 2.0)'), sprintf(_('Notice feed for %s (RSS 2.0)'),
$this->user->nickname)), $this->user->nickname)),
new Feed(Feed::ATOM, new Feed(Feed::ATOM,
common_local_url('api', common_local_url('ApiTimelineUser',
array('apiaction' => 'statuses', array(
'method' => 'user_timeline', 'id' => $this->user->nickname,
'argument' => $this->user->nickname.'.atom')), 'format' => 'atom')),
sprintf(_('Notice feed for %s (Atom)'), sprintf(_('Notice feed for %s (Atom)'),
$this->user->nickname)), $this->user->nickname)),
new Feed(Feed::FOAF, new Feed(Feed::FOAF,
@ -348,6 +348,8 @@ class ShowstreamAction extends ProfileAction
{ {
if (Event::handle('StartProfilePageActionsSection', array(&$this, $this->profile))) { if (Event::handle('StartProfilePageActionsSection', array(&$this, $this->profile))) {
$cur = common_current_user();
$this->elementStart('div', 'entity_actions'); $this->elementStart('div', 'entity_actions');
$this->element('h2', null, _('User actions')); $this->element('h2', null, _('User actions'));
$this->elementStart('ul'); $this->elementStart('ul');
@ -379,21 +381,21 @@ class ShowstreamAction extends ProfileAction
} }
$this->elementEnd('li'); $this->elementEnd('li');
if ($cur->mutuallySubscribed($user)) { if ($cur->mutuallySubscribed($this->user)) {
// message // message
$this->elementStart('li', 'entity_send-a-message'); $this->elementStart('li', 'entity_send-a-message');
$this->element('a', array('href' => common_local_url('newmessage', array('to' => $user->id)), $this->element('a', array('href' => common_local_url('newmessage', array('to' => $this->user->id)),
'title' => _('Send a direct message to this user')), 'title' => _('Send a direct message to this user')),
_('Message')); _('Message'));
$this->elementEnd('li'); $this->elementEnd('li');
// nudge // nudge
if ($user->email && $user->emailnotifynudge) { if ($this->user->email && $this->user->emailnotifynudge) {
$this->elementStart('li', 'entity_nudge'); $this->elementStart('li', 'entity_nudge');
$nf = new NudgeForm($this, $user); $nf = new NudgeForm($this, $this->user);
$nf->show(); $nf->show();
$this->elementEnd('li'); $this->elementEnd('li');
} }

View File

@ -86,17 +86,15 @@ class TagAction extends Action
sprintf(_('Notice feed for tag %s (RSS 1.0)'), sprintf(_('Notice feed for tag %s (RSS 1.0)'),
$this->tag)), $this->tag)),
new Feed(Feed::RSS2, new Feed(Feed::RSS2,
common_local_url('api', common_local_url('ApiTimelineTag',
array('apiaction' => 'tags', array('format' => 'rss',
'method' => 'timeline', 'tag' => $this->tag)),
'argument' => $this->tag.'.rss')), sprintf(_('Notice feed for tag %s (RSS 2.0)'),
sprintf(_('Notice feed for %s group (RSS 2.0)'),
$this->tag)), $this->tag)),
new Feed(Feed::ATOM, new Feed(Feed::ATOM,
common_local_url('api', common_local_url('ApiTimelineTag',
array('apiaction' => 'tags', array('format' => 'atom',
'method' => 'timeline', 'tag' => $this->tag)),
'argument' => $this->tag.'.atom')),
sprintf(_('Notice feed for tag %s (Atom)'), sprintf(_('Notice feed for tag %s (Atom)'),
$this->tag))); $this->tag)));
} }

View File

@ -36,6 +36,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
require_once INSTALLDIR.'/lib/omb.php'; require_once INSTALLDIR.'/lib/omb.php';
require_once INSTALLDIR.'/extlib/libomb/service_provider.php'; require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php'; require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
require_once INSTALLDIR.'/lib/xrdsoutputter.php';
/** /**
* XRDS for OpenMicroBlogging * XRDS for OpenMicroBlogging
@ -49,6 +50,8 @@ require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
*/ */
class XrdsAction extends Action class XrdsAction extends Action
{ {
var $user;
/** /**
* Is read only? * Is read only?
* *
@ -58,6 +61,18 @@ class XrdsAction extends Action
{ {
return true; return true;
} }
function prepare($args)
{
parent::prepare($args);
$nickname = $this->trimmed('nickname');
$this->user = User::staticGet('nickname', $nickname);
if (!$this->user) {
$this->clientError(_('No such user.'));
return;
}
return true;
}
/** /**
* Class handler. * Class handler.
@ -69,49 +84,64 @@ class XrdsAction extends Action
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
$nickname = $this->trimmed('nickname'); $xrdsOutputter = new XRDSOutputter();
$user = User::staticGet('nickname', $nickname); $xrdsOutputter->startXRDS();
if (!$user) {
$this->clientError(_('No such user.'));
return;
}
$this->showXrds($user);
}
/** Event::handle('StartUserXRDS', array($this,&$xrdsOutputter));
* Show XRDS for a user.
*
* @param class $user XRDS for this user.
*
* @return void
*/
function showXrds($user)
{
$srv = new OMB_Service_Provider(profile_to_omb_profile($user->uri,
$user->getProfile()));
/* Use libombs default XRDS Writer. */
$xrds_writer = null;
$srv->writeXRDS(new Laconica_XRDS_Mapper(), $xrds_writer);
}
}
class Laconica_XRDS_Mapper implements OMB_XRDS_Mapper //oauth
{ $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
protected $urls; 'xml:id' => 'oauth',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'));
$xrdsOutputter->element('Type', null, 'xri://$xrds*simple');
$xrdsOutputter->showXrdsService(OAUTH_ENDPOINT_REQUEST,
common_local_url('requesttoken'),
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY, OAUTH_HMAC_SHA1));
$xrdsOutputter->showXrdsService( OAUTH_ENDPOINT_AUTHORIZE,
common_local_url('userauthorization'),
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY, OAUTH_HMAC_SHA1),
null,
$this->user->getIdentifierURI());
$xrdsOutputter->showXrdsService(OAUTH_ENDPOINT_ACCESS,
common_local_url('accesstoken'),
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY, OAUTH_HMAC_SHA1),
null,
$this->user->getIdentifierURI());
$xrdsOutputter->showXrdsService(OAUTH_ENDPOINT_RESOURCE,
null,
array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY, OAUTH_HMAC_SHA1),
null,
$this->user->getIdentifierURI());
$xrdsOutputter->elementEnd('XRD');
//omb
$xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'xml:id' => 'oauth',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'));
$xrdsOutputter->element('Type', null, 'xri://$xrds*simple');
$xrdsOutputter->showXrdsService(OMB_ENDPOINT_POSTNOTICE,
common_local_url('postnotice'));
$xrdsOutputter->showXrdsService(OMB_ENDPOINT_UPDATEPROFILE,
common_local_url('updateprofile'));
$xrdsOutputter->elementEnd('XRD');
//misc
$xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'xml:id' => 'oauth',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'));
$xrdsOutputter->showXrdsService(OAUTH_DISCOVERY,
'#oauth');
$xrdsOutputter->showXrdsService(OMB_VERSION,
'#omb');
$xrdsOutputter->elementEnd('XRD');
public function __construct() Event::handle('EndUserXRDS', array($this,&$xrdsOutputter));
{
$this->urls = array(
OAUTH_ENDPOINT_REQUEST => 'requesttoken',
OAUTH_ENDPOINT_AUTHORIZE => 'userauthorization',
OAUTH_ENDPOINT_ACCESS => 'accesstoken',
OMB_ENDPOINT_POSTNOTICE => 'postnotice',
OMB_ENDPOINT_UPDATEPROFILE => 'updateprofile');
}
public function getURL($action) $xrdsOutputter->endXRDS();
{
return common_local_url($this->urls[$action]);
} }
} }
?> ?>

View File

@ -81,7 +81,7 @@ class Avatar extends Memcached_DataObject
if (empty($server)) { if (empty($server)) {
$server = common_config('site', 'server'); $server = common_config('site', 'server');
} }
common_debug('path = ' . $path);
// XXX: protocol // XXX: protocol
return 'http://'.$server.$path.$filename; return 'http://'.$server.$path.$filename;

View File

@ -0,0 +1,46 @@
<?php
/*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 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); }
/**
* Table Definition for location_namespace
*/
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Location_namespace extends Memcached_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'location_namespace'; // table name
public $id; // int(4) primary_key not_null
public $description; // varchar(255)
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
/* Static get */
function staticGet($k,$v=NULL) {
return Memcached_DataObject::staticGet('Location_namespace',$k,$v);
}
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
}

View File

@ -66,9 +66,15 @@ class Notice extends Memcached_DataObject
public $is_local; // tinyint(1) public $is_local; // tinyint(1)
public $source; // varchar(32) public $source; // varchar(32)
public $conversation; // int(4) public $conversation; // int(4)
public $lat; // decimal(10,7)
public $lon; // decimal(10,7)
public $location_id; // int(4)
public $location_ns; // int(4)
/* Static get */ /* Static get */
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Notice',$k,$v); } function staticGet($k,$v=NULL) {
return Memcached_DataObject::staticGet('Notice',$k,$v);
}
/* the code above is auto generated do not remove the tag below */ /* the code above is auto generated do not remove the tag below */
###END_AUTOCODE ###END_AUTOCODE
@ -162,7 +168,8 @@ class Notice extends Memcached_DataObject
} }
static function saveNew($profile_id, $content, $source=null, static function saveNew($profile_id, $content, $source=null,
$is_local=Notice::LOCAL_PUBLIC, $reply_to=null, $uri=null, $created=null) { $is_local=Notice::LOCAL_PUBLIC, $reply_to=null, $uri=null, $created=null,
$lat=null, $lon=null, $location_id=null, $location_ns=null) {
$profile = Profile::staticGet($profile_id); $profile = Profile::staticGet($profile_id);
@ -172,7 +179,7 @@ class Notice extends Memcached_DataObject
throw new ClientException(_('Problem saving notice. Too long.')); throw new ClientException(_('Problem saving notice. Too long.'));
} }
if (!$profile) { if (empty($profile)) {
throw new ClientException(_('Problem saving notice. Unknown user.')); throw new ClientException(_('Problem saving notice. Unknown user.'));
} }
@ -228,6 +235,26 @@ class Notice extends Memcached_DataObject
$notice->conversation = $reply->conversation; $notice->conversation = $reply->conversation;
} }
if (!empty($lat) && !empty($lon)) {
$notice->lat = $lat;
$notice->lon = $lon;
$notice->location_id = $location_id;
$notice->location_ns = $location_ns;
} else if (!empty($location_ns) && !empty($location_id)) {
$location = Location::fromId($location_id, $location_ns);
if (!empty($location)) {
$notice->lat = $location->lat;
$notice->lon = $location->lon;
$notice->location_id = $location_id;
$notice->location_ns = $location_ns;
}
} else {
$notice->lat = $profile->lat;
$notice->lon = $profile->lon;
$notice->location_id = $profile->location_id;
$notice->location_ns = $profile->location_ns;
}
if (Event::handle('StartNoticeSave', array(&$notice))) { if (Event::handle('StartNoticeSave', array(&$notice))) {
// XXX: some of these functions write to the DB // XXX: some of these functions write to the DB
@ -269,7 +296,6 @@ class Notice extends Memcached_DataObject
// XXX: do we need to change this for remote users? // XXX: do we need to change this for remote users?
$notice->saveReplies();
$notice->saveTags(); $notice->saveTags();
$notice->addToInboxes(); $notice->addToInboxes();
@ -307,11 +333,11 @@ class Notice extends Memcached_DataObject
static function checkDupes($profile_id, $content) { static function checkDupes($profile_id, $content) {
$profile = Profile::staticGet($profile_id); $profile = Profile::staticGet($profile_id);
if (!$profile) { if (empty($profile)) {
return false; return false;
} }
$notice = $profile->getNotices(0, NOTICE_CACHE_WINDOW); $notice = $profile->getNotices(0, NOTICE_CACHE_WINDOW);
if ($notice) { if (!empty($notice)) {
$last = 0; $last = 0;
while ($notice->fetch()) { while ($notice->fetch()) {
if (time() - strtotime($notice->created) >= common_config('site', 'dupelimit')) { if (time() - strtotime($notice->created) >= common_config('site', 'dupelimit')) {
@ -337,7 +363,7 @@ class Notice extends Memcached_DataObject
static function checkEditThrottle($profile_id) { static function checkEditThrottle($profile_id) {
$profile = Profile::staticGet($profile_id); $profile = Profile::staticGet($profile_id);
if (!$profile) { if (empty($profile)) {
return false; return false;
} }
# Get the Nth notice # Get the Nth notice
@ -658,7 +684,7 @@ class Notice extends Memcached_DataObject
$cache = common_memcache(); $cache = common_memcache();
if (!$cache) { if (empty($cache)) {
return Notice::getStreamDirect($qry, $offset, $limit, null, null, $order, null); return Notice::getStreamDirect($qry, $offset, $limit, null, null, $order, null);
} }
@ -719,7 +745,7 @@ class Notice extends Memcached_DataObject
# If there are no hits, just return the value # If there are no hits, just return the value
if (!$notice) { if (empty($notice)) {
return $notice; return $notice;
} }
@ -909,6 +935,18 @@ class Notice extends Memcached_DataObject
} }
} }
$recipients = $this->saveReplies();
foreach ($recipients as $recipient) {
if (!array_key_exists($recipient, $ni)) {
$recipientUser = User::staticGet('id', $recipient);
if (!empty($recipientUser)) {
$ni[$recipient] = NOTICE_INBOX_SOURCE_REPLY;
}
}
}
$cnt = 0; $cnt = 0;
$qryhdr = 'INSERT INTO notice_inbox (user_id, notice_id, source, created) VALUES '; $qryhdr = 'INSERT INTO notice_inbox (user_id, notice_id, source, created) VALUES ';
@ -1061,12 +1099,12 @@ class Notice extends Memcached_DataObject
for ($i=0; $i<count($names); $i++) { for ($i=0; $i<count($names); $i++) {
$nickname = $names[$i]; $nickname = $names[$i];
$recipient = common_relative_profile($sender, $nickname, $this->created); $recipient = common_relative_profile($sender, $nickname, $this->created);
if (!$recipient) { if (empty($recipient)) {
continue; continue;
} }
// Don't save replies from blocked profile to local user // Don't save replies from blocked profile to local user
$recipient_user = User::staticGet('id', $recipient->id); $recipient_user = User::staticGet('id', $recipient->id);
if ($recipient_user && $recipient_user->hasBlocked($sender)) { if (!empty($recipient_user) && $recipient_user->hasBlocked($sender)) {
continue; continue;
} }
$reply = new Reply(); $reply = new Reply();
@ -1077,7 +1115,7 @@ class Notice extends Memcached_DataObject
$last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
common_log(LOG_ERR, 'DB error inserting reply: ' . $last_error->message); common_log(LOG_ERR, 'DB error inserting reply: ' . $last_error->message);
common_server_error(sprintf(_('DB error inserting reply: %s'), $last_error->message)); common_server_error(sprintf(_('DB error inserting reply: %s'), $last_error->message));
return; return array();
} else { } else {
$replied[$recipient->id] = 1; $replied[$recipient->id] = 1;
} }
@ -1101,7 +1139,7 @@ class Notice extends Memcached_DataObject
$id = $reply->insert(); $id = $reply->insert();
if (!$id) { if (!$id) {
common_log_db_error($reply, 'INSERT', __FILE__); common_log_db_error($reply, 'INSERT', __FILE__);
return; return array();
} else { } else {
$replied[$recipient->id] = 1; $replied[$recipient->id] = 1;
} }
@ -1110,12 +1148,16 @@ class Notice extends Memcached_DataObject
} }
} }
foreach (array_keys($replied) as $recipient) { $recipientIds = array_keys($replied);
foreach ($recipientIds as $recipient) {
$user = User::staticGet('id', $recipient); $user = User::staticGet('id', $recipient);
if ($user) { if ($user) {
mail_notify_attn($user, $this); mail_notify_attn($user, $this);
} }
} }
return $recipientIds;
} }
function asAtomEntry($namespace=false, $source=false) function asAtomEntry($namespace=false, $source=false)
@ -1139,10 +1181,9 @@ class Notice extends Memcached_DataObject
$xs->element('link', array('href' => $profile->profileurl)); $xs->element('link', array('href' => $profile->profileurl));
$user = User::staticGet('id', $profile->id); $user = User::staticGet('id', $profile->id);
if (!empty($user)) { if (!empty($user)) {
$atom_feed = common_local_url('api', $atom_feed = common_local_url('ApiTimelineUser',
array('apiaction' => 'statuses', array('format' => 'atom',
'method' => 'user_timeline', 'id' => $profile->nickname));
'argument' => $profile->nickname.'.atom'));
$xs->element('link', array('rel' => 'self', $xs->element('link', array('rel' => 'self',
'type' => 'application/atom+xml', 'type' => 'application/atom+xml',
'href' => $profile->profileurl)); 'href' => $profile->profileurl));
@ -1370,4 +1411,21 @@ class Notice 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 getLocation()
{
$location = null;
if (!empty($this->location_id) && !empty($this->location_ns)) {
$location = Location::fromId($this->location_id, $this->location_ns);
}
if (is_null($location)) { // no ID, or Location::fromId() failed
if (!empty($this->lat) && !empty($this->lon)) {
$location = Location::fromLatLon($this->lat, $this->lon);
}
}
return $location;
}
} }

View File

@ -37,15 +37,26 @@ class Profile extends Memcached_DataObject
public $homepage; // varchar(255) multiple_key public $homepage; // varchar(255) multiple_key
public $bio; // text() multiple_key public $bio; // text() multiple_key
public $location; // varchar(255) multiple_key public $location; // varchar(255) multiple_key
public $lat; // decimal(10,7)
public $lon; // decimal(10,7)
public $location_id; // int(4)
public $location_ns; // int(4)
public $created; // datetime() not_null public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
/* Static get */ /* Static get */
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Profile',$k,$v); } function staticGet($k,$v=NULL) {
return Memcached_DataObject::staticGet('Profile',$k,$v);
}
/* the code above is auto generated do not remove the tag below */ /* the code above is auto generated do not remove the tag below */
###END_AUTOCODE ###END_AUTOCODE
function getUser()
{
return User::staticGet('id', $this->id);
}
function getAvatar($width, $height=null) function getAvatar($width, $height=null)
{ {
if (is_null($height)) { if (is_null($height)) {
@ -551,4 +562,29 @@ class Profile extends Memcached_DataObject
$block->blocked = $this->id; $block->blocked = $this->id;
$block->delete(); $block->delete();
} }
// XXX: identical to Notice::getLocation.
function getLocation()
{
$location = null;
if (!empty($this->location_id) && !empty($this->location_ns)) {
$location = Location::fromId($this->location_id, $this->location_ns);
}
if (is_null($location)) { // no ID, or Location::fromId() failed
if (!empty($this->lat) && !empty($this->lon)) {
$location = Location::fromLatLon($this->lat, $this->lon);
}
}
if (is_null($location)) { // still haven't found it!
if (!empty($this->location)) {
$location = Location::fromName($this->location);
}
}
return $location;
}
} }

View File

@ -198,6 +198,15 @@ class User extends Memcached_DataObject
} }
if (!empty($location)) { if (!empty($location)) {
$profile->location = $location; $profile->location = $location;
$loc = Location::fromName($location);
if (!empty($loc)) {
$profile->lat = $loc->lat;
$profile->lon = $loc->lon;
$profile->location_id = $loc->location_id;
$profile->location_ns = $loc->location_ns;
}
} }
$profile->created = common_sql_now(); $profile->created = common_sql_now();
@ -319,6 +328,7 @@ class User extends Memcached_DataObject
common_config('site', 'name'), common_config('site', 'name'),
$user->nickname), $user->nickname),
'system'); 'system');
common_broadcast_notice($notice);
} }
} }

View File

@ -1,3 +1,4 @@
[avatar] [avatar]
profile_id = 129 profile_id = 129
original = 17 original = 17
@ -243,6 +244,15 @@ created = 142
[invitation__keys] [invitation__keys]
code = K code = K
[location_namespace]
id = 129
description = 2
created = 142
modified = 384
[location_namespace__keys]
id = K
[message] [message]
id = 129 id = 129
uri = 2 uri = 2
@ -284,6 +294,10 @@ reply_to = 1
is_local = 17 is_local = 17
source = 2 source = 2
conversation = 1 conversation = 1
lat = 1
lon = 1
location_id = 1
location_ns = 1
[notice__keys] [notice__keys]
id = N id = N
@ -325,6 +339,10 @@ profileurl = 2
homepage = 2 homepage = 2
bio = 34 bio = 34
location = 2 location = 2
lat = 1
lon = 1
location_id = 1
location_ns = 1
created = 142 created = 142
modified = 384 modified = 384
@ -519,6 +537,16 @@ modified = 384
canonical = K canonical = K
display = U display = U
[user_openid_trustroot]
trustroot = 130
user_id = 129
created = 142
modified = 384
[user_openid__keys]
trustroot = K
user_id = K
[user_role] [user_role]
user_id = 129 user_id = 129
role = 130 role = 130

View File

@ -104,6 +104,10 @@ $config['sphinx']['port'] = 3312;
// $config['site']['timezone'] = 'Pacific/Auckland'; // $config['site']['timezone'] = 'Pacific/Auckland';
// $config['site']['language'] = 'en_NZ'; // $config['site']['language'] = 'en_NZ';
// When validating user supplied email addresses, validate if the domain
// is running an SMTP server.
// $config['mail']['check_domain'] = true;
// Email info, used for all outbound email // Email info, used for all outbound email
// $config['mail']['notifyfrom'] = 'microblog@example.net'; // $config['mail']['notifyfrom'] = 'microblog@example.net';
// $config['mail']['domain'] = 'microblog.example.net'; // $config['mail']['domain'] = 'microblog.example.net';

View File

@ -0,0 +1,5 @@
insert into location_namespace
(id, description, created)
values
(1, 'Geonames', now()),
(2, 'Where on Earth', now());

View File

@ -1,6 +1,7 @@
/* local and remote users have profiles */ /* local and remote users have profiles */
create table profile ( create table profile (
id integer auto_increment primary key comment 'unique identifier', id integer auto_increment primary key comment 'unique identifier',
nickname varchar(64) not null comment 'nickname or username', nickname varchar(64) not null comment 'nickname or username',
fullname varchar(255) comment 'display name', fullname varchar(255) comment 'display name',
@ -8,6 +9,11 @@ create table profile (
homepage varchar(255) comment 'identifying URL', homepage varchar(255) comment 'identifying URL',
bio text comment 'descriptive biography', bio text comment 'descriptive biography',
location varchar(255) comment 'physical location', location varchar(255) comment 'physical location',
lat decimal(10,7) comment 'latitude',
lon decimal(10,7) comment 'longitude',
location_id integer comment 'location id if possible',
location_ns integer comment 'namespace for location',
created datetime not null comment 'date this record was created', created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified', modified timestamp comment 'date this record was modified',
@ -119,6 +125,10 @@ create table notice (
is_local tinyint default 0 comment 'notice was generated by a user', is_local tinyint default 0 comment 'notice was generated by a user',
source varchar(32) comment 'source of comment, like "web", "im", or "clientname"', source varchar(32) comment 'source of comment, like "web", "im", or "clientname"',
conversation integer comment 'id of root notice in this conversation' references notice (id), conversation integer comment 'id of root notice in this conversation' references notice (id),
lat decimal(10,7) comment 'latitude',
lon decimal(10,7) comment 'longitude',
location_id integer comment 'location id if possible',
location_ns integer comment 'namespace for location',
index notice_profile_id_idx (profile_id), index notice_profile_id_idx (profile_id),
index notice_conversation_idx (conversation), index notice_conversation_idx (conversation),
@ -556,3 +566,12 @@ create table user_role (
constraint primary key (user_id, role) constraint primary key (user_id, role)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table location_namespace (
id integer primary key comment 'identity for this namespace',
description varchar(255) comment 'description of the namespace',
created datetime not null comment 'date the record was created',
modified timestamp comment 'date this record was modified'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;

View File

@ -2,4 +2,4 @@ A bookmarklet is a small piece of javascript code used as a bookmark. This one w
Drag-and-drop the following link to your bookmarks bar or right-click it and add it to your browser favorites to keep it handy. Drag-and-drop the following link to your bookmarks bar or right-click it and add it to your browser favorites to keep it handy.
<a href="javascript:var%20d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='http://%%site.server%%/%%site.path%%/index.php?action=newnotice',l=d.location,e=encodeURIComponent,g=f+'&amp;status_textarea=%22'+((e(s))?e(s):e(document.title))+'%22 from '+l.href;function%20a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=800,height=570')){l.href=g;}}a();void(0);">Post to %%site.name%%</a> <a href="javascript:(function(){var%20d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='http://%%site.server%%/%%site.path%%/index.php?action=bookmarklet',l=d.location,e=encodeURIComponent,g=f+'&status_textarea=%22'+((e(s))?e(s):e(document.title))+'%22%20%E2%80%94%20'+l.href;function%20a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=450,height=200')){l.href=g;}}a();})()">Post to %%site.name%%</a>

View File

@ -20,7 +20,7 @@
/** /**
* The library version string * The library version string
*/ */
define('Auth_OpenID_VERSION', '2.1.2'); define('Auth_OpenID_VERSION', '2.1.3');
/** /**
* Require the fetcher code. * Require the fetcher code.

View File

@ -376,7 +376,7 @@ function Auth_OpenID_detectMathLibrary($exts)
// Try to load dynamic modules. // Try to load dynamic modules.
if (!$loaded) { if (!$loaded) {
foreach ($extension['modules'] as $module) { foreach ($extension['modules'] as $module) {
if (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode') && @dl($module . "." . PHP_SHLIB_SUFFIX)) { if (@dl($module . "." . PHP_SHLIB_SUFFIX)) {
$loaded = true; $loaded = true;
break; break;
} }

View File

@ -1295,7 +1295,8 @@ class Auth_OpenID_GenericConsumer {
Auth_OpenID_OPENID2_NS => array_merge($basic_sig_fields, Auth_OpenID_OPENID2_NS => array_merge($basic_sig_fields,
array('response_nonce', array('response_nonce',
'claimed_id', 'claimed_id',
'assoc_handle')), 'assoc_handle',
'op_endpoint')),
Auth_OpenID_OPENID1_NS => array_merge($basic_sig_fields, Auth_OpenID_OPENID1_NS => array_merge($basic_sig_fields,
array('nonce')) array('nonce'))
); );

View File

@ -887,6 +887,11 @@ class Auth_OpenID_Message {
function getAliasedArg($aliased_key, $default = null) function getAliasedArg($aliased_key, $default = null)
{ {
if ($aliased_key == 'ns') {
// Return the namespace URI for the OpenID namespace
return $this->getOpenIDNamespace();
}
$parts = explode('.', $aliased_key, 2); $parts = explode('.', $aliased_key, 2);
if (count($parts) != 2) { if (count($parts) != 2) {

View File

@ -138,7 +138,7 @@ class Auth_Yadis_HTTPFetcher {
* pass the URLHasAllowedScheme check or if the server's response * pass the URLHasAllowedScheme check or if the server's response
* is malformed. * is malformed.
*/ */
function get($url, $headers) function get($url, $headers = null)
{ {
trigger_error("not implemented", E_USER_ERROR); trigger_error("not implemented", E_USER_ERROR);
} }

View File

@ -127,8 +127,6 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
Auth_OpenID_USER_AGENT.' '.$curl_user_agent); Auth_OpenID_USER_AGENT.' '.$curl_user_agent);
curl_setopt($c, CURLOPT_TIMEOUT, $off); curl_setopt($c, CURLOPT_TIMEOUT, $off);
curl_setopt($c, CURLOPT_URL, $url); curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_RANGE,
"0-".(1024 * Auth_OpenID_FETCHER_MAX_RESPONSE_KB));
curl_exec($c); curl_exec($c);

View File

@ -83,8 +83,6 @@ class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher {
"User-Agent: $user_agent", "User-Agent: $user_agent",
"Host: ".$parts['host']. "Host: ".$parts['host'].
($specify_port ? ":".$parts['port'] : ""), ($specify_port ? ":".$parts['port'] : ""),
"Range: 0-".
(1024*Auth_OpenID_FETCHER_MAX_RESPONSE_KB),
"Port: ".$parts['port']); "Port: ".$parts['port']);
$errno = 0; $errno = 0;

View File

@ -91,7 +91,7 @@ class Auth_Yadis_XMLParser {
* @return array $node_list An array of matching opaque node * @return array $node_list An array of matching opaque node
* objects to be used with other methods of this parser class. * objects to be used with other methods of this parser class.
*/ */
function evalXPath($xpath, $node = null) function &evalXPath($xpath, $node = null)
{ {
// Not implemented. // Not implemented.
} }
@ -349,7 +349,7 @@ function &Auth_Yadis_getXMLParser()
foreach ($extensions as $name => $params) { foreach ($extensions as $name => $params) {
if (!extension_loaded($name)) { if (!extension_loaded($name)) {
foreach ($params['libname'] as $libname) { foreach ($params['libname'] as $libname) {
if (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode') && @dl($libname)) { if (@dl($libname)) {
$classname = $params['classname']; $classname = $params['classname'];
} }
} }

View File

@ -235,7 +235,7 @@ class DB_DataObject extends DB_DataObject_Overload
* @access private * @access private
* @var string * @var string
*/ */
var $_DB_DataObject_version = "1.8.11"; var $_DB_DataObject_version = "1.8.12";
/** /**
* The Database table (used by table extends) * The Database table (used by table extends)

View File

@ -6,9 +6,9 @@
* *
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
* LICENSE: This source file is subject to version 3.0 of the PHP license * LICENSE: This source file is subject to version 3.01 of the PHP license
* that is available through the world-wide-web at the following URI: * that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of * http://www.php.net/license/3_01.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please * the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately. * send a note to license@php.net so we can mail you a copy immediately.
* *
@ -16,8 +16,8 @@
* @package DB_DataObject * @package DB_DataObject
* @author Alan Knowles <alan@akbkhome.com> * @author Alan Knowles <alan@akbkhome.com>
* @copyright 1997-2008 The PHP Group * @copyright 1997-2008 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0 * @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version CVS: $Id: Cast.php 264148 2008-08-04 03:44:59Z alan_k $ * @version CVS: $Id: Cast.php 287158 2009-08-12 13:58:31Z alan_k $
* @link http://pear.php.net/package/DB_DataObject * @link http://pear.php.net/package/DB_DataObject
*/ */

View File

@ -7,9 +7,9 @@
* *
* PHP versions 4 and 5 * PHP versions 4 and 5
* *
* LICENSE: This source file is subject to version 3.0 of the PHP license * LICENSE: This source file is subject to version 3.01 of the PHP license
* that is available through the world-wide-web at the following URI: * that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of * http://www.php.net/license/3_01.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please * the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately. * send a note to license@php.net so we can mail you a copy immediately.
* *
@ -17,8 +17,8 @@
* @package DB_DataObject * @package DB_DataObject
* @author Alan Knowles <alan@akbkhome.com> * @author Alan Knowles <alan@akbkhome.com>
* @copyright 1997-2006 The PHP Group * @copyright 1997-2006 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License 3.0 * @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version CVS: $Id: Error.php 277015 2009-03-12 05:51:03Z alan_k $ * @version CVS: $Id: Error.php 287158 2009-08-12 13:58:31Z alan_k $
* @link http://pear.php.net/package/DB_DataObject * @link http://pear.php.net/package/DB_DataObject
*/ */

58
extlib/README Normal file
View File

@ -0,0 +1,58 @@
DO NOT "FIX" CODE IN THIS DIRECTORY.
ONLY UPSTREAM VERSIONS OF SOFTWARE GO IN THIS DIRECTORY.
This directory is provided as a courtesy to our users who might be
unable or unwilling to find and install libraries we depend on.
If we "fix" software in this directory, we hamstring users who do the
right thing and keep a single version of upstream libraries in a
system-wide library. We introduce subtle and maddening bugs where
our code is "accidentally" using the "wrong" library version. We may
unwittingly interfere with other software that depends on the
canonical release versions of those same libraries!
Forking upstream software for trivial reasons makes us bad citizens in
the Open Source community and adds unnecessary heartache for our
users. Don't make us "that" project.
FAQ:
Q: What should we do when we find a bug in upstream software?
A: First and foremost, REPORT THE BUG, and if possible send in a patch.
Watch for a release of the upstream software and integrate with it
when it's released.
In the meantime, work around the bug, if at all possible. Usually,
it's quite possible, if slightly harder or less efficient.
Q: What if the bug can't be worked around?
A: If the upstream developers have accepted a bug patch, it's
undesirable but acceptable to apply that patch to the library in
the extlib dir. Ideally, use a release version for upstream or a
version control system snapshot.
Note that this is a last resort.
Q: What if upstream is unresponsive or won't accept a patch?
A: Try again.
Q: I tried again, and upstream is still unresponsive and nobody's
checked on my patch. Now what?
A: If the upstream project is moribund and there's a way to adopt it,
propose having the StatusNet dev team adopt the project. Or, adopt
it yourself.
Q: What if there's no upstream authority and it can't be adopted?
A: Then we fork it. Make a new name and a new version. Include it in
lib/ instead of extlib/, and use the StatusNet_* prefix to change
the namespace to avoid collisions.
This is a last resort; consult with the rest of the dev group
before taking this radical step.

View File

@ -1,3 +1,19 @@
2006-02-28 Danilo Šegan <danilo@gnome.org>
* gettext.php: Added some comments about these workarounds for
different PHP versions and architectures.
2006-02-28 Danilo Šegan <danilo@gnome.org>
Fixes bug #15923.
* gettext.php (gettext_reader): make magic check work on 64-bit
platforms as well (by Steffen Pingel).
2006-02-20 Danilo Šegan <danilo@gnome.org>
* gettext.inc (_bindtextdomain): Use php_uname to detect Windows.
2006-02-07 Danilo Šegan <danilo@gnome.org> 2006-02-07 Danilo Šegan <danilo@gnome.org>
* examples/pigs_dropin.php: comment-out bind_textdomain_codeset * examples/pigs_dropin.php: comment-out bind_textdomain_codeset

View File

@ -129,7 +129,7 @@ function _setlocale($category, $locale) {
$ret = 0; $ret = 0;
if (function_exists('setlocale')) // I don't know if this ever happens ;) if (function_exists('setlocale')) // I don't know if this ever happens ;)
$ret = setlocale($category, $locale); $ret = setlocale($category, $locale);
if (($ret and $locale == '') or ($ret == $locale)) { if ($ret and ($locale == '' or $ret == $locale)) {
$EMULATEGETTEXT = 0; $EMULATEGETTEXT = 0;
$CURRENTLOCALE = $ret; $CURRENTLOCALE = $ret;
} else { } else {
@ -148,9 +148,9 @@ function _setlocale($category, $locale) {
*/ */
function _bindtextdomain($domain, $path) { function _bindtextdomain($domain, $path) {
global $text_domains; global $text_domains;
// ensure $path ends with a slash // ensure $path ends with a slash
if ($path[strlen($path) - 1] != '/') $path .= '/'; if ($path[strlen($path) - 1] != '/') $path .= '/';
elseif ($path[strlen($path) - 1] != '\\') $path .= '\\'; elseif ($path[strlen($path) - 1] != '\\') $path .= '\\';
$text_domains[$domain]->path = $path; $text_domains[$domain]->path = $path;
} }

View File

@ -102,16 +102,16 @@ class gettext_reader {
// Caching can be turned off // Caching can be turned off
$this->enable_cache = $enable_cache; $this->enable_cache = $enable_cache;
// $MAGIC1 = (int)0x950412de; //bug in PHP 5 // $MAGIC1 = (int)0x950412de; //bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
$MAGIC1 = (int) - 1794895138; $MAGIC1 = (int) - 1794895138;
// $MAGIC2 = (int)0xde120495; //bug // $MAGIC2 = (int)0xde120495; //bug
$MAGIC2 = (int) - 569244523; $MAGIC2 = (int) - 569244523;
$this->STREAM = $Reader; $this->STREAM = $Reader;
$magic = $this->readint(); $magic = $this->readint();
if ($magic == $MAGIC1) { if ($magic == ($MAGIC1 & 0xFFFFFFFF)) { // to make sure it works for 64-bit platforms
$this->BYTEORDER = 0; $this->BYTEORDER = 0;
} elseif ($magic == $MAGIC2) { } elseif ($magic == ($MAGIC2 & 0xFFFFFFFF)) {
$this->BYTEORDER = 1; $this->BYTEORDER = 1;
} else { } else {
$this->error = 1; // not MO file $this->error = 1; // not MO file

View File

@ -5,6 +5,14 @@
RewriteBase /mublog/ RewriteBase /mublog/
# If your site is private and want to only allow logged-in users to
# be able to download file attachments, uncomment this rule.
#
# If you have a custom attachment path
# ($config['attachments']['path']), change "file/" to match.
#
#RewriteRule ^file/(.*) getfile/$1
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?p=$1 [L,QSA] RewriteRule (.*) index.php?p=$1 [L,QSA]

View File

@ -143,7 +143,7 @@ function checkMirror($action_obj, $args)
function isLoginAction($action) function isLoginAction($action)
{ {
static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register'); static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds');
$login = null; $login = null;

View File

@ -692,9 +692,7 @@ function writeConf($sitename, $server, $path, $fancy, $db)
// database // database
"\$config['db']['database'] = '{$db['database']}';\n\n". "\$config['db']['database'] = '{$db['database']}';\n\n".
($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":''). ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
"\$config['db']['type'] = '{$db['type']}';\n\n". "\$config['db']['type'] = '{$db['type']}';\n\n";
"?>";
// write configuration file out to install directory // write configuration file out to install directory
$res = file_put_contents(INSTALLDIR.'/config.php', $cfg); $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);

View File

@ -14,370 +14,377 @@
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category UI interaction
* @package StatusNet
* @author Sarven Capadisli <csarven@status.net>
* @author Evan Prodromou <evan@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/
*/ */
$(document).ready(function(){ $(document).ready(function(){
var counterBlackout = false; if ($('body.user_in').length > 0) {
$('.'+SN.C.S.FormNotice).each(function() { SN.U.FormNoticeEnhancements($(this)); });
// count character on keyup
function counter(event){
if (maxLength <= 0) {
return;
}
var currentLength = $("#notice_data-text").val().length;
var remaining = maxLength - currentLength;
var counter = $("#notice_text-count");
if (remaining.toString() != counter.text()) {
if (!counterBlackout || remaining == 0) {
if (counter.text() != String(remaining)) {
counter.text(remaining);
}
if (remaining < 0) { $('.form_user_subscribe').each(function() { SN.U.FormXHR($(this)); });
$("#form_notice").addClass("warning"); $('.form_user_unsubscribe').each(function() { SN.U.FormXHR($(this)); });
} else { $('.form_favor').each(function() { SN.U.FormXHR($(this)); });
$("#form_notice").removeClass("warning"); $('.form_disfavor').each(function() { SN.U.FormXHR($(this)); });
} $('.form_group_join').each(function() { SN.U.FormXHR($(this)); });
// Skip updates for the next 500ms. $('.form_group_leave').each(function() { SN.U.FormXHR($(this)); });
// On slower hardware, updating on every keypress is unpleasant. $('.form_user_nudge').each(function() { SN.U.FormXHR($(this)); });
if (!counterBlackout) {
counterBlackout = true;
window.setTimeout(clearCounterBlackout, 500);
}
}
}
}
function clearCounterBlackout() {
// Allow keyup events to poke the counter again
counterBlackout = false;
// Check if the string changed since we last looked
counter(null);
}
function submitonreturn(event) { SN.U.NoticeReply();
if (event.keyCode == 13 || event.keyCode == 10) {
// iPhone sends \n not \r for 'return'
$("#form_notice").submit();
event.preventDefault();
event.stopPropagation();
$("#notice_data-text").blur();
$("body").focus();
return false;
}
return true;
}
// define maxLength if it wasn't defined already SN.U.NoticeDataAttach();
if (typeof(maxLength) == "undefined") { SN.U.NewDirectMessage();
maxLength = 140;
} }
if ($("#notice_data-text").length) { SN.U.NoticeAttachments();
if (maxLength > 0) {
$("#notice_data-text").bind("keyup", counter);
// run once in case there's something in there
counter();
}
$("#notice_data-text").bind("keydown", submitonreturn);
if($('body')[0].id != 'conversation') {
$("#notice_data-text").focus();
}
}
// XXX: refactor this code
var favoptions = { dataType: 'xml',
beforeSubmit: function(data, target, options) {
$(target).addClass('processing');
return true;
},
success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
var dis = new_form.id;
var fav = dis.replace('disfavor', 'favor');
$('form#'+fav).replaceWith(new_form);
$('form#'+dis).ajaxForm(disoptions).each(addAjaxHidden);
}
};
var disoptions = { dataType: 'xml',
beforeSubmit: function(data, target, options) {
$(target).addClass('processing');
return true;
},
success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
var fav = new_form.id;
var dis = fav.replace('favor', 'disfavor');
$('form#'+dis).replaceWith(new_form);
$('form#'+fav).ajaxForm(favoptions).each(addAjaxHidden);
}
};
var joinoptions = { dataType: 'xml',
success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
var leave = new_form.id;
var join = leave.replace('leave', 'join');
$('form#'+join).replaceWith(new_form);
$('form#'+leave).ajaxForm(leaveoptions).each(addAjaxHidden);
}
};
var leaveoptions = { dataType: 'xml',
success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
var join = new_form.id;
var leave = join.replace('join', 'leave');
$('form#'+leave).replaceWith(new_form);
$('form#'+join).ajaxForm(joinoptions).each(addAjaxHidden);
}
};
function addAjaxHidden() {
var ajax = document.createElement('input');
ajax.setAttribute('type', 'hidden');
ajax.setAttribute('name', 'ajax');
ajax.setAttribute('value', 1);
this.appendChild(ajax);
}
$("form.form_favor").ajaxForm(favoptions);
$("form.form_disfavor").ajaxForm(disoptions);
$("form.form_group_join").ajaxForm(joinoptions);
$("form.form_group_leave").ajaxForm(leaveoptions);
$("form.form_favor").each(addAjaxHidden);
$("form.form_disfavor").each(addAjaxHidden);
$("form.form_group_join").each(addAjaxHidden);
$("form.form_group_leave").each(addAjaxHidden);
$("#form_user_nudge").ajaxForm ({ dataType: 'xml',
beforeSubmit: function(xml) { $("#form_user_nudge input[type=submit]").attr("disabled", "disabled");
$("#form_user_nudge input[type=submit]").addClass("disabled");
},
success: function(xml) { $("#form_user_nudge").replaceWith(document._importNode($("#nudge_response", xml).get(0),true));
$("#form_user_nudge input[type=submit]").removeAttr("disabled");
$("#form_user_nudge input[type=submit]").removeClass("disabled");
}
});
$("#form_user_nudge").each(addAjaxHidden);
var Subscribe = { dataType: 'xml',
beforeSubmit: function(formData, jqForm, options) { $(".form_user_subscribe input[type=submit]").attr("disabled", "disabled");
$(".form_user_subscribe input[type=submit]").addClass("disabled");
},
success: function(xml) { var form_unsubscribe = document._importNode($('form', xml).get(0), true);
var form_unsubscribe_id = form_unsubscribe.id;
var form_subscribe_id = form_unsubscribe_id.replace('unsubscribe', 'subscribe');
$("form#"+form_subscribe_id).replaceWith(form_unsubscribe);
$("form#"+form_unsubscribe_id).ajaxForm(UnSubscribe).each(addAjaxHidden);
$("dd.subscribers").text(parseInt($("dd.subscribers").text())+1);
$(".form_user_subscribe input[type=submit]").removeAttr("disabled");
$(".form_user_subscribe input[type=submit]").removeClass("disabled");
}
};
var UnSubscribe = { dataType: 'xml',
beforeSubmit: function(formData, jqForm, options) { $(".form_user_unsubscribe input[type=submit]").attr("disabled", "disabled");
$(".form_user_unsubscribe input[type=submit]").addClass("disabled");
},
success: function(xml) { var form_subscribe = document._importNode($('form', xml).get(0), true);
var form_subscribe_id = form_subscribe.id;
var form_unsubscribe_id = form_subscribe_id.replace('subscribe', 'unsubscribe');
$("form#"+form_unsubscribe_id).replaceWith(form_subscribe);
$("form#"+form_subscribe_id).ajaxForm(Subscribe).each(addAjaxHidden);
$("#profile_send_a_new_message").remove();
$("#profile_nudge").remove();
$("dd.subscribers").text(parseInt($("dd.subscribers").text())-1);
$(".form_user_unsubscribe input[type=submit]").removeAttr("disabled");
$(".form_user_unsubscribe input[type=submit]").removeClass("disabled");
}
};
$(".form_user_subscribe").ajaxForm(Subscribe);
$(".form_user_unsubscribe").ajaxForm(UnSubscribe);
$(".form_user_subscribe").each(addAjaxHidden);
$(".form_user_unsubscribe").each(addAjaxHidden);
var PostNotice = { dataType: 'xml',
beforeSubmit: function(formData, jqForm, options) { if ($("#notice_data-text").get(0).value.length == 0) {
$("#form_notice").addClass("warning");
return false;
}
$("#form_notice").addClass("processing");
$("#notice_action-submit").attr("disabled", "disabled");
$("#notice_action-submit").addClass("disabled");
return true;
},
timeout: '60000',
error: function (xhr, textStatus, errorThrown) { $("#form_notice").removeClass("processing");
$("#notice_action-submit").removeAttr("disabled");
$("#notice_action-submit").removeClass("disabled");
if (textStatus == "timeout") {
alert ("Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists");
}
else {
if ($(".error", xhr.responseXML).length > 0) {
$('#form_notice').append(document._importNode($(".error", xhr.responseXML).get(0), true));
}
else {
var HTTP20x30x = [200, 201, 202, 203, 204, 205, 206, 300, 301, 302, 303, 304, 305, 306, 307];
if(jQuery.inArray(parseInt(xhr.status), HTTP20x30x) < 0) {
alert("Sorry! We had trouble sending your notice ("+xhr.status+" "+xhr.statusText+"). Please report the problem to the site administrator if this happens again.");
}
else {
$("#notice_data-text").val("");
if (maxLength > 0) {
counter();
}
}
}
}
},
success: function(xml) { if ($("#error", xml).length > 0) {
var result = document._importNode($("p", xml).get(0), true);
result = result.textContent || result.innerHTML;
alert(result);
}
else {
if ($("#command_result", xml).length > 0) {
var result = document._importNode($("p", xml).get(0), true);
result = result.textContent || result.innerHTML;
alert(result);
}
else {
li = $("li", xml).get(0);
if ($("#"+li.id).length == 0) {
var notice_irt_value = $('#notice_in-reply-to').val();
var notice_irt = '#notices_primary #notice-'+notice_irt_value;
if($('body')[0].id == 'conversation') {
if(notice_irt_value.length > 0 && $(notice_irt+' .notices').length < 1) {
$(notice_irt).append('<ul class="notices"></ul>');
}
$($(notice_irt+' .notices')[0]).append(document._importNode(li, true));
}
else {
$("#notices_primary .notices").prepend(document._importNode(li, true));
}
$('#'+li.id).css({display:'none'});
$('#'+li.id).fadeIn(2500);
NoticeReply();
NoticeAttachments();
}
}
$("#notice_data-text").val("");
$("#notice_data-attach").val("");
$("#notice_in-reply-to").val("");
$('#notice_data-attach_selected').remove();
if (maxLength > 0) {
counter();
}
}
$("#form_notice").removeClass("processing");
$("#notice_action-submit").removeAttr("disabled");
$("#notice_action-submit").removeClass("disabled");
}
};
$("#form_notice").ajaxForm(PostNotice);
$("#form_notice").each(addAjaxHidden);
NoticeReply();
NoticeAttachments();
NoticeDataAttach();
}); });
function NoticeReply() {
if ($('#notice_data-text').length > 0 && $('#content .notice_reply').length > 0) { var SN = { // StatusNet
$('#content .notice').each(function() { C: { // Config
var notice = $(this)[0]; I: { // Init
$($('.notice_reply', notice)[0]).click(function() { CounterBlackout: false,
var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid'); MaxLength: 140,
NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text()); PatternUsername: /^[0-9a-zA-Z\-_.]*$/,
HTTP20x30x: [200, 201, 202, 203, 204, 205, 206, 300, 301, 302, 303, 304, 305, 306, 307]
},
S: { // Selector
Disabled: 'disabled',
Warning: 'warning',
Error: 'error',
Success: 'success',
Processing: 'processing',
CommandResult: 'command_result',
FormNotice: 'form_notice',
NoticeDataText: 'notice_data-text',
NoticeTextCount: 'notice_text-count',
NoticeInReplyTo: 'notice_in-reply-to',
NoticeDataAttach: 'notice_data-attach',
NoticeDataAttachSelected: 'notice_data-attach_selected',
NoticeActionSubmit: 'notice_action-submit'
}
},
U: { // Utils
FormNoticeEnhancements: function(form) {
form_id = form.attr('id');
if (maxLength > 0) {
$('#'+form_id+' #'+SN.C.S.NoticeDataText).bind('keyup', function(e) {
SN.U.Counter(form);
});
// run once in case there's something in there
SN.U.Counter(form);
}
$('#'+form_id+' #'+SN.C.S.NoticeDataText).bind('keydown', function(e) {
SN.U.SubmitOnReturn(e, form);
});
if($('body')[0].id != 'conversation') {
$('#'+form_id+' textarea').focus();
}
SN.U.FormNoticeXHR(form);
},
SubmitOnReturn: function(event, el) {
if (event.keyCode == 13 || event.keyCode == 10) {
el.submit();
event.preventDefault();
event.stopPropagation();
$('#'+el[0].id+' #'+SN.U.NoticeDataText).blur();
$('body').focus();
return false;
}
return true;
},
Counter: function(form) {
SN.C.I.FormNoticeCurrent = form;
form_id = form.attr('id');
if (typeof(maxLength) == "undefined") {
maxLength = SN.C.I.MaxLength;
}
if (maxLength <= 0) {
return;
}
var remaining = maxLength - $('#'+form_id+' #'+SN.C.S.NoticeDataText).val().length;
var counter = $('#'+form_id+' #'+SN.C.S.NoticeTextCount);
if (remaining.toString() != counter.text()) {
if (!SN.C.I.CounterBlackout || remaining == 0) {
if (counter.text() != String(remaining)) {
counter.text(remaining);
}
if (remaining < 0) {
form.addClass(SN.C.S.Warning);
} else {
form.removeClass(SN.C.S.Warning);
}
// Skip updates for the next 500ms.
// On slower hardware, updating on every keypress is unpleasant.
if (!SN.C.I.CounterBlackout) {
SN.C.I.CounterBlackout = true;
SN.C.I.FormNoticeCurrent = form;
window.setTimeout("SN.U.ClearCounterBlackout(SN.C.I.FormNoticeCurrent);", 500);
}
}
}
},
ClearCounterBlackout: function(form) {
// Allow keyup events to poke the counter again
SN.C.I.CounterBlackout = false;
// Check if the string changed since we last looked
SN.U.Counter(form);
},
FormXHR: function(f) {
f.bind('submit', function(e) {
form_id = $(this)[0].id;
$.ajax({
type: 'POST',
dataType: 'xml',
url: $(this)[0].action,
data: $(this).serialize() + '&ajax=1',
beforeSend: function(xhr) {
$('#'+form_id).addClass(SN.C.S.Processing);
$('#'+form_id+' .submit').addClass(SN.C.S.Disabled);
$('#'+form_id+' .submit').attr(SN.C.S.Disabled, SN.C.S.Disabled);
},
error: function (xhr, textStatus, errorThrown) {
alert(errorThrown || textStatus);
},
success: function(data, textStatus) {
if (typeof($('form', data)[0]) != 'undefined') {
form_new = document._importNode($('form', data)[0], true);
$('#'+form_id).replaceWith(form_new);
$('#'+form_new.id).each(function() { SN.U.FormXHR($(this)); });
}
else {
$('#'+form_id).replaceWith(document._importNode($('p', data)[0], true));
}
}
});
return false; return false;
}); });
}); },
FormNoticeXHR: function(form) {
form_id = form.attr('id');
form.append('<input type="hidden" name="ajax" value="1"/>');
form.ajaxForm({
dataType: 'xml',
timeout: '60000',
beforeSend: function(xhr) {
if ($('#'+form_id+' #'+SN.C.S.NoticeDataText)[0].value.length === 0) {
form.addClass(SN.C.S.Warning);
return false;
}
form.addClass(SN.C.S.Processing);
$('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).addClass(SN.C.S.Disabled);
$('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).attr(SN.C.S.Disabled, SN.C.S.Disabled);
return true;
},
error: function (xhr, textStatus, errorThrown) {
form.removeClass(SN.C.S.Processing);
$('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).removeClass(SN.C.S.Disabled);
$('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).removeAttr(SN.C.S.Disabled, SN.C.S.Disabled);
if (textStatus == 'timeout') {
alert ('Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists');
}
else {
if ($('.'+SN.C.S.Error, xhr.responseXML).length > 0) {
form.append(document._importNode($('.'+SN.C.S.Error, xhr.responseXML)[0], true));
}
else {
if(jQuery.inArray(parseInt(xhr.status), SN.C.I.HTTP20x30x) < 0) {
alert('Sorry! We had trouble sending your notice ('+xhr.status+' '+xhr.statusText+'). Please report the problem to the site administrator if this happens again.');
}
else {
$('#'+form_id+' #'+SN.C.S.NoticeDataText).val('');
SN.U.Counter($('#'+SN.C.S.FormNotice));
}
}
}
},
success: function(data, textStatus) {
if ($('#'+SN.C.S.Error, data).length > 0) {
var result = document._importNode($('p', data)[0], true);
alert(result.textContent || result.innerHTML);
}
else {
if($('body')[0].id == 'bookmarklet') {
self.close();
}
if ($('#'+SN.C.S.CommandResult, data).length > 0) {
var result = document._importNode($('p', data)[0], true);
alert(result.textContent || result.innerHTML);
}
else {
notice = document._importNode($('li', data)[0], true);
if ($('#'+notice.id).length == 0) {
var notice_irt_value = $('#'+SN.C.S.NoticeInReplyTo).val();
var notice_irt = '#notices_primary #notice-'+notice_irt_value;
if($('body')[0].id == 'conversation') {
if(notice_irt_value.length > 0 && $(notice_irt+' .notices').length < 1) {
$(notice_irt).append('<ul class="notices"></ul>');
}
$($(notice_irt+' .notices')[0]).append(notice);
}
else {
$("#notices_primary .notices").prepend(notice);
}
$('#'+notice.id).css({display:'none'});
$('#'+notice.id).fadeIn(2500);
SN.U.NoticeAttachments();
SN.U.NoticeReply();
}
}
$('#'+form_id+' #'+SN.C.S.NoticeDataText).val('');
$('#'+form_id+' #'+SN.C.S.NoticeDataAttach).val('');
$('#'+form_id+' #'+SN.C.S.NoticeInReplyTo).val('');
$('#'+form_id+' #'+SN.C.S.NoticeDataAttachSelected).remove();
SN.U.Counter($('#'+SN.C.S.FormNotice));
}
},
complete: function(xhr, textStatus) {
form.removeClass(SN.C.S.Processing);
$('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).removeAttr(SN.C.S.Disabled);
$('#'+form_id+' #'+SN.C.S.NoticeActionSubmit).removeClass(SN.C.S.Disabled);
}
});
},
NoticeReply: function() {
if ($('#'+SN.C.S.NoticeDataText).length > 0 && $('#content .notice_reply').length > 0) {
$('#content .notice').each(function() {
var notice = $(this)[0];
$($('.notice_reply', notice)[0]).click(function() {
var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid');
SN.U.NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text());
return false;
});
});
}
},
NoticeReplySet: function(nick,id) {
if (nick.match(SN.C.I.PatternUsername)) {
var text = $('#'+SN.C.S.NoticeDataText);
if (text.length) {
replyto = '@' + nick + ' ';
text.val(replyto + text.val().replace(RegExp(replyto, 'i'), ''));
$('#'+SN.C.S.FormNotice+' input#'+SN.C.S.NoticeInReplyTo).val(id);
if (text.get(0).setSelectionRange) {
var len = text.val().length;
text.get(0).setSelectionRange(len,len);
text.get(0).focus();
}
return false;
}
}
return true;
},
NoticeAttachments: function() {
$.fn.jOverlay.options = {
method : 'GET',
data : '',
url : '',
color : '#000',
opacity : '0.6',
zIndex : 99,
center : false,
imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif',
bgClickToClose : true,
success : function() {
$('#jOverlayContent').append('<button>&#215;</button>');
$('#jOverlayContent button').click($.closeOverlay);
},
timeout : 0,
autoHide : true,
css : {'max-width':'542px', 'top':'5%', 'left':'32.5%'}
};
$('#content .notice a.attachment').click(function() {
$().jOverlay({url: $('address .url')[0].href+'attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'});
return false;
});
var t;
$("body:not(#shownotice) #content .notice a.thumbnail").hover(
function() {
var anchor = $(this);
$("a.thumbnail").children('img').hide();
anchor.closest(".entry-title").addClass('ov');
if (anchor.children('img').length == 0) {
t = setTimeout(function() {
$.get($('address .url')[0].href+'attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) {
anchor.append(data);
});
}, 500);
}
else {
anchor.children('img').show();
}
},
function() {
clearTimeout(t);
$("a.thumbnail").children('img').hide();
$(this).closest(".entry-title").removeClass('ov');
}
);
},
NoticeDataAttach: function() {
NDA = $('#'+SN.C.S.NoticeDataAttach);
NDA.change(function() {
S = '<div id="'+SN.C.S.NoticeDataAttachSelected+'" class="'+SN.C.S.Success+'"><code>'+$(this).val()+'</code> <button>&#215;</button></div>';
NDAS = $('#'+SN.C.S.NoticeDataAttachSelected);
(NDAS.length > 0) ? NDAS.replaceWith(S) : $('#'+SN.C.S.FormNotice).append(S);
$('#'+SN.C.S.NoticeDataAttachSelected+' button').click(function(){
$('#'+SN.C.S.NoticeDataAttachSelected).remove();
NDA.val('');
});
});
},
NewDirectMessage: function() {
NDM = $('.entity_send-a-message a');
NDM.attr({'href':NDM.attr('href')+'&ajax=1'});
NDM.click(function() {
var NDMF = $('.entity_send-a-message form');
if (NDMF.length == 0) {
$.get(NDM.attr('href'), null, function(data) {
$('.entity_send-a-message').append(document._importNode($('form', data).get(0), true));
NDMF = $('.entity_send-a-message .form_notice');
SN.U.FormNoticeEnhancements(NDMF);
NDMF.append('<button>&#215;</button>');
$('.entity_send-a-message button').click(function(){
NDMF.hide();
return false;
});
});
}
else {
NDMF.show();
$('.entity_send-a-message textarea').focus();
}
return false;
});
}
} }
} }
function NoticeReplySet(nick,id) {
rgx_username = /^[0-9a-zA-Z\-_.]*$/;
if (nick.match(rgx_username)) {
var text = $("#notice_data-text");
if (text.length) {
replyto = "@" + nick + " ";
text.val(replyto + text.val().replace(RegExp(replyto, 'i'), ''));
$("#form_notice input#notice_in-reply-to").val(id);
if (text.get(0).setSelectionRange) {
var len = text.val().length;
text.get(0).setSelectionRange(len,len);
text.get(0).focus();
}
return false;
}
}
return true;
}
function NoticeAttachments() {
$.fn.jOverlay.options = {
method : 'GET',
data : '',
url : '',
color : '#000',
opacity : '0.6',
zIndex : 99,
center : false,
imgLoading : $('address .url')[0].href+'theme/base/images/illustrations/illu_progress_loading-01.gif',
bgClickToClose : true,
success : function() {
$('#jOverlayContent').append('<button>&#215;</button>');
$('#jOverlayContent button').click($.closeOverlay);
},
timeout : 0,
autoHide : true,
css : {'max-width':'542px', 'top':'5%', 'left':'32.5%'}
};
$('#content .notice a.attachment').click(function() {
$().jOverlay({url: $('address .url')[0].href+'attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'});
return false;
});
var t;
$("body:not(#shownotice) #content .notice a.thumbnail").hover(
function() {
var anchor = $(this);
$("a.thumbnail").children('img').hide();
anchor.closest(".entry-title").addClass('ov');
if (anchor.children('img').length == 0) {
t = setTimeout(function() {
$.get($('address .url')[0].href+'attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) {
anchor.append(data);
});
}, 500);
}
else {
anchor.children('img').show();
}
},
function() {
clearTimeout(t);
$("a.thumbnail").children('img').hide();
$(this).closest(".entry-title").removeClass('ov');
}
);
}
function NoticeDataAttach() {
NDA = $('#notice_data-attach');
NDA.change(function() {
S = '<div id="notice_data-attach_selected" class="success"><code>'+$(this).val()+'</code> <button>&#215;</button></div>';
NDAS = $('#notice_data-attach_selected');
(NDAS.length > 0) ? NDAS.replaceWith(S) : $('#form_notice').append(S);
$('#notice_data-attach_selected button').click(function(){
$('#notice_data-attach_selected').remove();
NDA.val('');
});
});
}

View File

@ -134,11 +134,19 @@ class ApiAction extends Action
$twitter_user['protected'] = false; # not supported by StatusNet yet $twitter_user['protected'] = false; # not supported by StatusNet yet
$twitter_user['followers_count'] = $profile->subscriberCount(); $twitter_user['followers_count'] = $profile->subscriberCount();
// To be supported soon... // Need to pull up the user for some of this
$twitter_user['profile_background_color'] = ''; $user = $profile->getUser();
$twitter_user['profile_text_color'] = ''; $design = $user->getDesign();
$twitter_user['profile_link_color'] = ''; $defaultDesign = Design::siteDesign();
$twitter_user['profile_sidebar_fill_color'] = ''; if (!$design) $design = $defaultDesign;
$color = Design::toWebColor(empty($design->backgroundcolor) ? $defaultDesign->backgroundcolor : $design->backgroundcolor);
$twitter_user['profile_background_color'] = ($color == null) ? '' : '#'.$color->hexValue();
$color = Design::toWebColor(empty($design->textcolor) ? $defaultDesign->textcolor : $design->textcolor);
$twitter_user['profile_text_color'] = ($color == null) ? '' : '#'.$color->hexValue();
$color = Design::toWebColor(empty($design->linkcolor) ? $defaultDesign->linkcolor : $design->linkcolor);
$twitter_user['profile_link_color'] = ($color == null) ? '' : '#'.$color->hexValue();
$color = Design::toWebColor(empty($design->sidebarcolor) ? $defaultDesign->sidebarcolor : $design->sidebarcolor);
$twitter_user['profile_sidebar_fill_color'] = ($color == null) ? '' : '#'.$color->hexValue();
$twitter_user['profile_sidebar_border_color'] = ''; $twitter_user['profile_sidebar_border_color'] = '';
$twitter_user['friends_count'] = $profile->subscriptionCount(); $twitter_user['friends_count'] = $profile->subscriptionCount();
@ -147,8 +155,6 @@ class ApiAction extends Action
$twitter_user['favourites_count'] = $profile->faveCount(); // British spelling! $twitter_user['favourites_count'] = $profile->faveCount(); // British spelling!
// Need to pull up the user for some of this
$user = User::staticGet($profile->id);
$timezone = 'UTC'; $timezone = 'UTC';

View File

@ -73,7 +73,7 @@ class UntrackCommand extends UnimplementedCommand
} }
} }
class NudgeCommand extends UnimplementedCommand class NudgeCommand extends Command
{ {
var $other = null; var $other = null;
function __construct($user, $other) function __construct($user, $other)
@ -81,6 +81,26 @@ class NudgeCommand extends UnimplementedCommand
parent::__construct($user); parent::__construct($user);
$this->other = $other; $this->other = $other;
} }
function execute($channel)
{
$recipient = User::staticGet('nickname', $this->other);
if(! $recipient){
$channel->error($this->user, sprintf(_('Could not find a user with nickname %s'),
$this->other));
}else{
if ($recipient->id == $this->user->id) {
$channel->error($this->user, _('It does not make a lot of sense to nudge yourself!'));
}else{
if ($recipient->email && $recipient->emailnotifynudge) {
mail_notify_nudge($this->user, $recipient);
}
// XXX: notify by IM
// XXX: notify by SMS
$channel->output($this->user, sprintf(_('Nudge sent to %s'),
$recipient->nickname));
}
}
}
} }
class InviteCommand extends UnimplementedCommand class InviteCommand extends UnimplementedCommand
@ -124,18 +144,30 @@ class FavCommand extends Command
function execute($channel) function execute($channel)
{ {
if(substr($this->other,0,1)=='#'){
//favoriting a specific notice_id
$recipient = $notice = Notice::staticGet(substr($this->other,1));
common_relative_profile($this->user, common_canonical_nickname($this->other)); if (!$notice) {
$channel->error($this->user, _('Notice with that id does not exist'));
return;
}
$recipient = $notice->getProfile();
}else{
//favoriting a given user's last notice
if (!$recipient) { $recipient =
$channel->error($this->user, _('No such user.')); common_relative_profile($this->user, common_canonical_nickname($this->other));
return;
} if (!$recipient) {
$notice = $recipient->getCurrentNotice(); $channel->error($this->user, _('No such user.'));
if (!$notice) { return;
$channel->error($this->user, _('User has no last notice')); }
return; $notice = $recipient->getCurrentNotice();
if (!$notice) {
$channel->error($this->user, _('User has no last notice'));
return;
}
} }
$fave = Fave::addNew($this->user, $notice); $fave = Fave::addNew($this->user, $notice);
@ -347,6 +379,71 @@ class MessageCommand extends Command
} }
} }
class ReplyCommand extends Command
{
var $other = null;
var $text = null;
function __construct($user, $other, $text)
{
parent::__construct($user);
$this->other = $other;
$this->text = $text;
}
function execute($channel)
{
if(substr($this->other,0,1)=='#'){
//replying to 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{
//replying to 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;
}
}
$len = mb_strlen($this->text);
if ($len == 0) {
$channel->error($this->user, _('No content!'));
return;
}
$this->text = common_shorten_links($this->text);
if (Notice::contentTooLong($this->text)) {
$channel->error($this->user, sprintf(_('Notice too long - maximum is %d characters, you sent %d'),
Notice::maxContent(), mb_strlen($this->text)));
return;
}
$notice = Notice::saveNew($this->user->id, $this->text, $channel->source(), 1,
$notice->id);
if ($notice) {
$channel->output($this->user, sprintf(_('Reply to %s sent'), $recipient->nickname));
} else {
$channel->error($this->user, _('Error saving notice.'));
}
common_broadcast_notice($notice);
}
}
class GetCommand extends Command class GetCommand extends Command
{ {
@ -497,6 +594,9 @@ class HelpCommand extends Command
"get <nickname> - get last notice from user\n". "get <nickname> - get last notice from user\n".
"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".
"reply #<notice_id> - reply to notice with a given id\n".
"reply <nickname> - reply to the last notice from user\n".
"join <group> - join group\n". "join <group> - join group\n".
"drop <group> - leave group\n". "drop <group> - leave group\n".
"stats - get your stats\n". "stats - get your stats\n".
@ -507,7 +607,7 @@ class HelpCommand extends Command
"last <nickname> - same as 'get'\n". "last <nickname> - same as 'get'\n".
"on <nickname> - not yet implemented.\n". "on <nickname> - not yet implemented.\n".
"off <nickname> - not yet implemented.\n". "off <nickname> - not yet implemented.\n".
"nudge <nickname> - not yet implemented.\n". "nudge <nickname> - remind a user to update.\n".
"invite <phone number> - not yet implemented.\n". "invite <phone number> - not yet implemented.\n".
"track <word> - not yet implemented.\n". "track <word> - not yet implemented.\n".
"untrack <word> - not yet implemented.\n". "untrack <word> - not yet implemented.\n".

View File

@ -134,6 +134,17 @@ class CommandInterpreter
} else { } else {
return new MessageCommand($user, $other, $extra); return new MessageCommand($user, $other, $extra);
} }
case 'r':
case 'reply':
if (!$arg) {
return null;
}
list($other, $extra) = $this->split_arg($arg);
if (!$extra) {
return null;
} else {
return new ReplyCommand($user, $other, $extra);
}
case 'whois': case 'whois':
if (!$arg) { if (!$arg) {
return null; return null;

View File

@ -185,7 +185,14 @@ function _have_config()
} }
// XXX: Throw a conniption if database not installed // XXX: Throw a conniption if database not installed
// XXX: Find a way to use htmlwriter for this instead of handcoded markup
if (!_have_config()) {
echo '<p>'. _('No configuation file found. ') .'</p>';
echo '<p>'. _('I looked for configuration files in the following places: ') .'<br/> '. implode($_config_files, '<br/>');
echo '<p>'. _('You may wish to run the installer to fix this.') .'</p>';
echo '<a href="install.php">'. _('Go to the installer.') .'</a>';
exit;
}
// Fixup for statusnet.ini // Fixup for statusnet.ini
$_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1); $_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1);
@ -223,7 +230,6 @@ require_once INSTALLDIR.'/lib/theme.php';
require_once INSTALLDIR.'/lib/mail.php'; require_once INSTALLDIR.'/lib/mail.php';
require_once INSTALLDIR.'/lib/subs.php'; require_once INSTALLDIR.'/lib/subs.php';
require_once INSTALLDIR.'/lib/Shorturl_api.php'; require_once INSTALLDIR.'/lib/Shorturl_api.php';
require_once INSTALLDIR.'/lib/twitter.php';
require_once INSTALLDIR.'/lib/clientexception.php'; require_once INSTALLDIR.'/lib/clientexception.php';
require_once INSTALLDIR.'/lib/serverexception.php'; require_once INSTALLDIR.'/lib/serverexception.php';

View File

@ -98,34 +98,37 @@ class ConnectSettingsNav extends Widget
function show() function show()
{ {
# action => array('prompt', 'title')
$menu = array();
if (common_config('xmpp', 'enabled')) {
$menu['imsettings'] =
array(_('IM'),
_('Updates by instant messenger (IM)'));
}
if (common_config('sms', 'enabled')) {
$menu['smssettings'] =
array(_('SMS'),
_('Updates by SMS'));
}
if (common_config('twitter', 'enabled')) {
$menu['twittersettings'] =
array(_('Twitter'),
_('Twitter integration options'));
}
$action_name = $this->action->trimmed('action'); $action_name = $this->action->trimmed('action');
$this->action->elementStart('ul', array('class' => 'nav')); $this->action->elementStart('ul', array('class' => 'nav'));
foreach ($menu as $menuaction => $menudesc) { if (Event::handle('StartConnectSettingsNav', array(&$this->action))) {
$this->action->menuItem(common_local_url($menuaction),
$menudesc[0], # action => array('prompt', 'title')
$menudesc[1], $menu = array();
$action_name === $menuaction); if (common_config('xmpp', 'enabled')) {
$menu['imsettings'] =
array(_('IM'),
_('Updates by instant messenger (IM)'));
}
if (common_config('sms', 'enabled')) {
$menu['smssettings'] =
array(_('SMS'),
_('Updates by SMS'));
}
foreach ($menu as $menuaction => $menudesc) {
$this->action->menuItem(common_local_url($menuaction),
$menudesc[0],
$menudesc[1],
$action_name === $menuaction);
}
Event::handle('EndConnectSettingsNav', array(&$this->action));
} }
$this->action->elementEnd('ul'); $this->action->elementEnd('ul');
} }
} }

View File

@ -1,4 +1,4 @@
n<?php <?php
/** /**
* StatusNet, the distributed open-source microblogging tool * StatusNet, the distributed open-source microblogging tool
* *

View File

@ -84,7 +84,8 @@ $default =
'image' => 'http://i.creativecommons.org/l/by/3.0/80x15.png'), 'image' => 'http://i.creativecommons.org/l/by/3.0/80x15.png'),
'mail' => 'mail' =>
array('backend' => 'mail', array('backend' => 'mail',
'params' => null), 'params' => null,
'domain_check' => true),
'nickname' => 'nickname' =>
array('blacklist' => array(), array('blacklist' => array(),
'featured' => array()), 'featured' => array()),
@ -140,21 +141,21 @@ $default =
array('enabled' => true), array('enabled' => true),
'sms' => 'sms' =>
array('enabled' => true), array('enabled' => true),
'twitterbridge' => 'twitterimport' =>
array('enabled' => false), array('enabled' => false),
'integration' => 'integration' =>
array('source' => 'StatusNet', # source attribute for Twitter array('source' => 'StatusNet', # source attribute for Twitter
'taguri' => $_server.',2009'), # base for tag URIs 'taguri' => $_server.',2009'), # base for tag URIs
'twitter' => 'twitter' =>
array('enabled' => true, array('enabled' => true,
'consumer_key' => null, 'consumer_key' => null,
'consumer_secret' => null), 'consumer_secret' => null),
'memcached' => 'memcached' =>
array('enabled' => false, array('enabled' => false,
'server' => 'localhost', 'server' => 'localhost',
'base' => null, 'base' => null,
'port' => 11211), 'port' => 11211),
'ping' => 'ping' =>
array('notify' => array()), array('notify' => array()),
'inboxes' => 'inboxes' =>
array('enabled' => true), # ignored after 0.9.x array('enabled' => true), # ignored after 0.9.x
@ -200,12 +201,12 @@ $default =
'video/mp4', 'video/mp4',
'video/quicktime', 'video/quicktime',
'video/mpeg'), 'video/mpeg'),
'file_quota' => 5000000, 'file_quota' => 5000000,
'user_quota' => 50000000, 'user_quota' => 50000000,
'monthly_quota' => 15000000, 'monthly_quota' => 15000000,
'uploads' => true, 'uploads' => true,
'filecommand' => '/usr/bin/file', 'filecommand' => '/usr/bin/file',
), ),
'group' => 'group' =>
array('maxaliases' => 3, array('maxaliases' => 3,
'desclimit' => null), 'desclimit' => null),
@ -229,4 +230,6 @@ $default =
array('contentlimit' => null), array('contentlimit' => null),
'http' => 'http' =>
array('client' => 'curl'), // XXX: should this be the default? array('client' => 'curl'), // XXX: should this be the default?
'location' =>
array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth
); );

View File

@ -48,7 +48,7 @@ if (!defined('STATUSNET')) {
class HTTPResponse class HTTPResponse
{ {
public $code = null; public $code = null;
public $headers = null; public $headers = array();
public $body = null; public $body = null;
} }

View File

@ -176,6 +176,7 @@ function jabber_format_entry($profile, $notice)
$xs = new XMLStringer(); $xs = new XMLStringer();
$xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im')); $xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im'));
$xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml')); $xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml'));
$xs->element("img", array('src'=> $profile->avatarUrl(AVATAR_MINI_SIZE) , 'alt' => $profile->nickname));
$xs->element('a', array('href' => $profile->profileurl), $xs->element('a', array('href' => $profile->profileurl),
$profile->nickname); $profile->nickname);
$xs->text(": "); $xs->text(": ");
@ -184,6 +185,11 @@ function jabber_format_entry($profile, $notice)
} else { } else {
$xs->raw(common_render_content($notice->content, $notice)); $xs->raw(common_render_content($notice->content, $notice));
} }
$xs->raw(" ");
$xs->element('a', array(
'href'=>common_local_url('conversation',
array('id' => $notice->conversation)).'#notice-'.$notice->id
),sprintf(_('notice id: %s'),$notice->id));
$xs->elementEnd('body'); $xs->elementEnd('body');
$xs->elementEnd('html'); $xs->elementEnd('html');

View File

@ -101,35 +101,36 @@ function get_nice_language_list()
*/ */
function get_all_languages() { function get_all_languages() {
return array( return array(
'bg' => array('q' => 0.8, 'lang' => 'bg_BG', 'name' => 'Bulgarian', 'direction' => 'ltr'), 'bg' => array('q' => 0.8, 'lang' => 'bg', 'name' => 'Bulgarian', 'direction' => 'ltr'),
'ca' => array('q' => 0.5, 'lang' => 'ca_ES', 'name' => 'Catalan', 'direction' => 'ltr'), 'ca' => array('q' => 0.5, 'lang' => 'ca', 'name' => 'Catalan', 'direction' => 'ltr'),
'cs' => array('q' => 0.5, 'lang' => 'cs_CZ', 'name' => 'Czech', 'direction' => 'ltr'), 'cs' => array('q' => 0.5, 'lang' => 'cs', 'name' => 'Czech', 'direction' => 'ltr'),
'de' => array('q' => 0.8, 'lang' => 'de_DE', 'name' => 'German', 'direction' => 'ltr'), 'de' => array('q' => 0.8, 'lang' => 'de', 'name' => 'German', 'direction' => 'ltr'),
'el' => array('q' => 0.1, 'lang' => 'el', 'name' => 'Greek', 'direction' => 'ltr'), 'el' => array('q' => 0.1, 'lang' => 'el', 'name' => 'Greek', 'direction' => 'ltr'),
'en-us' => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'), 'en-us' => array('q' => 1, 'lang' => 'en', 'name' => 'English (US)', 'direction' => 'ltr'),
'en-gb' => array('q' => 1, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'), 'en-gb' => array('q' => 1, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'),
'en' => array('q' => 1, 'lang' => 'en_US', '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'),
'fr-fr' => array('q' => 1, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'), 'fr-fr' => array('q' => 1, 'lang' => 'fr', 'name' => 'French', 'direction' => 'ltr'),
'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'rtl'), 'ga' => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Galician', 'direction' => 'ltr'),
'it' => array('q' => 1, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'ltr'), 'he' => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'),
'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'), 'it' => array('q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'),
'ko' => array('q' => 0.9, 'lang' => 'ko_KR', 'name' => 'Korean', 'direction' => 'ltr'), 'jp' => array('q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', 'direction' => 'ltr'),
'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'), 'ko' => array('q' => 0.9, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'),
'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), 'mk' => array('q' => 0.5, 'lang' => 'mk', 'name' => 'Macedonian', 'direction' => 'ltr'),
'no' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), 'nb' => array('q' => 0.1, 'lang' => 'nb', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
'nn' => array('q' => 1, 'lang' => 'nn_NO', 'name' => 'Norwegian (Nynorsk)', 'direction' => 'ltr'), 'no' => array('q' => 0.1, 'lang' => 'nb', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
'nl' => array('q' => 0.5, 'lang' => 'nl_NL', 'name' => 'Dutch', 'direction' => 'ltr'), 'nn' => array('q' => 1, 'lang' => 'nn', 'name' => 'Norwegian (Nynorsk)', 'direction' => 'ltr'),
'pl' => array('q' => 0.5, 'lang' => 'pl_PL', 'name' => 'Polish', 'direction' => 'ltr'), 'nl' => array('q' => 0.5, 'lang' => 'nl', 'name' => 'Dutch', 'direction' => 'ltr'),
'pl' => array('q' => 0.5, 'lang' => 'pl', 'name' => 'Polish', 'direction' => 'ltr'),
'pt' => array('q' => 0.1, 'lang' => 'pt', 'name' => 'Portuguese', 'direction' => 'ltr'), 'pt' => array('q' => 0.1, 'lang' => 'pt', 'name' => 'Portuguese', 'direction' => 'ltr'),
'pt-br' => array('q' => 0.9, 'lang' => 'pt_BR', 'name' => 'Portuguese Brazil', 'direction' => 'ltr'), 'pt-br' => array('q' => 0.9, 'lang' => 'pt_BR', 'name' => 'Portuguese Brazil', 'direction' => 'ltr'),
'ru' => array('q' => 0.9, 'lang' => 'ru_RU', 'name' => 'Russian', 'direction' => 'ltr'), 'ru' => array('q' => 0.9, 'lang' => 'ru', 'name' => 'Russian', 'direction' => 'ltr'),
'sv' => array('q' => 0.8, 'lang' => 'sv_SE', 'name' => 'Swedish', 'direction' => 'ltr'), 'sv' => array('q' => 0.8, 'lang' => 'sv', 'name' => 'Swedish', 'direction' => 'ltr'),
'te' => array('q' => 0.3, 'lang' => 'te_IN', 'name' => 'Telugu', 'direction' => 'ltr'), 'te' => array('q' => 0.3, 'lang' => 'te', 'name' => 'Telugu', 'direction' => 'ltr'),
'tr' => array('q' => 0.5, 'lang' => 'tr_TR', 'name' => 'Turkish', 'direction' => 'ltr'), 'tr' => array('q' => 0.5, 'lang' => 'tr', 'name' => 'Turkish', 'direction' => 'ltr'),
'uk' => array('q' => 1, 'lang' => 'uk_UA', 'name' => 'Ukrainian', 'direction' => 'ltr'), 'uk' => array('q' => 1, 'lang' => 'uk', 'name' => 'Ukrainian', 'direction' => 'ltr'),
'vi' => array('q' => 0.8, 'lang' => 'vi_VN', 'name' => 'Vietnamese', 'direction' => 'ltr'), 'vi' => array('q' => 0.8, 'lang' => 'vi', 'name' => 'Vietnamese', 'direction' => 'ltr'),
'zh-cn' => array('q' => 0.9, 'lang' => 'zh_CN', 'name' => 'Chinese (Simplified)', 'direction' => 'ltr'), 'zh-cn' => array('q' => 0.9, 'lang' => 'zh_CN', 'name' => 'Chinese (Simplified)', 'direction' => 'ltr'),
'zh-hant' => array('q' => 0.2, 'lang' => 'zh_TW', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'), 'zh-hant' => array('q' => 0.2, 'lang' => 'zh_TW', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'),
); );

188
lib/location.php Normal file
View File

@ -0,0 +1,188 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Class for locations
*
* 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 Location
* @package StatusNet
* @author Evan Prodromou <evan@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') && !defined('LACONICA')) {
exit(1);
}
/**
* class for locations
*
* These are stored in the DB as part of notice and profile records,
* but since they're about the same in both, we have a separate class
* for them.
*
* @category Location
* @package StatusNet
* @author Evan Prodromou <evan@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 Location
{
public $lat;
public $lon;
public $location_id;
public $location_ns;
private $_url;
var $names = array();
/**
* Constructor that makes a Location from a string name
*
* @param string $name Human-readable name (any kind)
* @param string $language Language, default = common_language()
*
* @return Location Location with that name (or null if not found)
*/
static function fromName($name, $language=null)
{
if (is_null($language)) {
$language = common_language();
}
$location = null;
// Let a third-party handle it
Event::handle('LocationFromName', array($name, $language, &$location));
return $location;
}
/**
* Constructor that makes a Location from an ID
*
* @param integer $id Identifier ID
* @param integer $ns Namespace of the identifier
* @param string $language Language to return name in (default is common)
*
* @return Location The location with this ID (or null if none)
*/
static function fromId($id, $ns, $language=null)
{
if (is_null($language)) {
$language = common_language();
}
$location = null;
// Let a third-party handle it
Event::handle('LocationFromId', array($id, $ns, $language, &$location));
return $location;
}
/**
* Constructor that finds the nearest location to a lat/lon pair
*
* @param float $lat Latitude
* @param float $lon Longitude
* @param string $language Language for results, default = current
*
* @return Location the location found, or null if none found
*/
static function fromLatLon($lat, $lon, $language=null)
{
if (is_null($language)) {
$language = common_language();
}
$location = null;
// Let a third-party handle it
if (Event::handle('LocationFromLatLon',
array($lat, $lon, $language, &$location))) {
// Default is just the lat/lon pair
$location = new Location();
$location->lat = $lat;
$location->lon = $lon;
}
return $location;
}
/**
* Get the name for this location in the given language
*
* @param string $language language to use, default = current
*
* @return string location name or null if not found
*/
function getName($language=null)
{
if (is_null($language)) {
$language = common_language();
}
if (array_key_exists($language, $this->names)) {
return $this->names[$language];
} else {
$name = null;
Event::handle('LocationNameLanguage', array($this, $language, &$name));
if (!empty($name)) {
$this->names[$language] = $name;
return $name;
}
}
}
/**
* Get an URL suitable for this location
*
* @return string URL for this location or NULL
*/
function getURL()
{
// Keep one cached
if (is_string($this->_url)) {
return $this->_url;
}
$url = null;
Event::handle('LocationUrl', array($this, &$url));
$this->_url = $url;
return $url;
}
}

View File

@ -640,75 +640,3 @@ function mail_notify_attn($user, $notice)
mail_to_user($user, $subject, $body); mail_to_user($user, $subject, $body);
} }
/**
* Send a mail message to notify a user that her Twitter bridge link
* has stopped working, and therefore has been removed. This can
* happen when the user changes her Twitter password, or otherwise
* revokes access.
*
* @param User $user user whose Twitter bridge link has been removed
*
* @return boolean success flag
*/
function mail_twitter_bridge_removed($user)
{
common_init_locale($user->language);
$profile = $user->getProfile();
$subject = sprintf(_('Your Twitter bridge has been disabled.'));
$site_name = common_config('site', 'name');
$body = sprintf(_('Hi, %1$s. We\'re sorry to inform you that your ' .
'link to Twitter has been disabled. We no longer seem to have ' .
'permission to update your Twitter status. (Did you revoke ' .
'%3$s\'s access?)' . "\n\n" .
'You can re-enable your Twitter bridge by visiting your ' .
"Twitter settings page:\n\n\t%2\$s\n\n" .
"Regards,\n%3\$s\n"),
$profile->getBestName(),
common_local_url('twittersettings'),
common_config('site', 'name'));
common_init_locale();
return mail_to_user($user, $subject, $body);
}
/**
* Send a mail message to notify a user that her Facebook Application
* access has been removed.
*
* @param User $user user whose Facebook app link has been removed
*
* @return boolean success flag
*/
function mail_facebook_app_removed($user)
{
common_init_locale($user->language);
$profile = $user->getProfile();
$site_name = common_config('site', 'name');
$subject = sprintf(
_('Your %1$s Facebook application access has been disabled.',
$site_name));
$body = sprintf(_("Hi, %1\$s. We're sorry to inform you that we are " .
'unable to update your Facebook status from %2$s, and have disabled ' .
'the Facebook application for your account. This may be because ' .
'you have removed the Facebook application\'s authorization, or ' .
'have deleted your Facebook account. You can re-enable the ' .
'Facebook application and automatic status updating by ' .
"re-installing the %2\$s Facebook application.\n\nRegards,\n\n%2\$s"),
$user->nickname, $site_name);
common_init_locale();
return mail_to_user($user, $subject, $body);
}

284
lib/mediafile.php Normal file
View File

@ -0,0 +1,284 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Abstraction for media files in general
*
* TODO: combine with ImageFile?
*
* 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 Media
* @package StatusNet
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2008-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') && !defined('LACONICA')) {
exit(1);
}
class MediaFile
{
var $filename = null;
var $fileRecord = null;
var $user = null;
var $fileurl = null;
var $short_fileurl = null;
var $mimetype = null;
function __construct($user = null, $filename = null, $mimetype = null)
{
if ($user == null) {
$this->user = common_current_user();
}
$this->filename = $filename;
$this->mimetype = $mimetype;
$this->fileRecord = $this->storeFile();
$this->fileurl = common_local_url('attachment',
array('attachment' => $this->fileRecord->id));
$this->maybeAddRedir($this->fileRecord->id, $this->fileurl);
$this->short_fileurl = common_shorten_url($this->fileurl);
$this->maybeAddRedir($this->fileRecord->id, $this->short_fileurl);
}
function attachToNotice($notice)
{
File_to_post::processNew($this->fileRecord->id, $notice->id);
$this->maybeAddRedir($this->fileRecord->id,
common_local_url('file', array('notice' => $notice->id)));
}
function shortUrl()
{
return $this->short_fileurl;
}
function delete()
{
$filepath = File::path($this->filename);
@unlink($filepath);
}
function storeFile() {
$file = new File;
$file->filename = $this->filename;
$file->url = File::url($this->filename);
$filepath = File::path($this->filename);
$file->size = filesize($filepath);
$file->date = time();
$file->mimetype = $this->mimetype;
$file_id = $file->insert();
if (!$file_id) {
common_log_db_error($file, "INSERT", __FILE__);
throw new ClientException(_('There was a database error while saving your file. Please try again.'));
}
return $file;
}
function rememberFile($file, $short)
{
$this->maybeAddRedir($file->id, $short);
}
function maybeAddRedir($file_id, $url)
{
$file_redir = File_redirection::staticGet('url', $url);
if (empty($file_redir)) {
$file_redir = new File_redirection;
$file_redir->url = $url;
$file_redir->file_id = $file_id;
$result = $file_redir->insert();
if (!$result) {
common_log_db_error($file_redir, "INSERT", __FILE__);
throw new ClientException(_('There was a database error while saving your file. Please try again.'));
}
}
}
static function fromUpload($param = 'media', $user = null)
{
if (empty($user)) {
$user = common_current_user();
}
if (!isset($_FILES[$param]['error'])){
return;
}
switch ($_FILES[$param]['error']) {
case UPLOAD_ERR_OK: // success, jump out
break;
case UPLOAD_ERR_INI_SIZE:
throw new ClientException(_('The uploaded file exceeds the ' .
'upload_max_filesize directive in php.ini.'));
return;
case UPLOAD_ERR_FORM_SIZE:
throw new ClientException(
_('The uploaded file exceeds the MAX_FILE_SIZE directive' .
' that was specified in the HTML form.'));
return;
case UPLOAD_ERR_PARTIAL:
@unlink($_FILES[$param]['tmp_name']);
throw new ClientException(_('The uploaded file was only' .
' partially uploaded.'));
return;
case UPLOAD_ERR_NO_TMP_DIR:
throw new ClientException(_('Missing a temporary folder.'));
return;
case UPLOAD_ERR_CANT_WRITE:
throw new ClientException(_('Failed to write file to disk.'));
return;
case UPLOAD_ERR_EXTENSION:
throw new ClientException(_('File upload stopped by extension.'));
return;
default:
throw new ClientException(_('System error uploading file.'));
return;
}
if (!MediaFile::respectsQuota($user, $_FILES['attach']['size'])) {
// Should never actually get here
@unlink($_FILES[$param]['tmp_name']);
throw new ClientException(_('File exceeds user\'s quota!'));
return;
}
$mimetype = MediaFile::getUploadedFileType($_FILES[$param]['tmp_name']);
$filename = null;
if (isset($mimetype)) {
$basename = basename($_FILES[$param]['name']);
$filename = File::filename($user->getProfile(), $basename, $mimetype);
$filepath = File::path($filename);
$result = move_uploaded_file($_FILES[$param]['tmp_name'], $filepath);
if (!$result) {
throw new ClientException(_('File could not be moved to destination directory.'));
return;
}
} else {
throw new ClientException(_('Could not determine file\'s mime-type!'));
return;
}
return new MediaFile($user, $filename, $mimetype);
}
static function fromFilehandle($fh, $user) {
$stream = stream_get_meta_data($fh);
if (!MediaFile::respectsQuota($user, filesize($stream['uri']))) {
// Should never actually get here
throw new ClientException(_('File exceeds user\'s quota!'));
return;
}
$mimetype = MediaFile::getUploadedFileType($fh);
$filename = null;
if (isset($mimetype)) {
$filename = File::filename($user->getProfile(), "email", $mimetype);
$filepath = File::path($filename);
$result = copy($stream['uri'], $filepath) && chmod($filepath, 0664);
if (!$result) {
throw new ClientException(_('File could not be moved to destination directory.' .
$stream['uri'] . ' ' . $filepath));
}
} else {
throw new ClientException(_('Could not determine file\'s mime-type!'));
return;
}
return new MediaFile($user, $filename, $mimetype);
}
static function getUploadedFileType($f) {
require_once 'MIME/Type.php';
$cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
$cmd = common_config('attachments', 'filecommand');
$filetype = null;
if (is_string($f)) {
// assuming a filename
$filetype = MIME_Type::autoDetect($f);
} else {
// assuming a filehandle
$stream = stream_get_meta_data($f);
$filetype = MIME_Type::autoDetect($stream['uri']);
}
if (in_array($filetype, common_config('attachments', 'supported'))) {
return $filetype;
}
$media = MIME_Type::getMedia($filetype);
if ('application' !== $media) {
$hint = sprintf(_(' Try using another %s format.'), $media);
} else {
$hint = '';
}
throw new ClientException(sprintf(
_('%s is not a supported filetype on this server.'), $filetype) . $hint);
}
static function respectsQuota($user, $filesize)
{
$file = new File;
$result = $file->isRespectsQuota($user, $filesize);
if ($result === true) {
return true;
} else {
throw new ClientException($result);
}
}
}

View File

@ -80,10 +80,21 @@ class MessageForm extends Form
/** /**
* ID of the form * ID of the form
* *
* @return int ID of the form * @return string ID of the form
*/ */
function id() function id()
{
return 'form_notice-direct';
}
/**
* Class of the form
*
* @return string class of the form
*/
function formClass()
{ {
return 'form_notice'; return 'form_notice';
} }

View File

@ -105,7 +105,7 @@ class NoticeForm extends Form
/** /**
* ID of the form * ID of the form
* *
* @return int ID of the form * @return string ID of the form
*/ */
function id() function id()
@ -113,6 +113,17 @@ class NoticeForm extends Form
return 'form_notice'; return 'form_notice';
} }
/**
* Class of the form
*
* @return string class of the form
*/
function formClass()
{
return 'form_notice';
}
/** /**
* Action of the form * Action of the form
* *

View File

@ -199,6 +199,7 @@ class NoticeListItem extends Widget
{ {
$this->out->elementStart('div', 'entry-content'); $this->out->elementStart('div', 'entry-content');
$this->showNoticeLink(); $this->showNoticeLink();
$this->showNoticeLocation();
$this->showNoticeSource(); $this->showNoticeSource();
$this->showContext(); $this->showContext();
$this->out->elementEnd('div'); $this->out->elementEnd('div');
@ -369,6 +370,44 @@ class NoticeListItem extends Widget
$this->out->elementEnd('a'); $this->out->elementEnd('a');
} }
/**
* show the notice location
*
* shows the notice location in the correct language.
*
* If an URL is available, makes a link. Otherwise, just a span.
*
* @return void
*/
function showNoticeLocation()
{
$id = $this->notice->id;
$location = $this->notice->getLocation();
if (empty($location)) {
return;
}
$name = $location->getName();
if (empty($name)) {
// XXX: Could be a translation issue. Fall back to... something?
return;
}
$url = $location->getUrl();
if (empty($url)) {
$this->out->element('span', array('class' => 'location'), $name);
} else {
$this->out->element('a', array('class' => 'location',
'href' => $url),
$name);
}
}
/** /**
* Show the source of the notice * Show the source of the notice
* *

View File

@ -87,7 +87,7 @@ function omb_broadcast_notice($notice)
common_debug('Posting to ' . $rp->postnoticeurl, __FILE__); common_debug('Posting to ' . $rp->postnoticeurl, __FILE__);
/* Post notice. */ /* Post notice. */
$service = new Laconica_OMB_Service_Consumer( $service = new StatusNet_OMB_Service_Consumer(
array(OMB_ENDPOINT_POSTNOTICE => $rp->postnoticeurl)); array(OMB_ENDPOINT_POSTNOTICE => $rp->postnoticeurl));
try { try {
$service->setToken($rp->token, $rp->secret); $service->setToken($rp->token, $rp->secret);

View File

@ -62,9 +62,15 @@ class ProfileList extends Widget
function show() function show()
{ {
$this->startList(); $cnt = 0;
$cnt = $this->showProfiles();
$this->endList(); if (Event::handle('StartProfileList', array($this))) {
$this->startList();
$cnt = $this->showProfiles();
$this->endList();
Event::handle('EndProfileList', array($this));
}
return $cnt; return $cnt;
} }
@ -117,10 +123,19 @@ class ProfileListItem extends Widget
function show() function show()
{ {
$this->startItem(); if (Event::handle('StartProfileListItem', array($this))) {
$this->showProfile(); $this->startItem();
$this->showActions(); if (Event::handle('StartProfileListItemProfile', array($this))) {
$this->endItem(); $this->showProfile();
Event::handle('EndProfileListItemProfile', array($this));
}
if (Event::handle('StartProfileListItemActions', array($this))) {
$this->showActions();
Event::handle('EndProfileListItemActions', array($this));
}
$this->endItem();
Event::handle('EndProfileListItem', array($this));
}
} }
function startItem() function startItem()
@ -132,11 +147,29 @@ class ProfileListItem extends Widget
function showProfile() function showProfile()
{ {
$this->startProfile(); $this->startProfile();
$this->showAvatar(); if (Event::handle('StartProfileListItemProfileElements', array($this))) {
$this->showFullName(); if (Event::handle('StartProfileListItemAvatar', array($this))) {
$this->showLocation(); $this->showAvatar();
$this->showHomepage(); Event::handle('EndProfileListItemAvatar', array($this));
$this->showBio(); }
if (Event::handle('StartProfileListItemFullName', array($this))) {
$this->showFullName();
Event::handle('EndProfileListItemFullName', array($this));
}
if (Event::handle('StartProfileListItemLocation', array($this))) {
$this->showLocation();
Event::handle('EndProfileListItemLocation', array($this));
}
if (Event::handle('StartProfileListItemHomepage', array($this))) {
$this->showHomepage();
Event::handle('EndProfileListItemHomepage', array($this));
}
if (Event::handle('StartProfileListItemBio', array($this))) {
$this->showBio();
Event::handle('EndProfileListItemBio', array($this));
}
Event::handle('EndProfileListItemProfileElements', array($this));
}
$this->endProfile(); $this->endProfile();
} }
@ -225,7 +258,10 @@ class ProfileListItem extends Widget
function showActions() function showActions()
{ {
$this->startActions(); $this->startActions();
$this->showSubscribeButton(); if (Event::handle('StartProfileListItemActionElements', array($this))) {
$this->showSubscribeButton();
Event::handle('EndProfileListItemActionElements', array($this));
}
$this->endActions(); $this->endActions();
} }

View File

@ -27,6 +27,22 @@ define('CLAIM_TIMEOUT', 1200);
define('QUEUE_HANDLER_MISS_IDLE', 10); define('QUEUE_HANDLER_MISS_IDLE', 10);
define('QUEUE_HANDLER_HIT_IDLE', 0); define('QUEUE_HANDLER_HIT_IDLE', 0);
/**
* Base class for queue handlers.
*
* As extensions of the Daemon class, each queue handler has the ability
* to launch itself in the background, at which point it'll pass control
* to the configured QueueManager class to poll for updates.
*
* Subclasses must override at least the following methods:
* - transport
* - start
* - finish
* - handle_notice
*
* Some subclasses will also want to override the idle handler:
* - idle
*/
class QueueHandler extends Daemon class QueueHandler extends Daemon
{ {
@ -39,6 +55,14 @@ class QueueHandler extends Daemon
} }
} }
/**
* How many seconds a polling-based queue manager should wait between
* checks for new items to handle.
*
* Defaults to 60 seconds; override to speed up or slow down.
*
* @return int timeout in seconds
*/
function timeout() function timeout()
{ {
return 60; return 60;
@ -54,24 +78,69 @@ class QueueHandler extends Daemon
return strtolower($this->class_name().'.'.$this->get_id()); return strtolower($this->class_name().'.'.$this->get_id());
} }
/**
* Return transport keyword which identifies items this queue handler
* services; must be defined for all subclasses.
*
* Must be 8 characters or less to fit in the queue_item database.
* ex "email", "jabber", "sms", "irc", ...
*
* @return string
*/
function transport() function transport()
{ {
return null; return null;
} }
/**
* Initialization, run when the queue handler starts.
* If this function indicates failure, the handler run will be aborted.
*
* @fixme run() will abort if this doesn't return true,
* but some subclasses don't bother.
* @return boolean true on success, false on failure
*/
function start() function start()
{ {
} }
/**
* Cleanup, run when the queue handler ends.
* If this function indicates failure, a warning will be logged.
*
* @fixme run() will throw warnings if this doesn't return true,
* but many subclasses don't bother.
* @return boolean true on success, false on failure
*/
function finish() function finish()
{ {
} }
/**
* Here's the meat of your queue handler -- you're handed a Notice
* object, which you may do as you will with.
*
* If this function indicates failure, a warning will be logged
* and the item is placed back in the queue to be re-run.
*
* @param Notice $notice
* @return boolean true on success, false on failure
*/
function handle_notice($notice) function handle_notice($notice)
{ {
return true; return true;
} }
/**
* Setup and start of run loop for this queue handler as a daemon.
* Most of the heavy lifting is passed on to the QueueManager's service()
* method, which passes control back to our handle_notice() method for
* each notice that comes in on the queue.
*
* Most of the time this won't need to be overridden in a subclass.
*
* @return boolean true on success, false on failure
*/
function run() function run()
{ {
if (!$this->start()) { if (!$this->start()) {
@ -100,6 +169,14 @@ class QueueHandler extends Daemon
return true; return true;
} }
/**
* Called by QueueHandler after each handled item or empty polling cycle.
* This is a good time to e.g. service your XMPP connection.
*
* Doesn't need to be overridden if there's no maintenance to do.
*
* @param int $timeout seconds to sleep if there's nothing to do
*/
function idle($timeout=0) function idle($timeout=0)
{ {
if ($timeout > 0) { if ($timeout > 0) {

File diff suppressed because it is too large Load Diff

View File

@ -48,17 +48,6 @@ class UnQueueManager
jabber_public_notice($notice); jabber_public_notice($notice);
} }
break; break;
case 'twitter':
if ($this->_isLocal($notice)) {
broadcast_twitter($notice);
}
break;
case 'facebook':
if ($this->_isLocal($notice)) {
require_once INSTALLDIR . '/lib/facebookutil.php';
return facebookBroadcastNotice($notice);
}
break;
case 'ping': case 'ping':
if ($this->_isLocal($notice)) { if ($this->_isLocal($notice)) {
require_once INSTALLDIR . '/lib/ping.php'; require_once INSTALLDIR . '/lib/ping.php';
@ -77,7 +66,7 @@ class UnQueueManager
break; break;
default: default:
if (Event::handle('UnqueueHandleNotice', array(&$notice, $queue))) { if (Event::handle('UnqueueHandleNotice', array(&$notice, $queue))) {
throw ServerException("UnQueueManager: Unknown queue: $queue"); throw new ServerException("UnQueueManager: Unknown queue: $queue");
} }
} }
} }

View File

@ -51,13 +51,23 @@ function common_init_locale($language=null)
function common_init_language() function common_init_language()
{ {
mb_internal_encoding('UTF-8'); mb_internal_encoding('UTF-8');
// gettext seems very picky... We first need to setlocale()
// to a locale which _does_ exist on the system, and _then_
// we can set in another locale that may not be set up
// (say, ga_ES for Galego/Galician) it seems to take it.
common_init_locale("en_US");
$language = common_language(); $language = common_language();
// So we don't have to make people install the gettext locales
$locale_set = common_init_locale($language); $locale_set = common_init_locale($language);
bindtextdomain("statusnet", common_config('site','locale_path')); setlocale(LC_CTYPE, 'C');
// So we don't have to make people install the gettext locales
$path = common_config('site','locale_path');
bindtextdomain("statusnet", $path);
bind_textdomain_codeset("statusnet", "UTF-8"); bind_textdomain_codeset("statusnet", "UTF-8");
textdomain("statusnet"); textdomain("statusnet");
setlocale(LC_CTYPE, 'C');
if(!$locale_set) { if(!$locale_set) {
common_log(LOG_INFO, 'Language requested:' . $language . ' - locale could not be set. Perhaps that system locale is not installed.', __FILE__); common_log(LOG_INFO, 'Language requested:' . $language . ' - locale could not be set. Perhaps that system locale is not installed.', __FILE__);
} }
@ -391,7 +401,7 @@ function common_render_content($text, $notice)
{ {
$r = common_render_text($text); $r = common_render_text($text);
$id = $notice->profile_id; $id = $notice->profile_id;
$r = preg_replace('/(^|[\s\.\,\:\;]+)@([A-Za-z0-9]{1,64})/e', "'\\1@'.common_at_link($id, '\\2')", $r); $r = preg_replace('/(^|\s+)@(['.NICKNAME_FMT.']{1,64})/e', "'\\1@'.common_at_link($id, '\\2')", $r);
$r = preg_replace('/^T ([A-Z0-9]{1,64}) /e', "'T '.common_at_link($id, '\\1').' '", $r); $r = preg_replace('/^T ([A-Z0-9]{1,64}) /e', "'T '.common_at_link($id, '\\1').' '", $r);
$r = preg_replace('/(^|[\s\.\,\:\;]+)@#([A-Za-z0-9]{1,64})/e', "'\\1@#'.common_at_hash_link($id, '\\2')", $r); $r = preg_replace('/(^|[\s\.\,\:\;]+)@#([A-Za-z0-9]{1,64})/e', "'\\1@#'.common_at_hash_link($id, '\\2')", $r);
$r = preg_replace('/(^|[\s\.\,\:\;]+)!([A-Za-z0-9]{1,64})/e', "'\\1!'.common_group_link($id, '\\2')", $r); $r = preg_replace('/(^|[\s\.\,\:\;]+)!([A-Za-z0-9]{1,64})/e', "'\\1!'.common_group_link($id, '\\2')", $r);
@ -771,12 +781,18 @@ function common_path($relative, $ssl=false)
if (is_string(common_config('site', 'sslserver')) && if (is_string(common_config('site', 'sslserver')) &&
mb_strlen(common_config('site', 'sslserver')) > 0) { mb_strlen(common_config('site', 'sslserver')) > 0) {
$serverpart = common_config('site', 'sslserver'); $serverpart = common_config('site', 'sslserver');
} else { } else if (common_config('site', 'server')) {
$serverpart = common_config('site', 'server'); $serverpart = common_config('site', 'server');
} else {
common_log(LOG_ERR, 'Site Sever not configured, unable to determine site name.');
} }
} else { } else {
$proto = 'http'; $proto = 'http';
$serverpart = common_config('site', 'server'); if (common_config('site', 'server')) {
$serverpart = common_config('site', 'server');
} else {
common_log(LOG_ERR, 'Site Sever not configured, unable to determine site name.');
}
} }
return $proto.'://'.$serverpart.'/'.$pathpart.$relative; return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
@ -896,8 +912,6 @@ function common_broadcast_notice($notice, $remote=false)
function common_enqueue_notice($notice) function common_enqueue_notice($notice)
{ {
static $localTransports = array('omb', static $localTransports = array('omb',
'twitter',
'facebook',
'ping'); 'ping');
static $allTransports = array('sms', 'plugin'); static $allTransports = array('sms', 'plugin');

View File

@ -1,21 +1,12 @@
<?php <?php
/** /**
* Public XRDS for OpenID * StatusNet, the distributed open-source microblogging tool
*
* Low-level generator for HTML
* *
* PHP version 5 * PHP version 5
* *
* @category Action * LICENCE: This program is free software: you can redistribute it and/or modify
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*
* 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 * it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
@ -27,60 +18,44 @@
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Output
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2008 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') && !defined('LACONICA')) { if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1); exit(1);
} }
require_once INSTALLDIR.'/plugins/OpenID/openid.php'; require_once INSTALLDIR.'/lib/xmloutputter.php';
/** /**
* Public XRDS for OpenID * Low-level generator for XRDS XML
* *
* @category Action * @category Output
* @package StatusNet * @package StatusNet
* @author Evan Prodromou <evan@status.net> * @author Craig Andrews <candrews@integralblue.com>
* @author Robin Millette <millette@status.net> * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/ * @link http://status.net/
* *
* @todo factor out similarities with XrdsAction * @see Action
* @see XMLOutputter
*/ */
class PublicxrdsAction extends Action class XRDSOutputter extends XMLOutputter
{ {
/** public function startXRDS()
* Is read only?
*
* @return boolean true
*/
function isReadOnly($args)
{ {
return true;
}
/**
* Class handler.
*
* @param array $args array of arguments
*
* @return nothing
*/
function handle($args)
{
parent::handle($args);
header('Content-Type: application/xrds+xml'); header('Content-Type: application/xrds+xml');
$this->startXML(); $this->startXML();
$this->elementStart('XRDS', array('xmlns' => 'xri://$xrds')); $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', }
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0')); public function endXRDS()
$this->element('Type', null, 'xri://$xrds*simple'); {
foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) {
$this->showService(Auth_OpenID_RP_RETURN_TO_URL_TYPE,
common_local_url($finish));
}
$this->elementEnd('XRD');
$this->elementEnd('XRDS'); $this->elementEnd('XRDS');
$this->endXML(); $this->endXML();
} }
@ -96,7 +71,7 @@ class PublicxrdsAction extends Action
* *
* @return void * @return void
*/ */
function showService($type, $uri, $params=null, $sigs=null, $localId=null) function showXrdsService($type, $uri, $params=null, $sigs=null, $localId=null)
{ {
$this->elementStart('Service'); $this->elementStart('Service');
if ($uri) { if ($uri) {
@ -119,4 +94,3 @@ class PublicxrdsAction extends Action
$this->elementEnd('Service'); $this->elementEnd('Service');
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More