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…
x
Reference in New Issue
Block a user