Merge branch '0.9.x' into userflag
This commit is contained in:
commit
5f5413624d
2
.gitignore
vendored
2
.gitignore
vendored
@ -24,4 +24,4 @@ config-*.php
|
||||
good-config.php
|
||||
lac08.log
|
||||
php.log
|
||||
|
||||
.DS_Store
|
||||
|
84
EVENTS.txt
84
EVENTS.txt
@ -129,6 +129,9 @@ StartSubGroupNav: Showing the subscriptions group nav menu
|
||||
EndSubGroupNav: At the end of the subscriptions group nav menu
|
||||
- $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
|
||||
- $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
|
||||
- &$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
263
README
@ -2,8 +2,8 @@
|
||||
README
|
||||
------
|
||||
|
||||
StatusNet 0.8.1 ("Second Guessing")
|
||||
26 Aug 2009
|
||||
StatusNet 0.8.2 ("Life and How to Live It")
|
||||
1 Nov 2009
|
||||
|
||||
This is the README file for StatusNet (formerly Laconica), the Open
|
||||
Source microblogging platform. It includes installation instructions,
|
||||
@ -77,49 +77,80 @@ for additional terms.
|
||||
New this version
|
||||
================
|
||||
|
||||
This is a minor feature and bugfix release since version 0.8.0,
|
||||
released Jul 15 2009. Notable changes this version:
|
||||
This is a minor feature and bugfix release since version 0.8.1,
|
||||
released Aug 26 2009. Notable changes this version:
|
||||
|
||||
- Laconica has been renamed StatusNet. With a few minor compatibility
|
||||
exceptions, all references to "Laconica" in code, documentation
|
||||
and comments were changed to "StatusNet".
|
||||
- A new plugin to support "infinite scroll".
|
||||
- A new plugin to support reCaptcha <http://recaptcha.net>.
|
||||
- Better logging of server errors.
|
||||
- Add an Openid-only mode for authentication.
|
||||
- 'lite' parameter for some Twitter API methods.
|
||||
- A new plugin to auto-complete nicknames for @-replies.
|
||||
- Configuration options to disable OpenID, SMS, Twitter, post-by-email, and IM.
|
||||
- Support for lighttpd <http://lighttpd.org/> using 404-based
|
||||
rewrites.
|
||||
- Support for using Twitter's OAuth authentication as a client.
|
||||
- First version of the groups API.
|
||||
- Can configure a site-wide design, including background image and
|
||||
colors.
|
||||
- Improved algorithm for replies and conversations, making
|
||||
conversation trees more accurate and useful.
|
||||
- Add a script to create a simulation database for testing/debugging.
|
||||
- Sanitize HTML for OEmbed.
|
||||
- Improved queue management for DB-based queuing.
|
||||
- More complete URL detection.
|
||||
- Hashtags now support full Unicode character set.
|
||||
- Notice inboxes are now garbage-collected on a regular basis
|
||||
at notice-write time.
|
||||
- PiwikAnalyticsPlugin updated for latest Piwik interface.
|
||||
- Attachment and notice pages can be embedded with OEmbed
|
||||
<http://www.oembed.com>.
|
||||
- Failed authentication is logged.
|
||||
- PostgreSQL schema and support brought up-to-date with 0.8.x features.
|
||||
- The installer works with PostgreSQL as well as MySQL.
|
||||
- RSS 1.0 feeds use HTTP Basic authentication in private mode.
|
||||
- Many, many bug fixes, particularly with performance.
|
||||
- Better (=working) garbage collection for old sessions.
|
||||
- Better (=working) search queries.
|
||||
- Some cleanup of HTML output.
|
||||
- Better error handling when updating Facebook.
|
||||
- Considerably better performance when using replication for API
|
||||
calls.
|
||||
- Initial unit tests.
|
||||
- New script for deleting user accounts. Not particularly safe or
|
||||
community-friendly. Better for deleting abusive accounts than for
|
||||
users who are 'retiring'.
|
||||
- Improved detection of URLs in notices, specifically for punctuation
|
||||
chars like ~, :, $, _, -, +, !, @, and %.
|
||||
- Removed some extra <dl> semantic HTML code.
|
||||
- Correct error in status-network database ini file (having multiple
|
||||
statusnet sites with a single codebase)
|
||||
- Fixed error output for Twitter posting failures.
|
||||
- Fixed bug in Twitter queue handler that requeued inapplicable
|
||||
notices ad infinitum.
|
||||
- Improve FOAF output for remote users.
|
||||
- new commands to join and leave groups.
|
||||
- Fixed bug in which you cannot turn off importing friends timelines
|
||||
flag.
|
||||
- Better error handling in Twitter posting.
|
||||
- Show oEmbed data for XHTML files as well as plain HTML.
|
||||
- Updated bug database link in README.
|
||||
- require HTML tidy extension.
|
||||
- add support for HTTP Basic Auth in PHP CGI or FastCGI (e.g. GoDaddy).
|
||||
- autofocus input to selected entry elements depending on page.
|
||||
- updated layout for filter-by-tag form.
|
||||
- better layout for inbox and outbox pages.
|
||||
- fix highlighting search terms in attributes of notice list elements.
|
||||
- Correctly handle errors in linkback plugin.
|
||||
- Updated biz theme.
|
||||
- Updated cloudy theme.
|
||||
- Don't match '::' as an IPv6 address.
|
||||
- Use the same decision logic for deciding whether to mark an
|
||||
attachment as an enclosure in RSS or as a paperclip item in Web
|
||||
output.
|
||||
- Fixed a bug in the Piwik plugin that hard-coded the site ID.
|
||||
- Add a param, inreplyto, to notice/new to allow an explicit response
|
||||
to another notice.
|
||||
- Show username in subject of emails.
|
||||
- Check if avatar exists before trying to delete it.
|
||||
- Correctly add omb_version to response for request token in OMB.
|
||||
- Add a few more SMS carriers.
|
||||
- Add a few more notice sources.
|
||||
- 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
|
||||
=============
|
||||
@ -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
|
||||
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
|
||||
may have to unpack the tarball on your local computer and FTP the
|
||||
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
|
||||
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
|
||||
your server, like "http://example.net/mublog". "microblog" or
|
||||
@ -526,10 +557,6 @@ This will run eight (for now) queue handlers:
|
||||
of registered users.
|
||||
* xmppconfirmhandler.php - sends confirmation messages to registered
|
||||
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
|
||||
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
|
||||
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
|
||||
--------
|
||||
|
||||
@ -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
|
||||
"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
|
||||
=========
|
||||
|
||||
@ -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
|
||||
been tracking the "git" version of the software, you will probably
|
||||
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.
|
||||
|
||||
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
|
||||
final backup of the Web directory and database.
|
||||
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.
|
||||
8. Copy the config.php file and avatar directory from your old
|
||||
directory to your new directory.
|
||||
@ -1251,24 +1193,11 @@ For SMS integration.
|
||||
enabled: Whether to enable SMS integration. Defaults to true. Queues
|
||||
should also be enabled.
|
||||
|
||||
twitter
|
||||
-------
|
||||
|
||||
For Twitter integration
|
||||
|
||||
enabled: Whether to enable Twitter integration. Defaults to true.
|
||||
Queues should also be enabled.
|
||||
|
||||
integration
|
||||
-----------
|
||||
|
||||
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'.
|
||||
|
||||
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
|
||||
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
|
||||
----
|
||||
|
||||
@ -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
|
||||
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,
|
||||
read the "Notice inboxes" section above.
|
||||
|
||||
@ -1661,6 +1581,7 @@ if anyone's been overlooked in error.
|
||||
* Jeffery To
|
||||
* Federico Marani
|
||||
* Craig Andrews
|
||||
* mEDI
|
||||
|
||||
Thanks also to the developers of our upstream library code and to the
|
||||
thousands of people who have tried out Identi.ca, installed StatusNet,
|
||||
|
@ -99,19 +99,17 @@ class AllAction extends ProfileAction
|
||||
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url(
|
||||
'api', array(
|
||||
'apiaction' => 'statuses',
|
||||
'method' => 'friends_timeline',
|
||||
'argument' => $this->user->nickname.'.rss'
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'rss',
|
||||
'id' => $this->user->nickname
|
||||
)
|
||||
),
|
||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url(
|
||||
'api', array(
|
||||
'apiaction' => 'statuses',
|
||||
'method' => 'friends_timeline',
|
||||
'argument' => $this->user->nickname.'.atom'
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'atom',
|
||||
'id' => $this->user->nickname
|
||||
)
|
||||
),
|
||||
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))
|
||||
|
@ -157,7 +157,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
|
||||
// Note: sending msgs to yourself is allowed by Twitter
|
||||
|
||||
$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);
|
||||
return;
|
||||
|
@ -127,7 +127,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
|
||||
|
||||
if (empty($fave)) {
|
||||
$this->clientError(
|
||||
_('Could not create favorite.')
|
||||
_('Could not create favorite.'),
|
||||
403,
|
||||
$this->format
|
||||
);
|
||||
|
@ -38,6 +38,7 @@ if (!defined('STATUSNET')) {
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apiauth.php';
|
||||
require_once INSTALLDIR . '/lib/mediafile.php';
|
||||
|
||||
/**
|
||||
* Updates the authenticating user's status (posts a notice).
|
||||
@ -60,7 +61,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
var $source = null;
|
||||
var $status = null;
|
||||
var $in_reply_to_status_id = null;
|
||||
|
||||
static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
|
||||
|
||||
/**
|
||||
@ -76,25 +76,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_('No such user!'), 404, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$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');
|
||||
|
||||
if (empty($this->source) || in_array($source, $this->reserved_sources)) {
|
||||
@ -129,6 +112,27 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
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);
|
||||
|
||||
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->user->id,
|
||||
html_entity_decode($this->status, ENT_NOQUOTES, 'UTF-8'),
|
||||
html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8'),
|
||||
$this->source,
|
||||
1,
|
||||
$reply_to
|
||||
);
|
||||
|
||||
if (isset($upload)) {
|
||||
$upload->attachToNotice($this->notice);
|
||||
}
|
||||
|
||||
common_broadcast_notice($this->notice);
|
||||
}
|
||||
|
||||
|
75
actions/bookmarklet.php
Normal file
75
actions/bookmarklet.php
Normal 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()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
||||
$this->showForm(_('Cannot normalize that email address'));
|
||||
return;
|
||||
}
|
||||
if (!Validate::email($email, true)) {
|
||||
if (!Validate::email($email, common_config('email', 'check_domain'))) {
|
||||
$this->showForm(_('Not a valid email address'));
|
||||
return;
|
||||
} else if ($user->email == $email) {
|
||||
|
145
actions/getfile.php
Normal file
145
actions/getfile.php
Normal 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);
|
||||
}
|
||||
}
|
@ -179,9 +179,12 @@ class GroupMemberListItem extends ProfileListItem
|
||||
function showActions()
|
||||
{
|
||||
$this->startActions();
|
||||
$this->showSubscribeButton();
|
||||
$this->showMakeAdminForm();
|
||||
$this->showGroupBlockForm();
|
||||
if (Event::handle('StartProfileListItemActionElements', array($this))) {
|
||||
$this->showSubscribeButton();
|
||||
$this->showMakeAdminForm();
|
||||
$this->showGroupBlockForm();
|
||||
Event::handle('EndProfileListItemActionElements', array($this));
|
||||
}
|
||||
$this->endActions();
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ class InviteAction extends CurrentUserDesignAction
|
||||
|
||||
foreach ($addresses as $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));
|
||||
return;
|
||||
}
|
||||
|
@ -99,7 +99,9 @@ class NewmessageAction extends Action
|
||||
$user = common_current_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;
|
||||
}
|
||||
|
||||
@ -221,7 +223,22 @@ class NewmessageAction extends Action
|
||||
}
|
||||
|
||||
$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()
|
||||
|
@ -33,7 +33,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
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
|
||||
@ -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
|
||||
*
|
||||
@ -160,18 +134,12 @@ class NewnoticeAction extends Action
|
||||
|
||||
if (!$content) {
|
||||
$this->clientError(_('No content!'));
|
||||
} else {
|
||||
$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()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$inter = new CommandInterpreter();
|
||||
|
||||
$cmd = $inter->handle_command($user, $content_shortened);
|
||||
$cmd = $inter->handle_command($user, $content);
|
||||
|
||||
if ($cmd) {
|
||||
if ($this->boolean('ajax')) {
|
||||
@ -182,6 +150,13 @@ class NewnoticeAction extends Action
|
||||
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');
|
||||
#If an ID of 0 is wrongly passed here, it will cause a database error,
|
||||
#so override it...
|
||||
@ -189,84 +164,37 @@ class NewnoticeAction extends Action
|
||||
$replyto = 'false';
|
||||
}
|
||||
|
||||
if (isset($_FILES['attach']['error'])) {
|
||||
switch ($_FILES['attach']['error']) {
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
// no file uploaded, nothing to do
|
||||
break;
|
||||
$upload = null;
|
||||
$upload = MediaFile::fromUpload('attach');
|
||||
|
||||
case UPLOAD_ERR_OK:
|
||||
$mimetype = $this->getUploadedFileType();
|
||||
if (!$this->isRespectsQuota($user)) {
|
||||
die('clientError() should trigger an exception before reaching here.');
|
||||
}
|
||||
break;
|
||||
if (isset($upload)) {
|
||||
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
$this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
|
||||
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
$this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
|
||||
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
$this->clientError(_('The uploaded file was only partially uploaded.'));
|
||||
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
$this->clientError(_('Missing a temporary folder.'));
|
||||
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
$this->clientError(_('Failed to write file to disk.'));
|
||||
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
$this->clientError(_('File upload stopped by extension.'));
|
||||
|
||||
default:
|
||||
die('Should never reach here.');
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
$content_shortened .= ' ' . $upload->shortUrl();
|
||||
|
||||
if (Notice::contentTooLong($content_shortened)) {
|
||||
$this->deleteFile($filename);
|
||||
$this->clientError(sprintf(_('Max notice size is %d chars, including attachment URL.'),
|
||||
Notice::maxContent()));
|
||||
$upload->delete();
|
||||
$this->clientError(
|
||||
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,
|
||||
($replyto == 'false') ? null : $replyto);
|
||||
|
||||
if (isset($mimetype)) {
|
||||
$this->attachFile($notice, $fileRecord);
|
||||
if (isset($upload)) {
|
||||
$upload->attachToNotice($notice);
|
||||
}
|
||||
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
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->element('title', null, _('Notice posted'));
|
||||
$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
|
||||
*
|
||||
|
@ -103,7 +103,7 @@ class OthersettingsAction extends AccountSettingsAction
|
||||
foreach($_shorteners as $name=>$value)
|
||||
{
|
||||
$services[$name]=$name;
|
||||
if($value['info']['freeService']){
|
||||
if(!empty($value['info']['freeService'])){
|
||||
// I18N
|
||||
$services[$name].=' (free service)';
|
||||
}
|
||||
|
@ -306,6 +306,16 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
$profile->homepage = $homepage;
|
||||
$profile->bio = $bio;
|
||||
$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);
|
||||
|
||||
common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__);
|
||||
|
@ -131,6 +131,13 @@ class PublicAction extends Action
|
||||
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
|
||||
@ -143,14 +150,12 @@ class PublicAction extends Action
|
||||
return array(new Feed(Feed::RSS1, common_local_url('publicrss'),
|
||||
_('Public Stream Feed (RSS 1.0)')),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'public_timeline.rss')),
|
||||
common_local_url('ApiTimelinePublic',
|
||||
array('format' => 'rss')),
|
||||
_('Public Stream Feed (RSS 2.0)')),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'public_timeline.atom')),
|
||||
common_local_url('ApiTimelinePublic',
|
||||
array('format' => 'atom')),
|
||||
_('Public Stream Feed (Atom)')));
|
||||
}
|
||||
|
||||
|
81
actions/publicxrds.php
Normal file
81
actions/publicxrds.php
Normal 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();
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ class RegisterAction extends Action
|
||||
if (!$this->boolean('license')) {
|
||||
$this->showForm(_('You can\'t register if you don\'t '.
|
||||
'agree to the license.'));
|
||||
} else if ($email && !Validate::email($email, true)) {
|
||||
} else if ($email && !Validate::email($email, common_config('email', 'check_domain'))) {
|
||||
$this->showForm(_('Not a valid email address.'));
|
||||
} else if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
|
@ -138,11 +138,25 @@ class RepliesAction extends OwnerDesignAction
|
||||
|
||||
function getFeeds()
|
||||
{
|
||||
$rssurl = common_local_url('repliesrss',
|
||||
array('nickname' => $this->user->nickname));
|
||||
$rsstitle = sprintf(_('Feed for replies to %s'), $this->user->nickname);
|
||||
|
||||
return array(new Feed(Feed::RSS1, $rssurl, $rsstitle));
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('repliesrss',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
sprintf(_('Replies feed for %s (RSS 1.0)'),
|
||||
$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)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,13 +164,25 @@ class ShowfavoritesAction extends OwnerDesignAction
|
||||
|
||||
function getFeeds()
|
||||
{
|
||||
$feedurl = common_local_url('favoritesrss',
|
||||
array('nickname' =>
|
||||
$this->user->nickname));
|
||||
$feedtitle = sprintf(_('Feed for favorites of %s'),
|
||||
$this->user->nickname);
|
||||
|
||||
return array(new Feed(Feed::RSS1, $feedurl, $feedtitle));
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('favoritesrss',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
sprintf(_('Feed for favorites of %s (RSS 1.0)'),
|
||||
$this->user->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
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)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,17 +328,15 @@ class ShowgroupAction extends GroupDesignAction
|
||||
sprintf(_('Notice feed for %s group (RSS 1.0)'),
|
||||
$this->group->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'groups',
|
||||
'method' => 'timeline',
|
||||
'argument' => $this->group->nickname.'.rss')),
|
||||
common_local_url('ApiTimelineGroup',
|
||||
array('format' => 'rss',
|
||||
'id' => $this->group->nickname)),
|
||||
sprintf(_('Notice feed for %s group (RSS 2.0)'),
|
||||
$this->group->nickname)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'groups',
|
||||
'method' => 'timeline',
|
||||
'argument' => $this->group->nickname.'.atom')),
|
||||
common_local_url('ApiTimelineGroup',
|
||||
array('format' => 'atom',
|
||||
'id' => $this->group->nickname)),
|
||||
sprintf(_('Notice feed for %s group (Atom)'),
|
||||
$this->group->nickname)),
|
||||
new Feed(Feed::FOAF,
|
||||
|
@ -172,9 +172,9 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
function title()
|
||||
{
|
||||
if (!empty($this->profile->fullname)) {
|
||||
$base = $this->profile->fullname . ' (' . $this->user->nickname . ') ';
|
||||
$base = $this->profile->fullname . ' (' . $this->profile->nickname . ') ';
|
||||
} else {
|
||||
$base = $this->user->nickname;
|
||||
$base = $this->profile->nickname;
|
||||
}
|
||||
|
||||
return sprintf(_('%1$s\'s status on %2$s'),
|
||||
|
@ -128,17 +128,17 @@ class ShowstreamAction extends ProfileAction
|
||||
sprintf(_('Notice feed for %s (RSS 1.0)'),
|
||||
$this->user->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'user_timeline',
|
||||
'argument' => $this->user->nickname.'.rss')),
|
||||
common_local_url('ApiTimelineUser',
|
||||
array(
|
||||
'id' => $this->user->nickname,
|
||||
'format' => 'rss')),
|
||||
sprintf(_('Notice feed for %s (RSS 2.0)'),
|
||||
$this->user->nickname)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'user_timeline',
|
||||
'argument' => $this->user->nickname.'.atom')),
|
||||
common_local_url('ApiTimelineUser',
|
||||
array(
|
||||
'id' => $this->user->nickname,
|
||||
'format' => 'atom')),
|
||||
sprintf(_('Notice feed for %s (Atom)'),
|
||||
$this->user->nickname)),
|
||||
new Feed(Feed::FOAF,
|
||||
@ -348,6 +348,8 @@ class ShowstreamAction extends ProfileAction
|
||||
{
|
||||
if (Event::handle('StartProfilePageActionsSection', array(&$this, $this->profile))) {
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
$this->elementStart('div', 'entity_actions');
|
||||
$this->element('h2', null, _('User actions'));
|
||||
$this->elementStart('ul');
|
||||
@ -379,21 +381,21 @@ class ShowstreamAction extends ProfileAction
|
||||
}
|
||||
$this->elementEnd('li');
|
||||
|
||||
if ($cur->mutuallySubscribed($user)) {
|
||||
if ($cur->mutuallySubscribed($this->user)) {
|
||||
|
||||
// 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')),
|
||||
_('Message'));
|
||||
$this->elementEnd('li');
|
||||
|
||||
// nudge
|
||||
|
||||
if ($user->email && $user->emailnotifynudge) {
|
||||
if ($this->user->email && $this->user->emailnotifynudge) {
|
||||
$this->elementStart('li', 'entity_nudge');
|
||||
$nf = new NudgeForm($this, $user);
|
||||
$nf = new NudgeForm($this, $this->user);
|
||||
$nf->show();
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
|
@ -86,17 +86,15 @@ class TagAction extends Action
|
||||
sprintf(_('Notice feed for tag %s (RSS 1.0)'),
|
||||
$this->tag)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'tags',
|
||||
'method' => 'timeline',
|
||||
'argument' => $this->tag.'.rss')),
|
||||
sprintf(_('Notice feed for %s group (RSS 2.0)'),
|
||||
common_local_url('ApiTimelineTag',
|
||||
array('format' => 'rss',
|
||||
'tag' => $this->tag)),
|
||||
sprintf(_('Notice feed for tag %s (RSS 2.0)'),
|
||||
$this->tag)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('api',
|
||||
array('apiaction' => 'tags',
|
||||
'method' => 'timeline',
|
||||
'argument' => $this->tag.'.atom')),
|
||||
common_local_url('ApiTimelineTag',
|
||||
array('format' => 'atom',
|
||||
'tag' => $this->tag)),
|
||||
sprintf(_('Notice feed for tag %s (Atom)'),
|
||||
$this->tag)));
|
||||
}
|
||||
|
108
actions/xrds.php
108
actions/xrds.php
@ -36,6 +36,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
require_once INSTALLDIR.'/lib/omb.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
|
||||
require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
|
||||
require_once INSTALLDIR.'/lib/xrdsoutputter.php';
|
||||
|
||||
/**
|
||||
* XRDS for OpenMicroBlogging
|
||||
@ -49,6 +50,8 @@ require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
|
||||
*/
|
||||
class XrdsAction extends Action
|
||||
{
|
||||
var $user;
|
||||
|
||||
/**
|
||||
* Is read only?
|
||||
*
|
||||
@ -58,6 +61,18 @@ class XrdsAction extends Action
|
||||
{
|
||||
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.
|
||||
@ -69,49 +84,64 @@ class XrdsAction extends Action
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$user = User::staticGet('nickname', $nickname);
|
||||
if (!$user) {
|
||||
$this->clientError(_('No such user.'));
|
||||
return;
|
||||
}
|
||||
$this->showXrds($user);
|
||||
}
|
||||
$xrdsOutputter = new XRDSOutputter();
|
||||
$xrdsOutputter->startXRDS();
|
||||
|
||||
/**
|
||||
* 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 libomb’s default XRDS Writer. */
|
||||
$xrds_writer = null;
|
||||
$srv->writeXRDS(new Laconica_XRDS_Mapper(), $xrds_writer);
|
||||
}
|
||||
}
|
||||
Event::handle('StartUserXRDS', array($this,&$xrdsOutputter));
|
||||
|
||||
class Laconica_XRDS_Mapper implements OMB_XRDS_Mapper
|
||||
{
|
||||
protected $urls;
|
||||
//oauth
|
||||
$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(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()
|
||||
{
|
||||
$this->urls = array(
|
||||
OAUTH_ENDPOINT_REQUEST => 'requesttoken',
|
||||
OAUTH_ENDPOINT_AUTHORIZE => 'userauthorization',
|
||||
OAUTH_ENDPOINT_ACCESS => 'accesstoken',
|
||||
OMB_ENDPOINT_POSTNOTICE => 'postnotice',
|
||||
OMB_ENDPOINT_UPDATEPROFILE => 'updateprofile');
|
||||
}
|
||||
Event::handle('EndUserXRDS', array($this,&$xrdsOutputter));
|
||||
|
||||
public function getURL($action)
|
||||
{
|
||||
return common_local_url($this->urls[$action]);
|
||||
$xrdsOutputter->endXRDS();
|
||||
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -81,7 +81,7 @@ class Avatar extends Memcached_DataObject
|
||||
if (empty($server)) {
|
||||
$server = common_config('site', 'server');
|
||||
}
|
||||
|
||||
common_debug('path = ' . $path);
|
||||
// XXX: protocol
|
||||
|
||||
return 'http://'.$server.$path.$filename;
|
||||
|
46
classes/Location_namespace.php
Normal file
46
classes/Location_namespace.php
Normal 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
|
||||
}
|
@ -66,9 +66,15 @@ class Notice extends Memcached_DataObject
|
||||
public $is_local; // tinyint(1)
|
||||
public $source; // varchar(32)
|
||||
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 */
|
||||
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 */
|
||||
###END_AUTOCODE
|
||||
@ -162,7 +168,8 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -172,7 +179,7 @@ class Notice extends Memcached_DataObject
|
||||
throw new ClientException(_('Problem saving notice. Too long.'));
|
||||
}
|
||||
|
||||
if (!$profile) {
|
||||
if (empty($profile)) {
|
||||
throw new ClientException(_('Problem saving notice. Unknown user.'));
|
||||
}
|
||||
|
||||
@ -228,6 +235,26 @@ class Notice extends Memcached_DataObject
|
||||
$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))) {
|
||||
|
||||
// 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?
|
||||
|
||||
$notice->saveReplies();
|
||||
$notice->saveTags();
|
||||
|
||||
$notice->addToInboxes();
|
||||
@ -307,11 +333,11 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
static function checkDupes($profile_id, $content) {
|
||||
$profile = Profile::staticGet($profile_id);
|
||||
if (!$profile) {
|
||||
if (empty($profile)) {
|
||||
return false;
|
||||
}
|
||||
$notice = $profile->getNotices(0, NOTICE_CACHE_WINDOW);
|
||||
if ($notice) {
|
||||
if (!empty($notice)) {
|
||||
$last = 0;
|
||||
while ($notice->fetch()) {
|
||||
if (time() - strtotime($notice->created) >= common_config('site', 'dupelimit')) {
|
||||
@ -337,7 +363,7 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
static function checkEditThrottle($profile_id) {
|
||||
$profile = Profile::staticGet($profile_id);
|
||||
if (!$profile) {
|
||||
if (empty($profile)) {
|
||||
return false;
|
||||
}
|
||||
# Get the Nth notice
|
||||
@ -658,7 +684,7 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
$cache = common_memcache();
|
||||
|
||||
if (!$cache) {
|
||||
if (empty($cache)) {
|
||||
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 (!$notice) {
|
||||
if (empty($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;
|
||||
|
||||
$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++) {
|
||||
$nickname = $names[$i];
|
||||
$recipient = common_relative_profile($sender, $nickname, $this->created);
|
||||
if (!$recipient) {
|
||||
if (empty($recipient)) {
|
||||
continue;
|
||||
}
|
||||
// Don't save replies from blocked profile to local user
|
||||
$recipient_user = User::staticGet('id', $recipient->id);
|
||||
if ($recipient_user && $recipient_user->hasBlocked($sender)) {
|
||||
if (!empty($recipient_user) && $recipient_user->hasBlocked($sender)) {
|
||||
continue;
|
||||
}
|
||||
$reply = new Reply();
|
||||
@ -1077,7 +1115,7 @@ class Notice extends Memcached_DataObject
|
||||
$last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
|
||||
common_log(LOG_ERR, 'DB error inserting reply: ' . $last_error->message);
|
||||
common_server_error(sprintf(_('DB error inserting reply: %s'), $last_error->message));
|
||||
return;
|
||||
return array();
|
||||
} else {
|
||||
$replied[$recipient->id] = 1;
|
||||
}
|
||||
@ -1101,7 +1139,7 @@ class Notice extends Memcached_DataObject
|
||||
$id = $reply->insert();
|
||||
if (!$id) {
|
||||
common_log_db_error($reply, 'INSERT', __FILE__);
|
||||
return;
|
||||
return array();
|
||||
} else {
|
||||
$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);
|
||||
if ($user) {
|
||||
mail_notify_attn($user, $this);
|
||||
}
|
||||
}
|
||||
|
||||
return $recipientIds;
|
||||
}
|
||||
|
||||
function asAtomEntry($namespace=false, $source=false)
|
||||
@ -1139,10 +1181,9 @@ class Notice extends Memcached_DataObject
|
||||
$xs->element('link', array('href' => $profile->profileurl));
|
||||
$user = User::staticGet('id', $profile->id);
|
||||
if (!empty($user)) {
|
||||
$atom_feed = common_local_url('api',
|
||||
array('apiaction' => 'statuses',
|
||||
'method' => 'user_timeline',
|
||||
'argument' => $profile->nickname.'.atom'));
|
||||
$atom_feed = common_local_url('ApiTimelineUser',
|
||||
array('format' => 'atom',
|
||||
'id' => $profile->nickname));
|
||||
$xs->element('link', array('rel' => 'self',
|
||||
'type' => 'application/atom+xml',
|
||||
'href' => $profile->profileurl));
|
||||
@ -1370,4 +1411,21 @@ class Notice extends Memcached_DataObject
|
||||
$contentlimit = self::maxContent();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -37,15 +37,26 @@ class Profile extends Memcached_DataObject
|
||||
public $homepage; // varchar(255) multiple_key
|
||||
public $bio; // text() 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 $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* 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 */
|
||||
###END_AUTOCODE
|
||||
|
||||
function getUser()
|
||||
{
|
||||
return User::staticGet('id', $this->id);
|
||||
}
|
||||
|
||||
function getAvatar($width, $height=null)
|
||||
{
|
||||
if (is_null($height)) {
|
||||
@ -551,4 +562,29 @@ class Profile extends Memcached_DataObject
|
||||
$block->blocked = $this->id;
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@ -198,6 +198,15 @@ class User extends Memcached_DataObject
|
||||
}
|
||||
if (!empty($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();
|
||||
@ -319,6 +328,7 @@ class User extends Memcached_DataObject
|
||||
common_config('site', 'name'),
|
||||
$user->nickname),
|
||||
'system');
|
||||
common_broadcast_notice($notice);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
[avatar]
|
||||
profile_id = 129
|
||||
original = 17
|
||||
@ -243,6 +244,15 @@ created = 142
|
||||
[invitation__keys]
|
||||
code = K
|
||||
|
||||
[location_namespace]
|
||||
id = 129
|
||||
description = 2
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[location_namespace__keys]
|
||||
id = K
|
||||
|
||||
[message]
|
||||
id = 129
|
||||
uri = 2
|
||||
@ -284,6 +294,10 @@ reply_to = 1
|
||||
is_local = 17
|
||||
source = 2
|
||||
conversation = 1
|
||||
lat = 1
|
||||
lon = 1
|
||||
location_id = 1
|
||||
location_ns = 1
|
||||
|
||||
[notice__keys]
|
||||
id = N
|
||||
@ -325,6 +339,10 @@ profileurl = 2
|
||||
homepage = 2
|
||||
bio = 34
|
||||
location = 2
|
||||
lat = 1
|
||||
lon = 1
|
||||
location_id = 1
|
||||
location_ns = 1
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
@ -519,6 +537,16 @@ modified = 384
|
||||
canonical = K
|
||||
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_id = 129
|
||||
role = 130
|
||||
|
@ -104,6 +104,10 @@ $config['sphinx']['port'] = 3312;
|
||||
// $config['site']['timezone'] = 'Pacific/Auckland';
|
||||
// $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
|
||||
// $config['mail']['notifyfrom'] = 'microblog@example.net';
|
||||
// $config['mail']['domain'] = 'microblog.example.net';
|
||||
|
5
db/location_namespace.sql
Normal file
5
db/location_namespace.sql
Normal file
@ -0,0 +1,5 @@
|
||||
insert into location_namespace
|
||||
(id, description, created)
|
||||
values
|
||||
(1, 'Geonames', now()),
|
||||
(2, 'Where on Earth', now());
|
@ -1,6 +1,7 @@
|
||||
/* local and remote users have profiles */
|
||||
|
||||
create table profile (
|
||||
|
||||
id integer auto_increment primary key comment 'unique identifier',
|
||||
nickname varchar(64) not null comment 'nickname or username',
|
||||
fullname varchar(255) comment 'display name',
|
||||
@ -8,6 +9,11 @@ create table profile (
|
||||
homepage varchar(255) comment 'identifying URL',
|
||||
bio text comment 'descriptive biography',
|
||||
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',
|
||||
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',
|
||||
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),
|
||||
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_conversation_idx (conversation),
|
||||
@ -556,3 +566,12 @@ create table user_role (
|
||||
constraint primary key (user_id, role)
|
||||
|
||||
) 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;
|
||||
|
@ -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.
|
||||
|
||||
<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+'&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>
|
||||
|
@ -20,7 +20,7 @@
|
||||
/**
|
||||
* The library version string
|
||||
*/
|
||||
define('Auth_OpenID_VERSION', '2.1.2');
|
||||
define('Auth_OpenID_VERSION', '2.1.3');
|
||||
|
||||
/**
|
||||
* Require the fetcher code.
|
||||
|
@ -376,7 +376,7 @@ function Auth_OpenID_detectMathLibrary($exts)
|
||||
// Try to load dynamic modules.
|
||||
if (!$loaded) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -1295,7 +1295,8 @@ class Auth_OpenID_GenericConsumer {
|
||||
Auth_OpenID_OPENID2_NS => array_merge($basic_sig_fields,
|
||||
array('response_nonce',
|
||||
'claimed_id',
|
||||
'assoc_handle')),
|
||||
'assoc_handle',
|
||||
'op_endpoint')),
|
||||
Auth_OpenID_OPENID1_NS => array_merge($basic_sig_fields,
|
||||
array('nonce'))
|
||||
);
|
||||
|
@ -887,6 +887,11 @@ class Auth_OpenID_Message {
|
||||
|
||||
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);
|
||||
|
||||
if (count($parts) != 2) {
|
||||
|
@ -138,7 +138,7 @@ class Auth_Yadis_HTTPFetcher {
|
||||
* pass the URLHasAllowedScheme check or if the server's response
|
||||
* is malformed.
|
||||
*/
|
||||
function get($url, $headers)
|
||||
function get($url, $headers = null)
|
||||
{
|
||||
trigger_error("not implemented", E_USER_ERROR);
|
||||
}
|
||||
|
@ -127,8 +127,6 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
|
||||
Auth_OpenID_USER_AGENT.' '.$curl_user_agent);
|
||||
curl_setopt($c, CURLOPT_TIMEOUT, $off);
|
||||
curl_setopt($c, CURLOPT_URL, $url);
|
||||
curl_setopt($c, CURLOPT_RANGE,
|
||||
"0-".(1024 * Auth_OpenID_FETCHER_MAX_RESPONSE_KB));
|
||||
|
||||
curl_exec($c);
|
||||
|
||||
|
@ -83,8 +83,6 @@ class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher {
|
||||
"User-Agent: $user_agent",
|
||||
"Host: ".$parts['host'].
|
||||
($specify_port ? ":".$parts['port'] : ""),
|
||||
"Range: 0-".
|
||||
(1024*Auth_OpenID_FETCHER_MAX_RESPONSE_KB),
|
||||
"Port: ".$parts['port']);
|
||||
|
||||
$errno = 0;
|
||||
|
@ -91,7 +91,7 @@ class Auth_Yadis_XMLParser {
|
||||
* @return array $node_list An array of matching opaque node
|
||||
* objects to be used with other methods of this parser class.
|
||||
*/
|
||||
function evalXPath($xpath, $node = null)
|
||||
function &evalXPath($xpath, $node = null)
|
||||
{
|
||||
// Not implemented.
|
||||
}
|
||||
@ -349,7 +349,7 @@ function &Auth_Yadis_getXMLParser()
|
||||
foreach ($extensions as $name => $params) {
|
||||
if (!extension_loaded($name)) {
|
||||
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'];
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
var $_DB_DataObject_version = "1.8.11";
|
||||
var $_DB_DataObject_version = "1.8.12";
|
||||
|
||||
/**
|
||||
* The Database table (used by table extends)
|
||||
|
@ -6,9 +6,9 @@
|
||||
*
|
||||
* 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:
|
||||
* 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
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
@ -16,8 +16,8 @@
|
||||
* @package DB_DataObject
|
||||
* @author Alan Knowles <alan@akbkhome.com>
|
||||
* @copyright 1997-2008 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id: Cast.php 264148 2008-08-04 03:44:59Z alan_k $
|
||||
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||||
* @version CVS: $Id: Cast.php 287158 2009-08-12 13:58:31Z alan_k $
|
||||
* @link http://pear.php.net/package/DB_DataObject
|
||||
*/
|
||||
|
||||
|
@ -7,9 +7,9 @@
|
||||
*
|
||||
* 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:
|
||||
* 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
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
@ -17,8 +17,8 @@
|
||||
* @package DB_DataObject
|
||||
* @author Alan Knowles <alan@akbkhome.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id: Error.php 277015 2009-03-12 05:51:03Z alan_k $
|
||||
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||||
* @version CVS: $Id: Error.php 287158 2009-08-12 13:58:31Z alan_k $
|
||||
* @link http://pear.php.net/package/DB_DataObject
|
||||
*/
|
||||
|
||||
|
58
extlib/README
Normal file
58
extlib/README
Normal 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.
|
@ -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>
|
||||
|
||||
* examples/pigs_dropin.php: comment-out bind_textdomain_codeset
|
||||
|
@ -129,7 +129,7 @@ function _setlocale($category, $locale) {
|
||||
$ret = 0;
|
||||
if (function_exists('setlocale')) // I don't know if this ever happens ;)
|
||||
$ret = setlocale($category, $locale);
|
||||
if (($ret and $locale == '') or ($ret == $locale)) {
|
||||
if ($ret and ($locale == '' or $ret == $locale)) {
|
||||
$EMULATEGETTEXT = 0;
|
||||
$CURRENTLOCALE = $ret;
|
||||
} else {
|
||||
@ -148,9 +148,9 @@ function _setlocale($category, $locale) {
|
||||
*/
|
||||
function _bindtextdomain($domain, $path) {
|
||||
global $text_domains;
|
||||
// ensure $path ends with a slash
|
||||
if ($path[strlen($path) - 1] != '/') $path .= '/';
|
||||
elseif ($path[strlen($path) - 1] != '\\') $path .= '\\';
|
||||
// ensure $path ends with a slash
|
||||
if ($path[strlen($path) - 1] != '/') $path .= '/';
|
||||
elseif ($path[strlen($path) - 1] != '\\') $path .= '\\';
|
||||
$text_domains[$domain]->path = $path;
|
||||
}
|
||||
|
||||
|
@ -102,16 +102,16 @@ class gettext_reader {
|
||||
// Caching can be turned off
|
||||
$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;
|
||||
// $MAGIC2 = (int)0xde120495; //bug
|
||||
$MAGIC2 = (int) - 569244523;
|
||||
|
||||
$this->STREAM = $Reader;
|
||||
$magic = $this->readint();
|
||||
if ($magic == $MAGIC1) {
|
||||
if ($magic == ($MAGIC1 & 0xFFFFFFFF)) { // to make sure it works for 64-bit platforms
|
||||
$this->BYTEORDER = 0;
|
||||
} elseif ($magic == $MAGIC2) {
|
||||
} elseif ($magic == ($MAGIC2 & 0xFFFFFFFF)) {
|
||||
$this->BYTEORDER = 1;
|
||||
} else {
|
||||
$this->error = 1; // not MO file
|
||||
|
@ -5,6 +5,14 @@
|
||||
|
||||
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} !-d
|
||||
RewriteRule (.*) index.php?p=$1 [L,QSA]
|
||||
|
@ -143,7 +143,7 @@ function checkMirror($action_obj, $args)
|
||||
|
||||
function isLoginAction($action)
|
||||
{
|
||||
static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register');
|
||||
static $loginActions = array('login', 'recoverpassword', 'api', 'doc', 'register', 'publicxrds');
|
||||
|
||||
$login = null;
|
||||
|
||||
|
@ -692,9 +692,7 @@ function writeConf($sitename, $server, $path, $fancy, $db)
|
||||
// database
|
||||
"\$config['db']['database'] = '{$db['database']}';\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
|
||||
$res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
|
||||
|
||||
|
711
js/util.js
711
js/util.js
@ -14,370 +14,377 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category UI 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(){
|
||||
var counterBlackout = false;
|
||||
|
||||
// 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 ($('body.user_in').length > 0) {
|
||||
$('.'+SN.C.S.FormNotice).each(function() { SN.U.FormNoticeEnhancements($(this)); });
|
||||
|
||||
if (remaining < 0) {
|
||||
$("#form_notice").addClass("warning");
|
||||
} else {
|
||||
$("#form_notice").removeClass("warning");
|
||||
}
|
||||
// Skip updates for the next 500ms.
|
||||
// On slower hardware, updating on every keypress is unpleasant.
|
||||
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);
|
||||
}
|
||||
$('.form_user_subscribe').each(function() { SN.U.FormXHR($(this)); });
|
||||
$('.form_user_unsubscribe').each(function() { SN.U.FormXHR($(this)); });
|
||||
$('.form_favor').each(function() { SN.U.FormXHR($(this)); });
|
||||
$('.form_disfavor').each(function() { SN.U.FormXHR($(this)); });
|
||||
$('.form_group_join').each(function() { SN.U.FormXHR($(this)); });
|
||||
$('.form_group_leave').each(function() { SN.U.FormXHR($(this)); });
|
||||
$('.form_user_nudge').each(function() { SN.U.FormXHR($(this)); });
|
||||
|
||||
function submitonreturn(event) {
|
||||
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;
|
||||
}
|
||||
SN.U.NoticeReply();
|
||||
|
||||
// define maxLength if it wasn't defined already
|
||||
SN.U.NoticeDataAttach();
|
||||
|
||||
if (typeof(maxLength) == "undefined") {
|
||||
maxLength = 140;
|
||||
SN.U.NewDirectMessage();
|
||||
}
|
||||
|
||||
if ($("#notice_data-text").length) {
|
||||
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();
|
||||
SN.U.NoticeAttachments();
|
||||
});
|
||||
|
||||
function NoticeReply() {
|
||||
if ($('#notice_data-text').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');
|
||||
NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text());
|
||||
|
||||
var SN = { // StatusNet
|
||||
C: { // Config
|
||||
I: { // Init
|
||||
CounterBlackout: false,
|
||||
MaxLength: 140,
|
||||
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;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
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>×</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>×</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>×</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>×</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>×</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('');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
20
lib/api.php
20
lib/api.php
@ -134,11 +134,19 @@ class ApiAction extends Action
|
||||
$twitter_user['protected'] = false; # not supported by StatusNet yet
|
||||
$twitter_user['followers_count'] = $profile->subscriberCount();
|
||||
|
||||
// To be supported soon...
|
||||
$twitter_user['profile_background_color'] = '';
|
||||
$twitter_user['profile_text_color'] = '';
|
||||
$twitter_user['profile_link_color'] = '';
|
||||
$twitter_user['profile_sidebar_fill_color'] = '';
|
||||
// Need to pull up the user for some of this
|
||||
$user = $profile->getUser();
|
||||
$design = $user->getDesign();
|
||||
$defaultDesign = Design::siteDesign();
|
||||
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['friends_count'] = $profile->subscriptionCount();
|
||||
@ -147,8 +155,6 @@ class ApiAction extends Action
|
||||
|
||||
$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';
|
||||
|
||||
|
124
lib/command.php
124
lib/command.php
@ -73,7 +73,7 @@ class UntrackCommand extends UnimplementedCommand
|
||||
}
|
||||
}
|
||||
|
||||
class NudgeCommand extends UnimplementedCommand
|
||||
class NudgeCommand extends Command
|
||||
{
|
||||
var $other = null;
|
||||
function __construct($user, $other)
|
||||
@ -81,6 +81,26 @@ class NudgeCommand extends UnimplementedCommand
|
||||
parent::__construct($user);
|
||||
$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
|
||||
@ -124,18 +144,30 @@ class FavCommand extends Command
|
||||
|
||||
function execute($channel)
|
||||
{
|
||||
if(substr($this->other,0,1)=='#'){
|
||||
//favoriting a specific notice_id
|
||||
|
||||
$recipient =
|
||||
common_relative_profile($this->user, common_canonical_nickname($this->other));
|
||||
$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{
|
||||
//favoriting a given user's last notice
|
||||
|
||||
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;
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
$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
|
||||
{
|
||||
|
||||
@ -497,6 +594,9 @@ class HelpCommand extends Command
|
||||
"get <nickname> - get last notice from user\n".
|
||||
"whois <nickname> - get profile info on user\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".
|
||||
"drop <group> - leave group\n".
|
||||
"stats - get your stats\n".
|
||||
@ -507,7 +607,7 @@ class HelpCommand extends Command
|
||||
"last <nickname> - same as 'get'\n".
|
||||
"on <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".
|
||||
"track <word> - not yet implemented.\n".
|
||||
"untrack <word> - not yet implemented.\n".
|
||||
|
@ -134,6 +134,17 @@ class CommandInterpreter
|
||||
} else {
|
||||
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':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
|
@ -185,7 +185,14 @@ function _have_config()
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
$_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/subs.php';
|
||||
require_once INSTALLDIR.'/lib/Shorturl_api.php';
|
||||
require_once INSTALLDIR.'/lib/twitter.php';
|
||||
|
||||
require_once INSTALLDIR.'/lib/clientexception.php';
|
||||
require_once INSTALLDIR.'/lib/serverexception.php';
|
||||
|
@ -98,34 +98,37 @@ class ConnectSettingsNav extends Widget
|
||||
|
||||
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');
|
||||
$this->action->elementStart('ul', array('class' => 'nav'));
|
||||
|
||||
foreach ($menu as $menuaction => $menudesc) {
|
||||
$this->action->menuItem(common_local_url($menuaction),
|
||||
$menudesc[0],
|
||||
$menudesc[1],
|
||||
$action_name === $menuaction);
|
||||
if (Event::handle('StartConnectSettingsNav', array(&$this->action))) {
|
||||
|
||||
# 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'));
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
n<?php
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
|
@ -84,7 +84,8 @@ $default =
|
||||
'image' => 'http://i.creativecommons.org/l/by/3.0/80x15.png'),
|
||||
'mail' =>
|
||||
array('backend' => 'mail',
|
||||
'params' => null),
|
||||
'params' => null,
|
||||
'domain_check' => true),
|
||||
'nickname' =>
|
||||
array('blacklist' => array(),
|
||||
'featured' => array()),
|
||||
@ -140,21 +141,21 @@ $default =
|
||||
array('enabled' => true),
|
||||
'sms' =>
|
||||
array('enabled' => true),
|
||||
'twitterbridge' =>
|
||||
'twitterimport' =>
|
||||
array('enabled' => false),
|
||||
'integration' =>
|
||||
array('source' => 'StatusNet', # source attribute for Twitter
|
||||
'taguri' => $_server.',2009'), # base for tag URIs
|
||||
'twitter' =>
|
||||
array('enabled' => true,
|
||||
'consumer_key' => null,
|
||||
'consumer_secret' => null),
|
||||
'twitter' =>
|
||||
array('enabled' => true,
|
||||
'consumer_key' => null,
|
||||
'consumer_secret' => null),
|
||||
'memcached' =>
|
||||
array('enabled' => false,
|
||||
'server' => 'localhost',
|
||||
'base' => null,
|
||||
'port' => 11211),
|
||||
'ping' =>
|
||||
'ping' =>
|
||||
array('notify' => array()),
|
||||
'inboxes' =>
|
||||
array('enabled' => true), # ignored after 0.9.x
|
||||
@ -200,12 +201,12 @@ $default =
|
||||
'video/mp4',
|
||||
'video/quicktime',
|
||||
'video/mpeg'),
|
||||
'file_quota' => 5000000,
|
||||
'user_quota' => 50000000,
|
||||
'monthly_quota' => 15000000,
|
||||
'uploads' => true,
|
||||
'filecommand' => '/usr/bin/file',
|
||||
),
|
||||
'file_quota' => 5000000,
|
||||
'user_quota' => 50000000,
|
||||
'monthly_quota' => 15000000,
|
||||
'uploads' => true,
|
||||
'filecommand' => '/usr/bin/file',
|
||||
),
|
||||
'group' =>
|
||||
array('maxaliases' => 3,
|
||||
'desclimit' => null),
|
||||
@ -229,4 +230,6 @@ $default =
|
||||
array('contentlimit' => null),
|
||||
'http' =>
|
||||
array('client' => 'curl'), // XXX: should this be the default?
|
||||
'location' =>
|
||||
array('namespace' => 1), // 1 = geonames, 2 = Yahoo Where on Earth
|
||||
);
|
||||
|
@ -48,7 +48,7 @@ if (!defined('STATUSNET')) {
|
||||
class HTTPResponse
|
||||
{
|
||||
public $code = null;
|
||||
public $headers = null;
|
||||
public $headers = array();
|
||||
public $body = null;
|
||||
}
|
||||
|
||||
|
@ -176,6 +176,7 @@ function jabber_format_entry($profile, $notice)
|
||||
$xs = new XMLStringer();
|
||||
$xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im'));
|
||||
$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),
|
||||
$profile->nickname);
|
||||
$xs->text(": ");
|
||||
@ -184,6 +185,11 @@ function jabber_format_entry($profile, $notice)
|
||||
} else {
|
||||
$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('html');
|
||||
|
||||
|
@ -101,35 +101,36 @@ function get_nice_language_list()
|
||||
*/
|
||||
function get_all_languages() {
|
||||
return array(
|
||||
'bg' => array('q' => 0.8, 'lang' => 'bg_BG', 'name' => 'Bulgarian', 'direction' => 'ltr'),
|
||||
'ca' => array('q' => 0.5, 'lang' => 'ca_ES', 'name' => 'Catalan', 'direction' => 'ltr'),
|
||||
'cs' => array('q' => 0.5, 'lang' => 'cs_CZ', 'name' => 'Czech', 'direction' => 'ltr'),
|
||||
'de' => array('q' => 0.8, 'lang' => 'de_DE', 'name' => 'German', 'direction' => 'ltr'),
|
||||
'bg' => array('q' => 0.8, 'lang' => 'bg', 'name' => 'Bulgarian', 'direction' => 'ltr'),
|
||||
'ca' => array('q' => 0.5, 'lang' => 'ca', 'name' => 'Catalan', 'direction' => 'ltr'),
|
||||
'cs' => array('q' => 0.5, 'lang' => 'cs', 'name' => 'Czech', 'direction' => 'ltr'),
|
||||
'de' => array('q' => 0.8, 'lang' => 'de', 'name' => 'German', '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' => 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'),
|
||||
'fi' => array('q' => 1, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'),
|
||||
'fr-fr' => array('q' => 1, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'),
|
||||
'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'rtl'),
|
||||
'it' => array('q' => 1, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'ltr'),
|
||||
'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'),
|
||||
'ko' => array('q' => 0.9, 'lang' => 'ko_KR', 'name' => 'Korean', 'direction' => 'ltr'),
|
||||
'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'),
|
||||
'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
|
||||
'no' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
|
||||
'nn' => array('q' => 1, 'lang' => 'nn_NO', 'name' => 'Norwegian (Nynorsk)', 'direction' => 'ltr'),
|
||||
'nl' => array('q' => 0.5, 'lang' => 'nl_NL', 'name' => 'Dutch', 'direction' => 'ltr'),
|
||||
'pl' => array('q' => 0.5, 'lang' => 'pl_PL', 'name' => 'Polish', 'direction' => 'ltr'),
|
||||
'fr-fr' => array('q' => 1, 'lang' => 'fr', 'name' => 'French', 'direction' => 'ltr'),
|
||||
'ga' => array('q' => 0.5, 'lang' => 'ga', 'name' => 'Galician', 'direction' => 'ltr'),
|
||||
'he' => array('q' => 0.5, 'lang' => 'he', 'name' => 'Hebrew', 'direction' => 'rtl'),
|
||||
'it' => array('q' => 1, 'lang' => 'it', 'name' => 'Italian', 'direction' => 'ltr'),
|
||||
'jp' => array('q' => 0.5, 'lang' => 'ja', 'name' => 'Japanese', 'direction' => 'ltr'),
|
||||
'ko' => array('q' => 0.9, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'),
|
||||
'mk' => array('q' => 0.5, 'lang' => 'mk', 'name' => 'Macedonian', 'direction' => 'ltr'),
|
||||
'nb' => array('q' => 0.1, 'lang' => 'nb', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
|
||||
'no' => array('q' => 0.1, 'lang' => 'nb', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'),
|
||||
'nn' => array('q' => 1, 'lang' => 'nn', 'name' => 'Norwegian (Nynorsk)', '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-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'),
|
||||
'sv' => array('q' => 0.8, 'lang' => 'sv_SE', 'name' => 'Swedish', 'direction' => 'ltr'),
|
||||
'te' => array('q' => 0.3, 'lang' => 'te_IN', 'name' => 'Telugu', 'direction' => 'ltr'),
|
||||
'tr' => array('q' => 0.5, 'lang' => 'tr_TR', 'name' => 'Turkish', 'direction' => 'ltr'),
|
||||
'uk' => array('q' => 1, 'lang' => 'uk_UA', 'name' => 'Ukrainian', 'direction' => 'ltr'),
|
||||
'vi' => array('q' => 0.8, 'lang' => 'vi_VN', 'name' => 'Vietnamese', 'direction' => 'ltr'),
|
||||
'ru' => array('q' => 0.9, 'lang' => 'ru', 'name' => 'Russian', 'direction' => 'ltr'),
|
||||
'sv' => array('q' => 0.8, 'lang' => 'sv', 'name' => 'Swedish', 'direction' => 'ltr'),
|
||||
'te' => array('q' => 0.3, 'lang' => 'te', 'name' => 'Telugu', 'direction' => 'ltr'),
|
||||
'tr' => array('q' => 0.5, 'lang' => 'tr', 'name' => 'Turkish', 'direction' => 'ltr'),
|
||||
'uk' => array('q' => 1, 'lang' => 'uk', 'name' => 'Ukrainian', '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-hant' => array('q' => 0.2, 'lang' => 'zh_TW', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'),
|
||||
);
|
||||
|
188
lib/location.php
Normal file
188
lib/location.php
Normal 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;
|
||||
}
|
||||
}
|
72
lib/mail.php
72
lib/mail.php
@ -640,75 +640,3 @@ function mail_notify_attn($user, $notice)
|
||||
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
284
lib/mediafile.php
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -80,10 +80,21 @@ class MessageForm extends Form
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return int ID of the form
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_notice-direct';
|
||||
}
|
||||
|
||||
/**
|
||||
* Class of the form
|
||||
*
|
||||
* @return string class of the form
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_notice';
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ class NoticeForm extends Form
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return int ID of the form
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
@ -113,6 +113,17 @@ class NoticeForm extends Form
|
||||
return 'form_notice';
|
||||
}
|
||||
|
||||
/**
|
||||
* Class of the form
|
||||
*
|
||||
* @return string class of the form
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_notice';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
|
@ -199,6 +199,7 @@ class NoticeListItem extends Widget
|
||||
{
|
||||
$this->out->elementStart('div', 'entry-content');
|
||||
$this->showNoticeLink();
|
||||
$this->showNoticeLocation();
|
||||
$this->showNoticeSource();
|
||||
$this->showContext();
|
||||
$this->out->elementEnd('div');
|
||||
@ -369,6 +370,44 @@ class NoticeListItem extends Widget
|
||||
$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
|
||||
*
|
||||
|
@ -87,7 +87,7 @@ function omb_broadcast_notice($notice)
|
||||
common_debug('Posting to ' . $rp->postnoticeurl, __FILE__);
|
||||
|
||||
/* Post notice. */
|
||||
$service = new Laconica_OMB_Service_Consumer(
|
||||
$service = new StatusNet_OMB_Service_Consumer(
|
||||
array(OMB_ENDPOINT_POSTNOTICE => $rp->postnoticeurl));
|
||||
try {
|
||||
$service->setToken($rp->token, $rp->secret);
|
||||
|
@ -62,9 +62,15 @@ class ProfileList extends Widget
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->startList();
|
||||
$cnt = $this->showProfiles();
|
||||
$this->endList();
|
||||
$cnt = 0;
|
||||
|
||||
if (Event::handle('StartProfileList', array($this))) {
|
||||
$this->startList();
|
||||
$cnt = $this->showProfiles();
|
||||
$this->endList();
|
||||
Event::handle('EndProfileList', array($this));
|
||||
}
|
||||
|
||||
return $cnt;
|
||||
}
|
||||
|
||||
@ -117,10 +123,19 @@ class ProfileListItem extends Widget
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->startItem();
|
||||
$this->showProfile();
|
||||
$this->showActions();
|
||||
$this->endItem();
|
||||
if (Event::handle('StartProfileListItem', array($this))) {
|
||||
$this->startItem();
|
||||
if (Event::handle('StartProfileListItemProfile', array($this))) {
|
||||
$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()
|
||||
@ -132,11 +147,29 @@ class ProfileListItem extends Widget
|
||||
function showProfile()
|
||||
{
|
||||
$this->startProfile();
|
||||
$this->showAvatar();
|
||||
$this->showFullName();
|
||||
$this->showLocation();
|
||||
$this->showHomepage();
|
||||
$this->showBio();
|
||||
if (Event::handle('StartProfileListItemProfileElements', array($this))) {
|
||||
if (Event::handle('StartProfileListItemAvatar', array($this))) {
|
||||
$this->showAvatar();
|
||||
Event::handle('EndProfileListItemAvatar', array($this));
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
@ -225,7 +258,10 @@ class ProfileListItem extends Widget
|
||||
function showActions()
|
||||
{
|
||||
$this->startActions();
|
||||
$this->showSubscribeButton();
|
||||
if (Event::handle('StartProfileListItemActionElements', array($this))) {
|
||||
$this->showSubscribeButton();
|
||||
Event::handle('EndProfileListItemActionElements', array($this));
|
||||
}
|
||||
$this->endActions();
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,22 @@ define('CLAIM_TIMEOUT', 1200);
|
||||
define('QUEUE_HANDLER_MISS_IDLE', 10);
|
||||
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
|
||||
{
|
||||
|
||||
@ -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()
|
||||
{
|
||||
return 60;
|
||||
@ -54,24 +78,69 @@ class QueueHandler extends Daemon
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
if (!$this->start()) {
|
||||
@ -100,6 +169,14 @@ class QueueHandler extends Daemon
|
||||
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)
|
||||
{
|
||||
if ($timeout > 0) {
|
||||
|
937
lib/router.php
937
lib/router.php
File diff suppressed because it is too large
Load Diff
@ -48,17 +48,6 @@ class UnQueueManager
|
||||
jabber_public_notice($notice);
|
||||
}
|
||||
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':
|
||||
if ($this->_isLocal($notice)) {
|
||||
require_once INSTALLDIR . '/lib/ping.php';
|
||||
@ -77,7 +66,7 @@ class UnQueueManager
|
||||
break;
|
||||
default:
|
||||
if (Event::handle('UnqueueHandleNotice', array(&$notice, $queue))) {
|
||||
throw ServerException("UnQueueManager: Unknown queue: $queue");
|
||||
throw new ServerException("UnQueueManager: Unknown queue: $queue");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
lib/util.php
30
lib/util.php
@ -51,13 +51,23 @@ function common_init_locale($language=null)
|
||||
function common_init_language()
|
||||
{
|
||||
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();
|
||||
// So we don't have to make people install the gettext locales
|
||||
$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");
|
||||
textdomain("statusnet");
|
||||
setlocale(LC_CTYPE, 'C');
|
||||
|
||||
if(!$locale_set) {
|
||||
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);
|
||||
$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('/(^|[\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);
|
||||
@ -771,12 +781,18 @@ function common_path($relative, $ssl=false)
|
||||
if (is_string(common_config('site', 'sslserver')) &&
|
||||
mb_strlen(common_config('site', 'sslserver')) > 0) {
|
||||
$serverpart = common_config('site', 'sslserver');
|
||||
} else {
|
||||
} else if (common_config('site', 'server')) {
|
||||
$serverpart = common_config('site', 'server');
|
||||
} else {
|
||||
common_log(LOG_ERR, 'Site Sever not configured, unable to determine site name.');
|
||||
}
|
||||
} else {
|
||||
$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;
|
||||
@ -896,8 +912,6 @@ function common_broadcast_notice($notice, $remote=false)
|
||||
function common_enqueue_notice($notice)
|
||||
{
|
||||
static $localTransports = array('omb',
|
||||
'twitter',
|
||||
'facebook',
|
||||
'ping');
|
||||
|
||||
static $allTransports = array('sms', 'plugin');
|
||||
|
@ -1,21 +1,12 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Public XRDS for OpenID
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Low-level generator for HTML
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
@ -27,60 +18,44 @@
|
||||
*
|
||||
* 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 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')) {
|
||||
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
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <millette@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @todo factor out similarities with XrdsAction
|
||||
* @see Action
|
||||
* @see XMLOutputter
|
||||
*/
|
||||
class PublicxrdsAction extends Action
|
||||
class XRDSOutputter extends XMLOutputter
|
||||
{
|
||||
/**
|
||||
* Is read only?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
public function startXRDS()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
header('Content-Type: application/xrds+xml');
|
||||
$this->startXML();
|
||||
$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'));
|
||||
$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');
|
||||
}
|
||||
|
||||
public function endXRDS()
|
||||
{
|
||||
$this->elementEnd('XRDS');
|
||||
$this->endXML();
|
||||
}
|
||||
@ -96,7 +71,7 @@ class PublicxrdsAction extends Action
|
||||
*
|
||||
* @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');
|
||||
if ($uri) {
|
||||
@ -119,4 +94,3 @@ class PublicxrdsAction extends Action
|
||||
$this->elementEnd('Service');
|
||||
}
|
||||
}
|
||||
|
BIN
locale/bg/LC_MESSAGES/statusnet.mo
Normal file
BIN
locale/bg/LC_MESSAGES/statusnet.mo
Normal file
Binary file not shown.
Binary file not shown.
BIN
locale/cs/LC_MESSAGES/statusnet.mo
Normal file
BIN
locale/cs/LC_MESSAGES/statusnet.mo
Normal file
Binary file not shown.
Binary file not shown.
BIN
locale/de/LC_MESSAGES/statusnet.mo
Normal file
BIN
locale/de/LC_MESSAGES/statusnet.mo
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
locale/fr/LC_MESSAGES/statusnet.mo
Normal file
BIN
locale/fr/LC_MESSAGES/statusnet.mo
Normal file
Binary file not shown.
Binary file not shown.
BIN
locale/ga/LC_MESSAGES/statusnet.mo
Normal file
BIN
locale/ga/LC_MESSAGES/statusnet.mo
Normal file
Binary file not shown.
4713
locale/ga/LC_MESSAGES/statusnet.po
Normal file
4713
locale/ga/LC_MESSAGES/statusnet.po
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user