Merge branch '0.9-release'

* 0.9-release: (874 commits)
  Removed call to NewDirectMessage() until IE return is fixed i.e.,
  Don't show flag user button your own profile
  Fixed HXR response for flag user
  Using the right form class name
  Using common_redirect
  Left a form_data class of a <ul> in the user admin panel
  Added validation to fields in user admin panel
  Added a user admin panel
  Added mobile logos for default and identica themes
  Changed gif to png
  Changed this to action. THANKS zach!
  Doing content negotiation only once
  Add execute bit to pingqueuehandler
  Localisation updates for !StatusNet from !translatewiki.net
  Use the browser's geolocation API to set the location on the notice form
  Add geometa library, and include it.
  Add location form elements to the noticeform, and save their values on submission
  Use the $user object nickname, as login name doesnt have to == nickname anymore with plugins such as ldap/etc
  Revert "Re added NICKNAME_FMT constant to router.php."
  Moved most path and server settings to a new paths admin panel
  ...

Conflicts:
	js/util.js
	locale/it_IT/LC_MESSAGES/statusnet.mo
	locale/mk_MK/LC_MESSAGES/statusnet.mo
	locale/mk_MK/LC_MESSAGES/statusnet.po
	locale/pt_BR/LC_MESSAGES/statusnet.mo
	locale/vi_VN/LC_MESSAGES/statusnet.mo
	plugins/InfiniteScroll/infinitescroll.js
	plugins/Realtime/realtimeupdate.js
This commit is contained in:
Zach Copley 2009-11-19 20:12:46 -08:00
commit 4b98edf75f
556 changed files with 212549 additions and 158143 deletions

2
.gitignore vendored
View File

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

View File

@ -32,10 +32,10 @@ StartShowLaconicaStyles: backwards compatibility; deprecated
EndShowLaconicaStyles: backwards compatibility; deprecated
- $action: the current action
StartShowUAStyles: Showing custom UA Style links
StartShowUAStyles: Showing custom User-Agent style links
- $action: the current action
EndShowUAStyles: End showing custom UA Style links; good place to add user-agent (e.g., filter, -webkit, -moz) specific styles
EndShowUAStyles: End showing custom User-Agent links; good place to add user-agent (e.g., filter, -webkit, -moz) specific styles
- $action: the current action
StartShowScripts: Showing JavaScript links
@ -87,6 +87,18 @@ StartShowContentBlock: Showing before the content container
EndShowContentBlock: Showing after the content container
- $action: the current action
StartShowAside: Showing before the Aside container
- $action: the current action
EndShowAside: Showing after the Aside container
- $action: the current action
StartShowNoticeFormData: Showing before the notice form data
- $action: the current action
EndShowNoticeFormData: Showing after the notice form data
- $action: the current action
StartNoticeSave: before inserting a notice (good place for content filters)
- $notice: notice being saved (no ID or URI)
@ -117,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
@ -134,3 +149,428 @@ StartAddressData: Allows the site owner to provide additional information about
EndAddressData: At the end of <address>
- $action: the current action
StartLoginGroupNav: Before showing the login and register navigation menu
- $action: the current action
EndLoginGroupNav: After showing the login and register navigation menu
- $action: the current action
StartAccountSettingsNav: Before showing the account settings menu
- $action: the current action
EndAccountSettingsNav: After showing the account settings menu
- $action: the current action
StartAccountSettingsProfileMenuItem: Before showing the Profile menu item
- $widget: AccountSettingsNav instance being shown
EndAccountSettingsProfileMenuItem: After showing the Profile menu item
- $widget: AccountSettingsNav instance being shown
StartAccountSettingsAvatarMenuItem: Before showing the Avatar menu item
- $widget: AccountSettingsNav instance being shown
EndAccountSettingsAvatarMenuItem: After showing the Avatar menu item
- $widget: AccountSettingsNav instance being shown
StartAccountSettingsPasswordMenuItem: Before showing the Password menu item
- $widget: AccountSettingsNav instance being shown
EndAccountSettingsPasswordMenuItem: After showing the Password menu item
- $widget: AccountSettingsNav instance being shown
StartAccountSettingsEmailMenuItem: Before showing the Email menu item
- $widget: AccountSettingsNav instance being shown
EndAccountSettingsEmailMenuItem: After showing the Email menu item
- $widget: AccountSettingsNav instance being shown
StartAccountSettingsDesignMenuItem: Before showing the Design menu item
- $widget: AccountSettingsNav instance being shown
EndAccountSettingsDesignMenuItem: After showing the Design menu item
- $widget: AccountSettingsNav instance being shown
StartAccountSettingsOtherMenuItem: Before showing the Other menu item
- $widget: AccountSettingsNav instance being shown
EndAccountSettingsOtherMenuItem: After showing the Other menu item
- $widget: AccountSettingsNav instance being shown
Autoload: When trying to autoload a class
- $cls: the class being sought. A plugin might require_once the file for the class.
SensitiveAction: determines if an action is 'sensitive' and should use SSL
- $action: name of the action, like 'login'
- $sensitive: flag for whether this is a sensitive action
LoginAction: determines if an action is a 'login' action (OK for public view in private mode)
- $action: name of the action, like 'register'
- $login: flag for whether this is a login action
StartShowHead: called before showing the <head> element and children
- $action: action object being show
EndShowHead: called after showing the <head> element (and </head>)
- $action: action object being shown
StartShowBody: called before showing the <body> element and children
- $action: action object being shown
EndShowBody: called after showing the <body> element (and </body>)
- $action: action object being shown
StartPersonalGroupNav: beginning of personal group nav menu
- $action: action object being shown
EndPersonalGroupNav: end of personal group nav menu (good place to add a menu item)
- $action: action object being shown
StartGroupGroupNav: Showing the group nav menu
- $action: the current action
EndGroupGroupNav: At the end of the group nav menu
- $action: the current action
StartEndHTML: just before the </html> tag
- $action: action object being shown
EndEndHTML: just after the </html> tag
- $action: action object being shown
StartShowDesign: just before showing a site, user, or group design
- $action: action object being shown
EndShowDesign: just after showing a site, user, or group design
- $action: action object being shown
StartShowExportData: just before showing the <div> with export data (feeds)
- $action: action object being shown
EndShowExportData: just after showing the <div> with export data (feeds)
- $action: action object being shown
StartShowNoticeItem: just before showing the notice item
- $action: action object being shown
EndShowNoticeItem: just after showing the notice item
- $action: action object being shown
StartShowPageNotice: just before showing the page notice (instructions or error)
- $action: action object being shown
EndShowPageNotice: just after showing the page notice (instructions or error)
- $action: action object being shown
StartShowPageTitle: just before showing the main h1 title of a page (only for registration)
- $action: action object being shown
StartProfileFormData: just before showing text entry fields on profile settings page
- $action: action object being shown
EndProfileFormData: just after showing text entry fields on profile settings page
- $action: action object being shown
StartProfileSaveForm: before starting to save a profile settings form
- $action: action object being shown
EndProfileSaveForm: after saving a profile settings form (after commit, no profile or user object!)
- $action: action object being shown
StartRegistrationFormData: just before showing text entry fields on registration page
- $action: action object being shown
EndRegistrationFormData: just after showing text entry fields on registration page
- $action: action object being shown
StartRegistrationTry: before validating and saving a new user
- $action: action object being shown
EndRegistrationTry: after saving a new user (note: no profile or user object!)
- $action: action object being shown
StartNewQueueManager: before trying to start a new queue manager; good for plugins implementing new queue manager classes
- $qm: empty queue manager to set
RedirectToLogin: event when we force a redirect to login (like when going to a settings page on a remembered login)
- $action: action object being shown
- $user: current user
StartLoadDoc: before loading a help doc (hook this to show your own documentation)
- $title: title of the document
- $output: HTML output to show
EndLoadDoc: after loading a help doc (hook this to modify other documentation)
- $title: title of the document
- $output: HTML output to show
StartApiRss: after the rss <channel> element is started
- $action: action object being shown
StartApiAtom: after the <feed> element is started
- $action: action object being shown
StartEnqueueNotice: about to add a notice to the queues (good place to add a new transport)
- $notice: the notice being added
- &$transports: modifiable list of transports (as strings) to queue for
EndEnqueueNotice: after adding a notice to the queues
- $notice: the notice being added
- $transports: modifiable list of transports to use
UnqueueHandleNotice: Handle a notice when no queue manager is available
- $notice: the notice to handle
- $queue: the "queue" that is being executed
GetValidDaemons: Just before determining which daemons to run
- &$daemons: modifiable list of daemon scripts to run, filenames relative to scripts/
HandleQueuedNotice: Handle a queued notice at queue time (or immediately if no queue)
- &$notice: notice to handle
StartShowHeadElements: Right after the <head> tag
- $action: the current action
EndShowHeadElements: Right before the </head> tag; put <script>s here if you need them in <head>
- $action: the current action
CheckSchema: chance to check the schema
StartProfilePageProfileSection: Starting to show the section of the
profile page with the actual profile data;
hook to prevent showing the profile (e.g.)
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageProfileElements: inside the section, before the first
element; prepend elements here
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageProfileElements: inside the section, after the last element;
append elements here
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageProfileSection: After showing the section of the profile
page with the profile elements
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageActionsSection: Starting to show the section of the
profile page with action links; hook
to hide them (for example)
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageActionsElements: inside the list, before the first
element; prepend elements here
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageActionsElements: inside the list, after the last element;
append elements here
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageActionsSection: After showing the section of the profile
page with the entity actions
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageAvatar: before showing the avatar on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageAvatar: after showing the avatar on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageNickname: before showing the nickname on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageNickname: after showing the nickname on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageFullName: before showing the fullname on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageFullName: after showing the fullname on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageLocation: before showing the location on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageLocation: after showing the location on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageHomepage: before showing the homepage link on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageHomepage: after showing the homepage on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageBio: before showing the bio on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageBio: after showing the bio on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
StartProfilePageProfileTags: before showing the tags on the profile page
- $userprofile: UserProfile widget
- &$profile: the profile being shown
EndProfilePageProfileTags: after showing the tags on the profile page
- $userprofile: UserProfile widget
- &$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
StartCheckPassword: Check a username/password
- $nickname: The nickname to check
- $password: The password to check
- &$authenticatedUser: set to User object if credentials match a user.
EndCheckPassword: After checking a username/password pair
- $nickname: The nickname that was checked
- $password: The password that was checked
- $authenticatedUser: User object if credentials match a user, else null.
StartChangePassword: Before changing a password
- $user: user
- $oldpassword: the user's old password
- $newpassword: the desired new password
EndChangePassword: After changing a password
- $user: user
StartSetUser: Before setting the currently logged in user
- $user: user
EndSetUser: After setting the currently logged in user
- $user: user
StartSetApiUser: Before setting the current API user
- $user: user
EndSetApiUser: After setting the current API user
- $user: user
StartHasRole: Before determing if the a profile has a given role
- $profile: profile in question
- $name: name of the role in question
- &$has_role: does this profile have the named role?
EndHasRole: Before determing if the a profile has a given role
- $profile: profile in question
- $name: name of the role in question
- $has_role: does this profile have the named role?
UserDeleteRelated: Specify additional tables to delete entries from when deleting users
- $user: User object
- &$related: array of DB_DataObject class names to delete entries on matching user_id.
GetUrlShorteners: Specify URL shorteners that are available for use
- &$shorteners: append your shortener to this array like so: $shorteners[shortenerName]=array('display'=>display, 'freeService'=>boolean)
StartShortenUrl: About to shorten a URL
- $url: url to be shortened
- $shortenerName: name of the requested shortener
- &$shortenedUrl: short version of the url
EndShortenUrl: After a URL has been shortened
- $url: url to be shortened
- $shortenerName: name of the requested shortener
- $shortenedUrl: short version of the url

254
README
View File

@ -150,6 +150,7 @@ released Aug 26 2009. Notable changes this version:
- 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.)
- a script to register a new user.
- a script to make a user admin of a group.
@ -388,20 +389,16 @@ the server first.
Sphinx
------
To use a Sphinx server to search users and notices, you also need
to install, compile and enable the sphinx pecl extension for php on the
client side, which itself depends on the sphinx development files.
"pecl install sphinx" should take care of that. Add "extension=sphinx.so"
to your php.ini and reload apache to enable it.
To use a Sphinx server to search users and notices, you'll need to
enable the SphinxSearch plugin. Add to your config.php:
You can update your MySQL or Postgresql databases to drop their fulltext
search indexes, since they're now provided by sphinx.
addPlugin('SphinxSearch');
$config['sphinx']['server'] = 'searchhost.local';
On the sphinx server side, a script reads the main database and build
the keyword index. A cron job reads the database and keeps the sphinx
indexes up to date. scripts/sphinx-cron.sh should be called by cron
every 5 minutes, for example. scripts/sphinx.sh is an init.d script
to start and stop the sphinx search daemon.
You also need to install, compile and enable the sphinx pecl extension for
php on the client side, which itself depends on the sphinx development files.
See plugins/SphinxSearch/README for more details and server setup.
SMS
---
@ -558,10 +555,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
@ -579,101 +572,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
--------
@ -787,6 +685,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
=========
@ -871,40 +779,8 @@ to update it.
Notice inboxes
--------------
Before version 0.6.2, the page showing all notices from people the
user is subscribed to ("so-and-so with friends") was calculated at run
time. Starting with 0.6.2, we have a new data structure for holding a
user's "notice inbox". (Note: distinct from the "message inbox", which
is the "inbox" tab in the UI. The notice inbox appears under the
"Personal" tab.)
Notices are added to the inbox when they're created. This speeds up
the query considerably, and also allows us the opportunity, in the
future, to add different kind of notices to an inbox -- like @-replies
or subscriptions to search terms or hashtags.
Notice inboxes are enabled by default for new installations. If you
are upgrading an existing site, this means that your users will see
empty "Personal" pages. The following steps will help you fix the
problem.
0. $config['inboxes']['enabled'] can be set to one of three values. If
you set it to 'false', the site will work as before. Support for this
will probably be dropped in future versions.
1. Setting the flag to 'transitional' means that you're in transition.
In this mode, the code will run the "new query" or the "old query"
based on whether the user's inbox has been updated.
2. After setting the flag to "transitional", you can run the
fixup_inboxes.php script to create the inboxes. You may want to set
the memory limit high. You can re-run it without ill effect.
3. When fixup_inboxes is finished, you can set the enabled flag to
'true'.
NOTE: As of version 0.8.1 notice inboxes are automatically trimmed back
to ~1000 notices every once in a while.
NOTE: we will drop support for non-inboxed sites in the 0.9.x version
of StatusNet. It's time to switch now!
Notice inboxes are now required. If you don't have inboxes enabled,
StatusNet will no longer run.
UTF-8 Database
--------------
@ -976,6 +852,12 @@ locale_path: full path to the directory for locale data. Unless you
store all your locale data in one place, you probably
don't need to use this.
language: default language for your site. Defaults to US English.
Note that this is overridden if a user is logged in and has
selected a different language. It is also overridden if the
user is NOT logged in, but their browser requests a different
langauge. Since pretty much everybody's browser requests a
language, that means that changing this setting has little or
no effect in practice.
languages: A list of languages supported on your site. Typically you'd
only change this if you wanted to disable support for one
or another language:
@ -1000,8 +882,6 @@ closed: If set to 'true', will disallow registration on your site.
the service, *then* set this variable to 'true'.
inviteonly: If set to 'true', will only allow registration if the user
was invited by an existing user.
openidonly: If set to 'true', will only allow registrations and logins
through OpenID.
private: If set to 'true', anonymous users will be redirected to the
'login' page. Also, API methods that normally require no
authentication will require it. Note that this does not turn
@ -1029,6 +909,9 @@ shorturllength: Length of URL at which URLs in a message exceeding 140
dupelimit: minimum time allowed for one person to say the same thing
twice. Default 60s. Anything lower is considered a user
or UI error.
textlimit: default max size for texts in the site. Defaults to 140.
0 means no limit. Can be fine-tuned for notices, messages,
profile bios and group descriptions.
db
--
@ -1068,6 +951,14 @@ utf8: whether to talk to the database in UTF-8 mode. This is the default
with new installations, but older sites may want to turn it off
until they get their databases fixed up. See "UTF-8 database"
above for details.
schemacheck: when to let plugins check the database schema to add
tables or update them. Values can be 'runtime' (default)
or 'script'. 'runtime' can be costly (plugins check the
schema on every hit, adding potentially several db
queries, some quite long), but not everyone knows how to
run a script. If you can, set this to 'script' and run
scripts/checkschema.php whenever you install or upgrade a
plugin.
syslog
------
@ -1229,14 +1120,6 @@ For configuring invites.
enabled: Whether to allow users to send invites. Default true.
openid
------
For configuring OpenID.
enabled: Whether to allow users to register and login using OpenID. Default
true.
tag
---
@ -1287,17 +1170,6 @@ base: memcached uses key-value pairs to store data. We build long,
StatusNet site using your memcached server.
port: Port to connect to; defaults to 11211.
sphinx
------
You can get a significant boost in performance using Sphinx Search
instead of your database server to search for users and notices.
<http://sphinxsearch.com/>.
enabled: Set to true to enable. Default false.
server: a string with the hostname of the sphinx server.
port: an integer with the port number of the sphinx server.
emailpost
---------
@ -1314,24 +1186,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
@ -1339,9 +1198,8 @@ inboxes
For notice inboxes.
enabled: A three-valued flag for whether to use notice inboxes (see
upgrading info above for notes about this change). Can be
'false', 'true', or '"transitional"'.
enabled: No longer used. If you set this to something other than true,
StatusNet will no longer run.
throttle
--------
@ -1363,6 +1221,8 @@ banned: an array of usernames and/or profile IDs of 'banned' profiles.
The site will reject any notices by these users -- they will
not be accepted at all. (Compare with blacklisted users above,
whose posts just won't show up in the public stream.)
biolimit: max character length of bio; 0 means no limit; null means to use
the site text limit default.
newuser
-------
@ -1459,6 +1319,9 @@ Options for group functionality.
maxaliases: maximum number of aliases a group can have. Default 3. Set
to 0 or less to prevent aliases in a group.
desclimit: maximum number of characters to allow in group descriptions.
null (default) means to use the site-wide text limits. 0
means no limit.
oohembed
--------
@ -1505,15 +1368,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
----
@ -1537,6 +1391,24 @@ linkcolor: Hex color of all links.
backgroundimage: Image to use for the background.
disposition: Flags for whether or not to tile the background image.
notice
------
Configuration options specific to notices.
contentlimit: max length of the plain-text content of a notice.
Default is null, meaning to use the site-wide text limit.
0 means no limit.
message
-------
Configuration options specific to messages.
contentlimit: max length of the plain-text content of a message.
Default is null, meaning to use the site-wide text limit.
0 means no limit.
Plugins
=======

View File

@ -1,6 +1,6 @@
<?php
/**
* Access token class.
* Access token class
*
* PHP version 5
*
@ -32,10 +32,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
require_once INSTALLDIR.'/lib/omb.php';
/**
* Access token class.
* Access token class
*
* @category Action
* @package StatusNet
@ -47,28 +48,23 @@ require_once INSTALLDIR.'/lib/omb.php';
class AccesstokenAction extends Action
{
/**
* Class handler.
* Class handler
*
* @param array $args query arguments
*
* @return boolean false if user doesn't exist
*/
* @return nothing
*
**/
function handle($args)
{
parent::handle($args);
try {
common_debug('getting request from env variables', __FILE__);
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('accesstoken'));
common_debug('getting a server', __FILE__);
$server = omb_oauth_server();
common_debug('fetching the access token', __FILE__);
$token = $server->fetch_access_token($req);
common_debug('got this token: "'.print_r($token, true).'"', __FILE__);
common_debug('printing the access token', __FILE__);
print $token;
} catch (OAuthException $e) {
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
omb_oauth_server());
$srv->writeAccessToken();
} catch (Exception $e) {
$this->serverError($e->getMessage());
}
}
}
?>

View File

@ -1,5 +1,5 @@
<?php
/*
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
@ -15,9 +15,25 @@
*
* 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 Actions
* @package Actions
* @author Evan Prodromou <evan@status.net>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <millette@controlyourself.ca>
* @author Adrian Lang <mail@adrianlang.de>
* @author Meitar Moscovitz <meitarm@gmail.com>
* @author Sarven Capadisli <csarven@status.net>
* @author Craig Andrews <candrews@integralblue.com>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@controlyourself.ca>
* @license GNU Affero General Public License http://www.gnu.org/licenses/
* @link http://status.net
*/
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/personalgroupnav.php';
require_once INSTALLDIR.'/lib/noticelist.php';
@ -43,8 +59,8 @@ class AllAction extends ProfileAction
$this->notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
}
if($this->page > 1 && $this->notice->N == 0){
$this->serverError(_('No such page'),$code=404);
if ($this->page > 1 && $this->notice->N == 0) {
$this->serverError(_('No such page'), $code = 404);
}
return true;
@ -73,20 +89,31 @@ class AllAction extends ProfileAction
function getFeeds()
{
return array(new Feed(Feed::RSS1,
common_local_url('allrss', array('nickname' =>
$this->user->nickname)),
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')),
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')),
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)));
return array(
new Feed(Feed::RSS1,
common_local_url(
'allrss', array(
'nickname' =>
$this->user->nickname)
),
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
new Feed(Feed::RSS2,
common_local_url(
'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(
'ApiTimelineFriends', array(
'format' => 'atom',
'id' => $this->user->nickname
)
),
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))
);
}
function showLocalNav()
@ -106,11 +133,8 @@ class AllAction extends ProfileAction
} else {
$message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
}
}
else {
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'),
(!common_config('site','openidonly')) ? 'register' : 'openidlogin',
$this->user->nickname);
} else {
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
}
$this->elementStart('div', 'guide');
@ -128,17 +152,19 @@ class AllAction extends ProfileAction
$this->showEmptyListMessage();
}
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
$this->page, 'all', array('nickname' => $this->user->nickname));
$this->pagination(
$this->page > 1, $cnt > NOTICES_PER_PAGE,
$this->page, 'all', array('nickname' => $this->user->nickname)
);
}
function showPageTitle()
{
$user =& common_current_user();
if ($user && ($user->id == $this->user->id)) {
$this->element('h1', NULL, _("You and friends"));
$this->element('h1', null, _("You and friends"));
} else {
$this->element('h1', NULL, sprintf(_('%s and friends'), $this->user->nickname));
$this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname));
}
}

View File

@ -68,6 +68,7 @@ class AllrssAction extends Rss10Action
$this->clientError(_('No such user.'));
return false;
} else {
$this->notices = $this->getNotices($this->limit);
return true;
}
}

View File

@ -1,293 +0,0 @@
<?php
/*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class ApiAction extends Action
{
var $user;
var $content_type;
var $api_arg;
var $api_method;
var $api_action;
var $auth_user;
var $auth_pw;
function handle($args)
{
parent::handle($args);
$this->api_action = $this->arg('apiaction');
$method = $this->arg('method');
$argument = $this->arg('argument');
$this->basic_auth_process_header();
if (isset($argument)) {
$cmdext = explode('.', $argument);
$this->api_arg = $cmdext[0];
$this->api_method = $method;
$this->content_type = strtolower($cmdext[1]);
} else {
# Requested format / content-type will be an extension on the method
$cmdext = explode('.', $method);
$this->api_method = $cmdext[0];
$this->content_type = strtolower($cmdext[1]);
}
if ($this->requires_auth()) {
if (!isset($this->auth_user)) {
# This header makes basic auth go
header('WWW-Authenticate: Basic realm="StatusNet API"');
# If the user hits cancel -- bam!
$this->show_basic_auth_error();
} else {
$nickname = $this->auth_user;
$password = $this->auth_pw;
$user = common_check_user($nickname, $password);
if ($user) {
$this->user = $user;
$this->process_command();
} else {
# basic authentication failed
list($proxy, $ip) = common_client_ip();
common_log(LOG_WARNING, "Failed API auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip.");
$this->show_basic_auth_error();
}
}
} else {
// Caller might give us a username even if not required
if (isset($this->auth_user)) {
$user = User::staticGet('nickname', $this->auth_user);
if ($user) {
$this->user = $user;
}
# Twitter doesn't throw an error if the user isn't found
}
$this->process_command();
}
}
function process_command()
{
$action = "twitapi$this->api_action";
$actionfile = INSTALLDIR."/actions/$action.php";
if (file_exists($actionfile)) {
require_once($actionfile);
$action_class = ucfirst($action)."Action";
$action_obj = new $action_class();
if (!$action_obj->prepare($this->args)) {
return;
}
if (method_exists($action_obj, $this->api_method)) {
$apidata = array( 'content-type' => $this->content_type,
'api_method' => $this->api_method,
'api_arg' => $this->api_arg,
'user' => $this->user);
call_user_func(array($action_obj, $this->api_method), $_REQUEST, $apidata);
} else {
$this->clientError("API method not found!", $code=404);
}
} else {
$this->clientError("API method not found!", $code=404);
}
}
// Whitelist of API methods that don't need authentication
function requires_auth()
{
static $noauth = array( 'statuses/public_timeline',
'statuses/show',
'users/show',
'help/test',
'help/downtime_schedule',
'statusnet/version',
'statusnet/config',
'statusnet/wadl',
'tags/timeline',
'oembed/oembed',
'groups/show',
'groups/timeline',
'groups/list_all',
'groups/membership',
'groups/is_member',
'groups/timeline');
static $bareauth = array('statuses/user_timeline',
'statuses/friends_timeline',
'statuses/home_timeline',
'statuses/friends',
'statuses/replies',
'statuses/mentions',
'statuses/followers',
'favorites/favorites',
'friendships/show',
'groups/list_groups');
$fullname = "$this->api_action/$this->api_method";
// If the site is "private", all API methods except statusnet/config
// need authentication
if (common_config('site', 'private')) {
return $fullname != 'statusnet/config' || false;
}
// bareauth: only needs auth if without an argument or query param specifying user
if (in_array($fullname, $bareauth)) {
// Special case: friendships/show only needs auth if source_id or
// source_screen_name is not specified as a param
if ($fullname == 'friendships/show') {
$source_id = $this->arg('source_id');
$source_screen_name = $this->arg('source_screen_name');
if (empty($source_id) && empty($source_screen_name)) {
return true;
}
return false;
}
// if all of these are empty, auth is required
$id = $this->arg('id');
$user_id = $this->arg('user_id');
$screen_name = $this->arg('screen_name');
if (empty($this->api_arg) &&
empty($id) &&
empty($user_id) &&
empty($screen_name)) {
return true;
} else {
return false;
}
} else if (in_array($fullname, $noauth)) {
// noauth: never needs auth
return false;
} else {
// everybody else needs auth
return true;
}
}
function basic_auth_process_header()
{
if(isset($_SERVER['AUTHORIZATION']) || isset($_SERVER['HTTP_AUTHORIZATION']))
{
$authorization_header = isset($_SERVER['HTTP_AUTHORIZATION'])?$_SERVER['HTTP_AUTHORIZATION']:$_SERVER['AUTHORIZATION'];
}
if(isset($_SERVER['PHP_AUTH_USER']))
{
$this->auth_user = $_SERVER['PHP_AUTH_USER'];
$this->auth_pw = $_SERVER['PHP_AUTH_PW'];
}
elseif ( isset($authorization_header) && strstr(substr($authorization_header, 0,5),'Basic') )
{
// decode the HTTP_AUTHORIZATION header on php-cgi server self
// on fcgid server the header name is AUTHORIZATION
$auth_hash = base64_decode( substr($authorization_header, 6) );
list($this->auth_user, $this->auth_pw) = explode(':', $auth_hash);
// set all to NULL on a empty basic auth request
if($this->auth_user == "") {
$this->auth_user = NULL;
$this->auth_pw = NULL;
}
}
else
{
$this->auth_user = NULL;
$this->auth_pw = NULL;
}
}
function show_basic_auth_error()
{
header('HTTP/1.1 401 Unauthorized');
$msg = 'Could not authenticate you.';
if ($this->content_type == 'xml') {
header('Content-Type: application/xml; charset=utf-8');
$this->startXML();
$this->elementStart('hash');
$this->element('error', null, $msg);
$this->element('request', null, $_SERVER['REQUEST_URI']);
$this->elementEnd('hash');
$this->endXML();
} else if ($this->content_type == 'json') {
header('Content-Type: application/json; charset=utf-8');
$error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']);
print(json_encode($error_array));
} else {
header('Content-type: text/plain');
print "$msg\n";
}
}
function isReadOnly($args)
{
$apiaction = $args['apiaction'];
$method = $args['method'];
list($cmdtext, $fmt) = explode('.', $method);
static $write_methods = array(
'account' => array('update_location', 'update_delivery_device', 'end_session'),
'blocks' => array('create', 'destroy'),
'direct_messages' => array('create', 'destroy'),
'favorites' => array('create', 'destroy'),
'friendships' => array('create', 'destroy'),
'help' => array(),
'notifications' => array('follow', 'leave'),
'statuses' => array('update', 'destroy'),
'users' => array()
);
if (array_key_exists($apiaction, $write_methods)) {
if (!in_array($cmdtext, $write_methods[$apiaction])) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,112 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Dummy action that emulates Twitter's rate limit status API resource
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* We don't have a rate limit, but some clients check this method.
* It always returns the same thing: 150 hits left.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
{
/**
* Handle the request
*
* Return some Twitter-ish data about API limits
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found.'),
404,
$this->format
);
return;
}
$reset = new DateTime();
$reset->modify('+1 hour');
$this->initDocument($this->format);
if ($this->format == 'xml') {
$this->elementStart('hash');
$this->element('remaining-hits', array('type' => 'integer'), 150);
$this->element('hourly-limit', array('type' => 'integer'), 150);
$this->element(
'reset-time', array('type' => 'datetime'),
common_date_iso8601($reset->format('r'))
);
$this->element(
'reset_time_in_seconds',
array('type' => 'integer'),
strtotime('+1 hour')
);
$this->elementEnd('hash');
} elseif ($this->format == 'json') {
$out = array(
'reset_time_in_seconds' => strtotime('+1 hour'),
'remaining_hits' => 150,
'hourly_limit' => 150,
'reset_time' => common_date_rfc2822(
$reset->format('r')
)
);
print json_encode($out);
}
$this->endDocument($this->format);
}
}

View File

@ -0,0 +1,157 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Update the authenticating user notification channels
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Sets which channel (device) StatusNet delivers updates to for
* the authenticating user. Sending none as the device parameter
* will disable IM and/or SMS updates.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->device = $this->trimmed('device');
return true;
}
/**
* Handle the request
*
* See which request params have been set, and update the user settings
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found.'),
404,
$this->format
);
return;
}
// Note: Twitter no longer supports IM
if (!in_array(strtolower($this->device), array('sms', 'im', 'none'))) {
$this->clientError(
_(
'You must specify a parameter named ' .
'\'device\' with a value of one of: sms, im, none'
)
);
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$original = clone($this->user);
if (strtolower($this->device) == 'sms') {
$this->user->smsnotify = true;
} elseif (strtolower($this->device) == 'im') {
$this->user->jabbernotify = true;
} elseif (strtolower($this->device == 'none')) {
$this->user->smsnotify = false;
$this->user->jabbernotify = false;
}
$result = $this->user->update($original);
if ($result === false) {
common_log_db_error($this->user, 'UPDATE', __FILE__);
$this->serverError(_('Could not update user.'));
return;
}
$profile = $this->user->getProfile();
$twitter_user = $this->twitterUserArray($profile, true);
// Note: this Twitter API method is retarded because it doesn't give
// any success/failure information. Twitter's docs claim that the
// notification field will change to reflect notification choice,
// but that's not true; notification> is used to indicate
// whether the auth user is following the user in question.
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}
}

View File

@ -0,0 +1,166 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Update the authenticating user's profile
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* API analog to the profile settings page
* Only the parameters specified will be updated.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiAccountUpdateProfileAction extends ApiAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->name = $this->trimmed('name');
$this->url = $this->trimmed('url');
$this->location = $this->trimmed('location');
$this->description = $this->trimmed('description');
return true;
}
/**
* Handle the request
*
* See which request params have been set, and update the profile
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found.'),
404,
$this->format
);
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$profile = $this->user->getProfile();
if (empty($profile)) {
$this->clientError(_('User has no profile.'));
return;
}
$original = clone($profile);
if (empty($this->name)) {
$profile->fullname = $this->name;
}
if (empty($this->url)) {
$profile->homepage = $this->url;
}
if (!empty($this->description)) {
$profile->bio = $this->description;
}
if (!empty($this->location)) {
$profile->location = $this->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;
}
}
$result = $profile->update($original);
if (!$result) {
common_log_db_error($profile, 'UPDATE', __FILE__);
$this->serverError(_('Could not save profile.'));
return;
}
common_broadcast_profile($profile);
$twitter_user = $this->twitterUserArray($profile, true);
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}
}

View File

@ -0,0 +1,211 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Update the authenticating user's profile background image
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Update the authenticating user's profile background image
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
{
var $tile = false;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->tile = $this->arg('tile');
return true;
}
/**
* Handle the request
*
* Check whether the credentials are valid and output the result
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found.'),
404,
$this->format
);
return;
}
// Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini
if (empty($_FILES)
&& empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0)
) {
$msg = _('The server was unable to handle that much POST ' .
'data (%s bytes) due to its current configuration.');
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$design = $this->user->getDesign();
// XXX: This is kinda gross, but before we can add a background
// img we have to make sure there's a Design because design ID
// is part of the img filename.
if (empty($design)) {
$this->user->query('BEGIN');
// save new design
$design = new Design();
$id = $design->insert();
if (empty($id)) {
common_log_db_error($id, 'INSERT', __FILE__);
$this->clientError(_('Unable to save your design settings.'));
return;
}
$original = clone($this->user);
$this->user->design_id = $id;
$result = $this->user->update($original);
if (empty($result)) {
common_log_db_error($original, 'UPDATE', __FILE__);
$this->clientError(_('Unable to save your design settings.'));
$this->user->query('ROLLBACK');
return;
}
$this->user->query('COMMIT');
}
// Okay, now get the image and add it to the design
try {
$imagefile = ImageFile::fromUpload('image');
} catch (Exception $e) {
$this->clientError($e->getMessage(), 400, $this->format);
return;
}
$filename = Design::filename(
$design->id,
image_type_to_extension($imagefile->type),
common_timestamp()
);
$filepath = Design::path($filename);
move_uploaded_file($imagefile->filepath, $filepath);
// delete any old backround img laying around
if (isset($design->backgroundimage)) {
@unlink(Design::path($design->backgroundimage));
}
$original = clone($design);
$design->backgroundimage = $filename;
$design->setDisposition(true, false, ($this->tile == 'true'));
$result = $design->update($original);
if ($result === false) {
common_log_db_error($design, 'UPDATE', __FILE__);
$this->showForm(_('Could not update your design.'));
return;
}
$profile = $this->user->getProfile();
if (empty($profile)) {
$this->clientError(_('User has no profile.'));
return;
}
$twitter_user = $this->twitterUserArray($profile, true);
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}
}

View File

@ -0,0 +1,246 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Update a user's design colors
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Sets one or more hex values that control the color scheme of the
* authenticating user's design
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
{
var $profile_background_color = null;
var $profile_text_color = null;
var $profile_link_color = null;
var $profile_sidebar_fill_color = null;
var $profile_sidebar_border_color = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->profile_background_color
= $this->trimmed('profile_background_color');
$this->profile_text_color
= $this->trimmed('profile_text_color');
$this->profile_link_color
= $this->trimmed('profile_link_color');
$this->profile_sidebar_fill_color
= $this->trimmed('profile_sidebar_fill_color');
// XXX: we don't support changing the sidebar border color
// in our designs.
$this->profile_sidebar_border_color
= $this->trimmed('profile_sidebar_border_color');
// XXX: Unlike Twitter, we do allow people to change the 'content color'
$this->profile_content_color = $this->trimmed('profile_content_color');
return true;
}
/**
* Handle the request
*
* Try to save the user's colors in her design. Create a new design
* if the user doesn't already have one.
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found.'),
404,
$this->format
);
return;
}
$design = $this->user->getDesign();
if (!empty($design)) {
$original = clone($design);
try {
$this->setColors($design);
} catch (WebColorException $e) {
$this->clientError($e->getMessage());
return false;
}
$result = $design->update($original);
if ($result === false) {
common_log_db_error($design, 'UPDATE', __FILE__);
$this->clientError(_('Could not update your design.'));
return;
}
} else {
$this->user->query('BEGIN');
// save new design
$design = new Design();
try {
$this->setColors($design);
} catch (WebColorException $e) {
$this->clientError($e->getMessage());
return false;
}
$id = $design->insert();
if (empty($id)) {
common_log_db_error($id, 'INSERT', __FILE__);
$this->clientError(_('Unable to save your design settings.'));
return;
}
$original = clone($this->user);
$this->user->design_id = $id;
$result = $this->user->update($original);
if (empty($result)) {
common_log_db_error($original, 'UPDATE', __FILE__);
$this->clientError(_('Unable to save your design settings.'));
$this->user->query('ROLLBACK');
return;
}
$this->user->query('COMMIT');
}
$profile = $this->user->getProfile();
if (empty($profile)) {
$this->clientError(_('User has no profile.'));
return;
}
$twitter_user = $this->twitterUserArray($profile, true);
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}
/**
* Sets the user's design colors based on the request parameters
*
* @param Design $design the user's Design
*
* @return void
*/
function setColors($design)
{
$bgcolor = empty($this->profile_background_color) ?
null : new WebColor($this->profile_background_color);
$tcolor = empty($this->profile_text_color) ?
null : new WebColor($this->profile_text_color);
$sbcolor = empty($this->profile_sidebar_fill_color) ?
null : new WebColor($this->profile_sidebar_fill_color);
$lcolor = empty($this->profile_link_color) ?
null : new WebColor($this->profile_link_color);
$ccolor = empty($this->profile_content_color) ?
null : new WebColor($this->profile_content_color);
if (!empty($bgcolor)) {
$design->backgroundcolor = $bgcolor->intValue();
}
if (!empty($ccolor)) {
$design->contentcolor = $ccolor->intValue();
}
if (!empty($sbcolor)) {
$design->sidebarcolor = $sbcolor->intValue();
}
if (!empty($tcolor)) {
$design->textcolor = $tcolor->intValue();
}
if (!empty($lcolor)) {
$design->linkcolor = $lcolor->intValue();
}
return true;
}
}

View File

@ -0,0 +1,151 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Update the authenticating user's profile image
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Updates the authenticating user's profile image. Note that this API method
* expects raw multipart data, not a URL to an image.
*
* @category API
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiAccountUpdateProfileImageAction extends ApiAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
return true;
}
/**
* Handle the request
*
* Check whether the credentials are valid and output the result
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
}
// Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini
if (empty($_FILES)
&& empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0)
) {
$msg = _('The server was unable to handle that much POST ' .
'data (%s bytes) due to its current configuration.');
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
try {
$imagefile = ImageFile::fromUpload('image');
} catch (Exception $e) {
$this->clientError($e->getMessage(), 400, $this->format);
return;
}
$filename = Avatar::filename(
$user->id,
image_type_to_extension($imagefile->type),
null,
'tmp'.common_timestamp()
);
$filepath = Avatar::path($filename);
move_uploaded_file($imagefile->filepath, $filepath);
$profile = $this->user->getProfile();
if (empty($profile)) {
$this->clientError(_('User has no profile.'));
return;
}
$profile->setOriginal($filename);
common_broadcast_profile($profile);
$twitter_user = $this->twitterUserArray($profile, true);
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}
}

View File

@ -0,0 +1,85 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Test if supplied user credentials are valid.
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Check a user's credentials. Returns an HTTP 200 OK response code and a
* representation of the requesting user if authentication was successful;
* returns a 401 status code and an error message if not.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiAccountVerifyCredentialsAction extends ApiAuthAction
{
/**
* Handle the request
*
* Check whether the credentials are valid and output the result
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
switch ($this->format) {
case 'xml':
case 'json':
$args['id'] = $this->auth_user->id;
$action_obj = new ApiUserShowAction();
if ($action_obj->prepare($args)) {
$action_obj->handle($args);
}
break;
default:
header('Content-Type: text/html; charset=utf-8');
print 'Authorized';
}
}
}

114
actions/apiblockcreate.php Normal file
View File

@ -0,0 +1,114 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Block a user via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Blocks the user specified in the ID parameter as the authenticating user.
* Destroys a friendship to the blocked user if it exists. Returns the
* blocked user in the requested format when successful.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiBlockCreateAction extends ApiAuthAction
{
var $other = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->other = $this->getTargetUser($this->arg('id'));
return true;
}
/**
* Handle the request
*
* Save the new message
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (empty($this->user) || empty($this->other)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
if ($this->user->hasBlocked($this->other)
|| $this->user->block($this->other)
) {
$this->initDocument($this->format);
$this->showProfile($this->other, $this->format);
$this->endDocument($this->format);
} else {
$this->serverError(_('Block user failed.'), 500, $this->format);
}
}
}

113
actions/apiblockdestroy.php Normal file
View File

@ -0,0 +1,113 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Un-block a user via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Un-blocks the user specified in the ID parameter for the authenticating user.
* Returns the un-blocked user in the requested format when successful.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiBlockDestroyAction extends ApiAuthAction
{
var $other = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->other = $this->getTargetUser($this->arg('id'));
return true;
}
/**
* Handle the request
*
* Save the new message
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (empty($this->user) || empty($this->other)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
if (!$this->user->hasBlocked($this->other)
|| $this->user->unblock($this->other)
) {
$this->initDocument($this->format);
$this->showProfile($this->other, $this->format);
$this->endDocument($this->format);
} else {
$this->serverError(_('Unblock user failed.'));
}
}
}

View File

@ -0,0 +1,375 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a the direct messages from or to a user
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Adrian Lang <mail@adrianlang.de>
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Show a list of direct messages from or to the authenticating user
*
* @category API
* @package StatusNet
* @author Adrian Lang <mail@adrianlang.de>
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiDirectMessageAction extends ApiAuthAction
{
var $messages = null;
var $title = null;
var $subtitle = null;
var $link = null;
var $selfuri_base = null;
var $id = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$server = common_root_url();
$taguribase = common_config('integration', 'taguri');
if ($this->arg('sent')) {
// Action was called by /api/direct_messages/sent.format
$this->title = sprintf(
_("Direct messages from %s"),
$this->user->nickname
);
$this->subtitle = sprintf(
_("All the direct messages sent from %s"),
$this->user->nickname
);
$this->link = $server . $this->user->nickname . '/outbox';
$this->selfuri_base = common_root_url() . 'api/direct_messages/sent';
$this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id;
} else {
$this->title = sprintf(
_("Direct messages to %s"),
$this->user->nickname
);
$this->subtitle = sprintf(
_("All the direct messages sent to %s"),
$this->user->nickname
);
$this->link = $server . $this->user->nickname . '/inbox';
$this->selfuri_base = common_root_url() . 'api/direct_messages';
$this->id = "tag:$taguribase:DirectMessages:" . $this->user->id;
}
$this->messages = $this->getMessages();
return true;
}
/**
* Handle the request
*
* Show the messages
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$this->showMessages();
}
/**
* Show the messages
*
* @return void
*/
function showMessages()
{
switch($this->format) {
case 'xml':
$this->showXmlDirectMessages();
break;
case 'rss':
$this->showRssDirectMessages();
break;
case 'atom':
$this->showAtomDirectMessages();
break;
case 'json':
$this->showJsonDirectMessages();
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
break;
}
}
/**
* Get notices
*
* @return array notices
*/
function getMessages()
{
$message = new Message();
if ($this->arg('sent')) {
$message->from_profile = $this->user->id;
} else {
$message->to_profile = $this->user->id;
}
if (!empty($this->max_id)) {
$message->whereAdd('id <= ' . $this->max_id);
}
if (!empty($this->since_id)) {
$message->whereAdd('id > ' . $this->since_id);
}
if (!empty($since)) {
$d = date('Y-m-d H:i:s', $this->since);
$message->whereAdd("created > '$d'");
}
$message->orderBy('created DESC, id DESC');
$message->limit((($this->page - 1) * $this->count), $this->count);
$message->find();
$messages = array();
while ($message->fetch()) {
$messages[] = clone($message);
}
return $messages;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this notice last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->messages)) {
return strtotime($this->messages[0]->created);
}
return null;
}
/**
* Shows a list of direct messages as Twitter-style XML array
*
* @return void
*/
function showXmlDirectMessages()
{
$this->initDocument('xml');
$this->elementStart('direct-messages', array('type' => 'array'));
foreach ($this->messages as $m) {
$dm_array = $this->directMessageArray($m);
$this->showXmlDirectMessage($dm_array);
}
$this->elementEnd('direct-messages');
$this->endDocument('xml');
}
/**
* Shows a list of direct messages as a JSON encoded array
*
* @return void
*/
function showJsonDirectMessages()
{
$this->initDocument('json');
$dmsgs = array();
foreach ($this->messages as $m) {
$dm_array = $this->directMessageArray($m);
array_push($dmsgs, $dm_array);
}
$this->showJsonObjects($dmsgs);
$this->endDocument('json');
}
/**
* Shows a list of direct messages as RSS items
*
* @return void
*/
function showRssDirectMessages()
{
$this->initDocument('rss');
$this->element('title', null, $this->title);
$this->element('link', null, $this->link);
$this->element('description', null, $this->subtitle);
$this->element('language', null, 'en-us');
$this->element(
'atom:link',
array(
'type' => 'application/rss+xml',
'href' => $this->selfuri_base . '.rss',
'rel' => self
),
null
);
$this->element('ttl', null, '40');
foreach ($this->messages as $m) {
$entry = $this->rssDirectMessageArray($m);
$this->showTwitterRssItem($entry);
}
$this->endTwitterRss();
}
/**
* Shows a list of direct messages as Atom entries
*
* @return void
*/
function showAtomDirectMessages()
{
$this->initDocument('atom');
$this->element('title', null, $this->title);
$this->element('id', null, $this->id);
$selfuri = common_root_url() . 'api/direct_messages.atom';
$this->element(
'link', array(
'href' => $this->link,
'rel' => 'alternate',
'type' => 'text/html'),
null
);
$this->element(
'link', array(
'href' => $this->selfuri_base . '.atom', 'rel' => 'self',
'type' => 'application/atom+xml'),
null
);
$this->element('updated', null, common_date_iso8601('now'));
$this->element('subtitle', null, $this->subtitle);
foreach ($this->messages as $m) {
$entry = $this->rssDirectMessageArray($m);
$this->showTwitterAtomEntry($entry);
}
$this->endDocument('atom');
}
/**
* An entity tag for this notice
*
* Returns an Etag based on the action name, language, and
* timestamps of the notice
*
* @return string etag
*/
function etag()
{
if (!empty($this->messages)) {
$last = count($this->messages) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
strtotime($this->messages[0]->created),
strtotime($this->messages[$last]->created)
)
)
. '"';
}
return null;
}
}

View File

@ -0,0 +1,188 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Send a direct message via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Adrian Lang <mail@adrianlang.de>
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Creates a new direct message from the authenticating user to
* the user specified by id.
*
* @category API
* @package StatusNet
* @author Adrian Lang <mail@adrianlang.de>
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiDirectMessageNewAction extends ApiAuthAction
{
var $source = null;
var $other = null;
var $content = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$this->source = $this->trimmed('source'); // Not supported by Twitter.
$reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
if (empty($thtis->source) || in_array($this->source, $reserved_sources)) {
$source = 'api';
}
$this->content = $this->trimmed('text');
$this->user = $this->auth_user;
$user_param = $this->trimmed('user');
$user_id = $this->arg('user_id');
$screen_name = $this->trimmed('screen_name');
if (isset($user_param) || isset($user_id) || isset($screen_name)) {
$this->other = $this->getTargetUser($user_param);
}
return true;
}
/**
* Handle the request
*
* Save the new message
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (empty($this->content)) {
$this->clientError(
_('No message text!'),
406,
$this->format
);
} else {
$content_shortened = common_shorten_links($this->content);
if (Message::contentTooLong($content_shortened)) {
$this->clientError(
sprintf(
_('That\'s too long. Max message size is %d chars.'),
Message::maxContent()
),
406,
$this->format
);
return;
}
}
if (empty($this->other)) {
$this->clientError(_('Recipient user not found.'), 403, $this->format);
return;
} else if (!$this->user->mutuallySubscribed($this->other)) {
$this->clientError(
_('Can\'t send direct messages to users who aren\'t your friend.'),
403,
$this->format
);
return;
} else if ($this->user->id == $this->other->id) {
// Note: sending msgs to yourself is allowed by Twitter
$errmsg = 'Don\'t send a message to yourself; ' .
'just say it to yourself quietly instead.';
$this->clientError(_($errmsg), 403, $this->format);
return;
}
$message = Message::saveNew(
$this->user->id,
$this->other->id,
html_entity_decode($this->content, ENT_NOQUOTES, 'UTF-8'),
$this->source
);
if (is_string($message)) {
$this->serverError($message);
return;
}
mail_notify_message($message, $this->user, $this->other);
if ($this->format == 'xml') {
$this->showSingleXmlDirectMessage($message);
} elseif ($this->format == 'json') {
$this->showSingleJsondirectMessage($message);
}
}
}

View File

@ -0,0 +1,168 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Add a notice to a user's list of favorite notices via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Favorites the status specified in the ID parameter as the authenticating user.
* Returns the favorite status when successful.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiFavoriteCreateAction extends ApiAuthAction
{
var $notice = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->notice = Notice::staticGet($this->arg('id'));
return true;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found!'),
404,
$this->format
);
return;
}
if (empty($this->notice)) {
$this->clientError(
_('No status found with that ID.'),
404,
$this->format
);
return;
}
// Note: Twitter lets you fave things repeatedly via API.
if ($this->user->hasFave($this->notice)) {
$this->clientError(
_('This status is already a favorite!'),
403,
$this->format
);
return;
}
$fave = Fave::addNew($this->user, $this->notice);
if (empty($fave)) {
$this->clientError(
_('Could not create favorite.'),
403,
$this->format
);
return;
}
$this->notify($fave, $this->notice, $this->user);
$this->user->blowFavesCache();
if ($this->format == 'xml') {
$this->showSingleXmlStatus($this->notice);
} elseif ($this->format == 'json') {
$this->show_single_json_status($this->notice);
}
}
/**
* Notify the author of the favorite that the user likes their notice
*
* @param Favorite $fave the favorite in question
* @param Notice $notice the notice that's been faved
* @param User $user the user doing the favoriting
*
* @return void
*/
function notify($fave, $notice, $user)
{
$other = User::staticGet('id', $notice->profile_id);
if ($other && $other->id != $user->id) {
if ($other->email && $other->emailnotifyfav) {
mail_notify_fave($other, $user, $notice);
}
// XXX: notify by IM
// XXX: notify by SMS
}
}
}

View File

@ -0,0 +1,150 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Remote a notice from a user's list of favorite notices via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Un-favorites the status specified in the ID parameter as the authenticating user.
* Returns the un-favorited status in the requested format when successful.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiFavoriteDestroyAction extends ApiAuthAction
{
var $notice = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->notice = Notice::staticGet($this->arg('id'));
return true;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found!'),
404,
$this->format
);
return;
}
if (empty($this->notice)) {
$this->clientError(
_('No status found with that ID.'),
404,
$this->format
);
return;
}
$fave = new Fave();
$fave->user_id = $this->user->id;
$fave->notice_id = $this->notice->id;
if (!$fave->find(true)) {
$this->clientError(
_('That status is not a favorite!'),
403,
$this->favorite
);
return;
}
$result = $fave->delete();
if (!$result) {
common_log_db_error($fave, 'DELETE', __FILE__);
$this->clientError(
_('Could not delete favorite.'),
404,
$this->format
);
return;
}
$this->user->blowFavesCache();
if ($this->format == 'xml') {
$this->showSingleXmlStatus($this->notice);
} elseif ($this->format == 'json') {
$this->show_single_json_status($this->notice);
}
}
}

View File

@ -0,0 +1,137 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Subscribe to a user via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Allows the authenticating users to follow (subscribe) the user specified in
* the ID parameter. Returns the befriended user in the requested format when
* successful. Returns a string describing the failure condition when unsuccessful.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiFriendshipsCreateAction extends ApiAuthAction
{
var $other = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->other = $this->getTargetUser($id);
return true;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found!'),
404,
$this->format
);
return;
}
if (empty($this->other)) {
$this->clientError(
_('Could not follow user: User not found.'),
403,
$this->format
);
return;
}
if ($this->user->isSubscribed($this->other)) {
$errmsg = sprintf(
_('Could not follow user: %s is already on your list.'),
$this->other->nickname
);
$this->clientError($errmsg, 403, $this->format);
return;
}
$result = subs_subscribe_to($this->user, $this->other);
if (is_string($result)) {
$this->clientError($result, 403, $this->format);
return;
}
$this->initDocument($this->format);
$this->showProfile($this->other, $this->format);
$this->endDocument($this->format);
}
}

View File

@ -0,0 +1,139 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Unsubscribe to a user via API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Allows the authenticating users to unfollow (unsubscribe) the user specified in
* the ID parameter. Returns the unfollowed user in the requested format when
* successful. Returns a string describing the failure condition when unsuccessful.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiFriendshipsDestroyAction extends ApiAuthAction
{
var $other = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->other = $this->getTargetUser($id);
return true;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
_('API method not found!'),
404,
$this->format
);
return;
}
if (empty($this->other)) {
$this->clientError(
_('Could not unfollow user: User not found.'),
403,
$this->format
);
return;
}
// Don't allow unsubscribing from yourself!
if ($this->user->id == $this->other->id) {
$this->clientError(
_("You cannot unfollow yourself!"),
403,
$this->format
);
return;
}
$result = subs_unsubscribe_user($this->user, $this->other->nickname);
if (is_string($result)) {
$this->clientError($result, 403, $this->format);
return;
}
$this->initDocument($this->format);
$this->showProfile($this->other, $this->format);
$this->endDocument($this->format);
}
}

View File

@ -0,0 +1,119 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show whether there is a friendship between two users
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Tests for the existence of friendship between two users. Will return true if
* user_a follows user_b, otherwise will return false.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
{
var $user_a = null;
var $user_b = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$user_a_id = $this->trimmed('user_a');
$user_b_id = $this->trimmed('user_b');
$this->user_a = $this->getTargetUser($user_a_id);
$this->user_b = $this->getTargetUser($user_b_id);
return true;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (empty($this->user_a) || empty($this->user_b)) {
$this->clientError(
_('Two user ids or screen_names must be supplied.'),
400,
$this->format
);
return;
}
$result = $this->user_a->isSubscribed($this->user_b);
switch ($this->format) {
case 'xml':
$this->initDocument('xml');
$this->element('friends', null, $result);
$this->endDocument('xml');
break;
case 'json':
$this->initDocument('json');
print json_encode($result);
$this->endDocument('json');
break;
default:
break;
}
}
}

View File

@ -0,0 +1,168 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show information about the relationship between two users
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* Outputs detailed information about the relationship between two users
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiFriendshipsShowAction extends ApiBareAuthAction
{
var $source = null;
var $target = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$source_id = (int)$this->trimmed('source_id');
$source_screen_name = $this->trimmed('source_screen_name');
$target_id = (int)$this->trimmed('target_id');
$target_screen_name = $this->trimmed('target_screen_name');
if (!empty($source_id)) {
$this->source = User::staticGet($source_id);
} elseif (!empty($source_screen_name)) {
$this->source = User::staticGet('nickname', $source_screen_name);
} else {
$this->source = $this->auth_user;
}
if (!empty($target_id)) {
$this->target = User::staticGet($target_id);
} elseif (!empty($target_screen_name)) {
$this->target = User::staticGet('nickname', $target_screen_name);
}
return true;
}
/**
* Determines whether this API resource requires auth. Overloaded to look
* return true in case source_id and source_screen_name are both empty
*
* @return boolean true or false
*/
function requiresAuth()
{
if (common_config('site', 'private')) {
return true;
}
$source_id = $this->trimmed('source_id');
$source_screen_name = $this->trimmed('source_screen_name');
if (empty($source_id) && empty($source_screen_name)) {
return true;
}
return false;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(_('API method not found!'), 404);
return;
}
if (empty($this->source)) {
$this->clientError(
_('Could not determine source user.'),
404
);
return;
}
if (empty($this->target)) {
$this->clientError(
_('Could not find target user.'),
404
);
return;
}
$result = $this->twitterRelationshipArray($this->source, $this->target);
switch ($this->format) {
case 'xml':
$this->initDocument('xml');
$this->showTwitterXmlRelationship($result[relationship]);
$this->endDocument('xml');
break;
case 'json':
$this->initDocument('json');
print json_encode($result);
$this->endDocument('json');
break;
default:
break;
}
}
}

324
actions/apigroupcreate.php Normal file
View File

@ -0,0 +1,324 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Create a group via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Make a new group. Sets the authenticated user as the administrator of the group.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiGroupCreateAction extends ApiAuthAction
{
var $group = null;
var $nickname = null;
var $fullname = null;
var $homepage = null;
var $description = null;
var $location = null;
var $aliasstring = null;
var $aliases = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->nickname = $this->arg('nickname');
$this->fullname = $this->arg('full_name');
$this->homepage = $this->arg('homepage');
$this->description = $this->arg('description');
$this->location = $this->arg('location');
$this->aliasstring = $this->arg('aliases');
return true;
}
/**
* Handle the request
*
* Save the new group
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
if ($this->validateParams() == false) {
return;
}
$group = User_group::register(array('nickname' => $this->nickname,
'fullname' => $this->fullname,
'homepage' => $this->homepage,
'description' => $this->description,
'location' => $this->location,
'aliases' => $this->aliases,
'userid' => $this->user->id));
switch($this->format) {
case 'xml':
$this->showSingleXmlGroup($group);
break;
case 'json':
$this->showSingleJsonGroup($group);
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
/**
* Validate params for the new group
*
* @return void
*/
function validateParams()
{
$valid = Validate::string(
$this->nickname, array(
'min_length' => 1,
'max_length' => 64,
'format' => NICKNAME_FMT
)
);
if (!$valid) {
$this->clientError(
_(
'Nickname must have only lowercase letters ' .
'and numbers and no spaces.'
),
403,
$this->format
);
return false;
} elseif ($this->groupNicknameExists($this->nickname)) {
$this->clientError(
_('Nickname already in use. Try another one.'),
403,
$this->format
);
return false;
} else if (!User_group::allowedNickname($this->nickname)) {
$this->clientError(
_('Not a valid nickname.'),
403,
$this->format
);
return false;
} elseif (
!is_null($this->homepage)
&& strlen($this->homepage) > 0
&& !Validate::uri(
$this->homepage, array(
'allowed_schemes' =>
array('http', 'https')
)
)) {
$this->clientError(
_('Homepage is not a valid URL.'),
403,
$this->format
);
return false;
} elseif (
!is_null($this->fullname)
&& mb_strlen($this->fullname) > 255) {
$this->clientError(
_('Full name is too long (max 255 chars).'),
403,
$this->format
);
return false;
} elseif (User_group::descriptionTooLong($this->description)) {
$this->clientError(
sprintf(
_('Description is too long (max %d chars).'),
User_group::maxDescription()
),
403,
$this->format
);
return false;
} elseif (
!is_null($this->location)
&& mb_strlen($this->location) > 255) {
$this->clientError(
_('Location is too long (max 255 chars).'),
403,
$this->format
);
return false;
}
if (!empty($this->aliasstring)) {
$this->aliases = array_map(
'common_canonical_nickname',
array_unique(preg_split('/[\s,]+/', $this->aliasstring))
);
} else {
$this->aliases = array();
}
if (count($this->aliases) > common_config('group', 'maxaliases')) {
$this->clientError(
sprintf(
_('Too many aliases! Maximum %d.'),
common_config('group', 'maxaliases')
),
403,
$this->format
);
return false;
}
foreach ($this->aliases as $alias) {
$valid = Validate::string(
$alias, array(
'min_length' => 1,
'max_length' => 64,
'format' => NICKNAME_FMT
)
);
if (!$valid) {
$this->clientError(
sprintf(_('Invalid alias: "%s"'), $alias),
403,
$this->format
);
return false;
}
if ($this->groupNicknameExists($alias)) {
$this->clientError(
sprintf(
_('Alias "%s" already in use. Try another one.'),
$alias
),
403,
$this->format
);
return false;
}
// XXX assumes alphanum nicknames
if (strcmp($alias, $this->nickname) == 0) {
$this->clientError(
_('Alias can\'t be the same as nickname.'),
403,
$this->format
);
return false;
}
}
// Evarything looks OK
return true;
}
/**
* Check to see whether a nickname is already in use by a group
*
* @param String $nickname The nickname in question
*
* @return boolean true or false
*/
function groupNicknameExists($nickname)
{
$group = User_group::staticGet('nickname', $nickname);
if (!empty($group)) {
return true;
}
$alias = Group_alias::staticGet('alias', $nickname);
if (!empty($alias)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,122 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Check to see whether a user a member of a group
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* Returns whether a user is a member of a specified group.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiGroupIsMemberAction extends ApiBareAuthAction
{
var $group = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->getTargetUser(null);
$this->group = $this->getTargetGroup(null);
return true;
}
/**
* Handle the request
*
* Save the new message
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
if (empty($this->group)) {
$this->clientError(_('Group not found!'), 404, $this->format);
return false;
}
$is_member = $this->user->isMember($this->group);
switch($this->format) {
case 'xml':
$this->initDocument('xml');
$this->element('is_member', null, $is_member);
$this->endDocument('xml');
break;
case 'json':
$this->initDocument('json');
$this->showJsonObjects(array('is_member' => $is_member));
$this->endDocument('json');
break;
default:
$this->clientError(
_('API method not found!'),
400,
$this->format
);
break;
}
}
}

163
actions/apigroupjoin.php Normal file
View File

@ -0,0 +1,163 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Join a group via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Joins the authenticated user to the group speicified by ID
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiGroupJoinAction extends ApiAuthAction
{
var $group = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->group = $this->getTargetGroup($this->arg('id'));
return true;
}
/**
* Handle the request
*
* Save the new message
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
if (empty($this->group)) {
$this->clientError(_('Group not found!'), 404, $this->format);
return false;
}
if ($this->user->isMember($this->group)) {
$this->clientError(
_('You are already a member of that group.'),
403,
$this->format
);
return;
}
if (Group_block::isBlocked($this->group, $this->user->getProfile())) {
$this->clientError(
_('You have been blocked from that group by the admin.'),
403,
$this->format
);
return;
}
$member = new Group_member();
$member->group_id = $this->group->id;
$member->profile_id = $this->user->id;
$member->created = common_sql_now();
$result = $member->insert();
if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__);
$this->serverError(
sprintf(
_('Could not join user %s to group %s.'),
$this->user->nickname,
$this->group->nickname
)
);
return;
}
switch($this->format) {
case 'xml':
$this->show_single_xml_group($this->group);
break;
case 'json':
$this->showSingleJsonGroup($this->group);
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
}

149
actions/apigroupleave.php Normal file
View File

@ -0,0 +1,149 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Leave a group via the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Removes the authenticated user from the group specified by ID
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiGroupLeaveAction extends ApiAuthAction
{
var $group = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->group = $this->getTargetGroup($this->arg('id'));
return true;
}
/**
* Handle the request
*
* Save the new message
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400,
$this->format
);
return;
}
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
if (empty($this->group)) {
$this->clientError(_('Group not found!'), 404, $this->format);
return false;
}
$member = new Group_member();
$member->group_id = $this->group->id;
$member->profile_id = $this->auth->id;
if (!$member->find(true)) {
$this->serverError(_('You are not a member of this group.'));
return;
}
$result = $member->delete();
if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__);
$this->serverError(
sprintf(
_('Could not remove user %s to group %s.'),
$this->user->nickname,
$this->$group->nickname
)
);
return;
}
switch($this->format) {
case 'xml':
$this->show_single_xml_group($this->group);
break;
case 'json':
$this->showSingleJsonGroup($this->group);
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
}

223
actions/apigrouplist.php Normal file
View File

@ -0,0 +1,223 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Check to see whether a user a member of a group
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* Returns whether a user is a member of a specified group.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiGroupListAction extends ApiBareAuthAction
{
var $groups = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->getTargetUser($id);
$this->groups = $this->getGroups();
return true;
}
/**
* Handle the request
*
* Show the user's groups
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$sitename = common_config('site', 'name');
$title = sprintf(_("%s's groups"), $this->user->nickname);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:Groups";
$link = common_local_url(
'usergroups',
array('nickname' => $this->user->nickname)
);
$subtitle = sprintf(
_("Groups %s is a member of on %s."),
$this->user->nickname,
$sitename
);
switch($this->format) {
case 'xml':
$this->showXmlGroups($this->groups);
break;
case 'rss':
$this->showRssGroups($this->groups, $title, $link, $subtitle);
break;
case 'atom':
$selfuri = common_root_url() . 'api/statusnet/groups/list/' .
$this->user->id . '.atom';
$this->showAtomGroups(
$this->groups,
$title,
$id,
$link,
$subtitle,
$selfuri
);
break;
case 'json':
$this->showJsonGroups($this->groups);
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
/**
* Get groups
*
* @return array groups
*/
function getGroups()
{
$groups = array();
$group = $this->user->getGroups(
($this->page - 1) * $this->count,
$this->count,
$this->since_id,
$this->max_id,
$this->since
);
while ($group->fetch()) {
$groups[] = clone($group);
}
return $groups;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest group the user has joined
*/
function lastModified()
{
if (!empty($this->groups) && (count($this->groups) > 0)) {
return strtotime($this->groups[0]->created);
}
return null;
}
/**
* An entity tag for this list of groups
*
* Returns an Etag based on the action name, language, user ID and
* timestamps of the first and last group the user has joined
*
* @return string etag
*/
function etag()
{
if (!empty($this->groups) && (count($this->groups) > 0)) {
$last = count($this->groups) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->user->id,
strtotime($this->groups[0]->created),
strtotime($this->groups[$last]->created))
)
. '"';
}
return null;
}
}

208
actions/apigrouplistall.php Normal file
View File

@ -0,0 +1,208 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show the newest groups
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns of the lastest 20 groups for the site
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiGroupListAllAction extends ApiPrivateAuthAction
{
var $groups = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->getTargetUser($id);
$this->groups = $this->getGroups();
return true;
}
/**
* Handle the request
*
* Show the user's groups
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$sitename = common_config('site', 'name');
$title = sprintf(_("%s groups"), $sitename);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:Groups";
$link = common_local_url('groups');
$subtitle = sprintf(_("groups on %s"), $sitename);
switch($this->format) {
case 'xml':
$this->showXmlGroups($this->groups);
break;
case 'rss':
$this->showRssGroups($this->groups, $title, $link, $subtitle);
break;
case 'atom':
$selfuri = common_root_url() .
'api/statusnet/groups/list_all.atom';
$this->showAtomGroups(
$this->groups,
$title,
$id,
$link,
$subtitle,
$selfuri
);
break;
case 'json':
$this->showJsonGroups($this->groups);
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
/**
* Get groups
*
* @return array groups
*/
function getGroups()
{
$groups = array();
// XXX: Use the $page, $count, $max_id, $since_id, and $since parameters
$group = new User_group();
$group->orderBy('created DESC');
$group->find();
while ($group->fetch()) {
$groups[] = clone($group);
}
return $groups;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the site's latest group
*/
function lastModified()
{
if (!empty($this->groups) && (count($this->groups) > 0)) {
return strtotime($this->groups[0]->created);
}
return null;
}
/**
* An entity tag for this list of groups
*
* Returns an Etag based on the action name, language, and
* timestamps of the first and last group the user has joined
*
* @return string etag
*/
function etag()
{
if (!empty($this->groups) && (count($this->groups) > 0)) {
$last = count($this->groups) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
strtotime($this->groups[0]->created),
strtotime($this->groups[$last]->created))
)
. '"';
}
return null;
}
}

View File

@ -0,0 +1,197 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* List a group's members
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* List 20 newest members of the group specified by name or ID.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiGroupMembershipAction extends ApiPrivateAuthAction
{
var $group = null;
var $profiles = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->group = $this->getTargetGroup($this->arg('id'));
$this->profiles = $this->getProfiles();
return true;
}
/**
* Handle the request
*
* Show the members of the group
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (empty($this->group)) {
$this->clientError(_('Group not found!'), 404, $this->format);
return false;
}
// XXX: RSS and Atom
switch($this->format) {
case 'xml':
$this->showTwitterXmlUsers($this->profiles);
break;
case 'json':
$this->showJsonUsers($this->profiles);
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
/**
* Fetch the members of a group
*
* @return array $profiles list of profiles
*/
function getProfiles()
{
$profiles = array();
$profile = $this->group->getMembers(
($this->page - 1) * $this->count,
$this->count,
$this->since_id,
$this->max_id,
$this->since
);
while ($profile->fetch()) {
$profiles[] = clone($profile);
}
return $profiles;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this list of profiles last modified?
*
* @return string datestamp of the lastest profile in the group
*/
function lastModified()
{
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
return strtotime($this->profiles[0]->created);
}
return null;
}
/**
* An entity tag for this list of groups
*
* Returns an Etag based on the action name, language
* the group id, and timestamps of the first and last
* user who has joined the group
*
* @return string etag
*/
function etag()
{
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
$last = count($this->profiles) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->group->id,
strtotime($this->profiles[0]->created),
strtotime($this->profiles[$last]->created))
)
. '"';
}
return null;
}
}

152
actions/apigroupshow.php Normal file
View File

@ -0,0 +1,152 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show information about a group
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Outputs detailed information about the group specified by ID
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiGroupShowAction extends ApiPrivateAuthAction
{
var $group = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->group = $this->getTargetGroup($this->arg('id'));
return true;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (empty($this->group)) {
$this->clientError(
_('Group not found!'),
404,
$this->format
);
return;
}
switch($this->format) {
case 'xml':
$this->show_single_xml_group($this->group);
break;
case 'json':
$this->showSingleJsonGroup($this->group);
break;
default:
$this->clientError(_('API method not found!'), 404, $this->format);
break;
}
}
/**
* When was this group last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->group)) {
return strtotime($this->group->modified);
}
return null;
}
/**
* An entity tag for this group
*
* Returns an Etag based on the action name, language, and
* timestamps of the notice
*
* @return string etag
*/
function etag()
{
if (!empty($this->group)) {
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->group->id,
strtotime($this->group->modified))
)
. '"';
}
return null;
}
}

96
actions/apihelptest.php Normal file
View File

@ -0,0 +1,96 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Test that you can connect to the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiHelpTestAction extends ApiPrivateAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
return true;
}
/**
* Handle the request
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->element('ok', null, 'true');
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
print '"ok"';
$this->endDocument('json');
} else {
$this->clientError(
_('API method not found!'),
404,
$this->format
);
}
}
}

View File

@ -0,0 +1,154 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Destroy a notice through the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Tom Blankenship <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Deletes one of the authenticating user's statuses (notices).
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Tom Blankenship <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiStatusesDestroyAction extends ApiAuthAction
{
var $status = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->notice_id = (int)$this->trimmed('id');
if (empty($notice_id)) {
$this->notice_id = (int)$this->arg('id');
}
$this->notice = Notice::staticGet((int)$this->notice_id);
return true;
}
/**
* Handle the request
*
* Delete the notice and all related replies
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(_('API method not found!'), $code = 404);
return;
}
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
$this->clientError(_('This method requires a POST or DELETE.'),
400, $this->format);
return;
}
if (empty($this->notice)) {
$this->clientError(_('No status found with that ID.'),
404, $this->format);
return;
}
if ($this->user->id == $this->notice->profile_id) {
$replies = new Reply;
$replies->get('notice_id', $this->notice_id);
$replies->delete();
$this->notice->delete();
if ($this->format == 'xml') {
$this->showSingleXmlStatus($this->notice);
} elseif ($this->format == 'json') {
$this->show_single_json_status($this->notice);
}
} else {
$this->clientError(_('You may not delete another user\'s status.'),
403, $this->format);
}
$this->showNotice();
}
/**
* Show the deleted notice
*
* @return void
*/
function showNotice()
{
if (!empty($this->notice)) {
if ($this->format == 'xml') {
$this->showSingleXmlStatus($this->notice);
} elseif ($this->format == 'json') {
$this->show_single_json_status($this->notice);
}
}
}
}

206
actions/apistatusesshow.php Normal file
View File

@ -0,0 +1,206 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a notice (as a Twitter-style status)
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Tom Blankenship <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the notice specified by id as a Twitter-style status and inline user
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Tom Blankenship <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiStatusesShowAction extends ApiPrivateAuthAction
{
var $notice_id = null;
var $notice = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
// 'id' is an undocumented parameter in Twitter's API. Several
// clients make use of it, so we support it too.
// show.json?id=12345 takes precedence over /show/12345.json
$this->notice_id = (int)$this->trimmed('id');
if (empty($notice_id)) {
$this->notice_id = (int)$this->arg('id');
}
$this->notice = Notice::staticGet((int)$this->notice_id);
return true;
}
/**
* Handle the request
*
* Check the format and show the notice
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(_('API method not found!'), $code = 404);
return;
}
$this->showNotice();
}
/**
* Show the notice
*
* @return void
*/
function showNotice()
{
if (!empty($this->notice)) {
if ($this->format == 'xml') {
$this->showSingleXmlStatus($this->notice);
} elseif ($this->format == 'json') {
$this->show_single_json_status($this->notice);
}
} else {
// XXX: Twitter just sets a 404 header and doens't bother
// to return an err msg
$deleted = Deleted_notice::staticGet($this->notice_id);
if (!empty($deleted)) {
$this->clientError(
_('Status deleted.'),
410,
$this->format
);
} else {
$this->clientError(
_('No status with that ID found.'),
404,
$this->format
);
}
}
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this notice last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notice)) {
return strtotime($this->notice->created);
}
return null;
}
/**
* An entity tag for this notice
*
* Returns an Etag based on the action name, language, and
* timestamps of the notice
*
* @return string etag
*/
function etag()
{
if (!empty($this->notice)) {
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->notice->id,
strtotime($this->notice->created))
)
. '"';
}
return null;
}
}

View File

@ -0,0 +1,295 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Post a notice (update your status) through the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Tom Blankenship <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
require_once INSTALLDIR . '/lib/mediafile.php';
/**
* Updates the authenticating user's status (posts a notice).
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Tom Blankenship <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiStatusesUpdateAction extends ApiAuthAction
{
var $source = null;
var $status = null;
var $in_reply_to_status_id = null;
var $lat = null;
var $lon = null;
static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->auth_user;
$this->status = $this->trimmed('status');
$this->source = $this->trimmed('source');
$this->lat = $this->trimmed('lat');
$this->lon = $this->trimmed('long');
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
$this->source = 'api';
}
$this->in_reply_to_status_id
= intval($this->trimmed('in_reply_to_status_id'));
return true;
}
/**
* Handle the request
*
* Make a new notice for the update, save it, and show it
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
}
// Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini
if (empty($_FILES)
&& empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0)
) {
$msg = _('The server was unable to handle that much POST ' .
'data (%s bytes) due to its current configuration.');
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
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;
}
$status_shortened = common_shorten_links($this->status);
if (Notice::contentTooLong($status_shortened)) {
// Note: Twitter truncates anything over 140, flags the status
// as "truncated."
$this->clientError(
sprintf(
_('That\'s too long. Max notice size is %d chars.'),
Notice::maxContent()
),
406,
$this->format
);
return;
}
// Check for commands
$inter = new CommandInterpreter();
$cmd = $inter->handle_command($this->user, $status_shortened);
if ($cmd) {
if ($this->supported($cmd)) {
$cmd->execute(new Channel());
}
// Cmd not supported? Twitter just returns your latest status.
// And, it returns your last status whether the cmd was successful
// or not!
$this->notice = $this->user->getCurrentNotice();
} else {
$reply_to = null;
if (!empty($this->in_reply_to_status_id)) {
// Check whether notice actually exists
$reply = Notice::staticGet($this->in_reply_to_status_id);
if ($reply) {
$reply_to = $this->in_reply_to_status_id;
} else {
$this->clientError(
_('Not found'),
$code = 404,
$this->format
);
return;
}
}
$location = null;
if (!empty($this->lat) && !empty($this->lon)) {
$location = Location::fromLatLon($this->lat, $this->lon);
}
$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($status_shortened, ENT_NOQUOTES, 'UTF-8'),
$this->source,
1,
$reply_to,
null,
null,
empty($location) ? null : $location->lat,
empty($location) ? null : $location->lon,
empty($location) ? null : $location->location_id,
empty($location) ? null : $location->location_ns
);
if (isset($upload)) {
$upload->attachToNotice($this->notice);
}
common_broadcast_notice($this->notice);
}
$this->showNotice();
}
/**
* Show the resulting notice
*
* @return void
*/
function showNotice()
{
if (!empty($this->notice)) {
if ($this->format == 'xml') {
$this->showSingleXmlStatus($this->notice);
} elseif ($this->format == 'json') {
$this->show_single_json_status($this->notice);
}
}
}
/**
* Is this command supported when doing an update from the API?
*
* @param string $cmd the command to check for
*
* @return boolean true or false
*/
function supported($cmd)
{
static $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand',
'FavCommand', 'OnCommand', 'OffCommand');
if (in_array(get_class($cmd), $cmdlist)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,142 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Dump of configuration variables
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/api.php';
/**
* Gives a full dump of configuration variables for this instance
* of StatusNet, minus variables that may be security-sensitive (like
* passwords).
* URL: http://identi.ca/api/statusnet/config.(xml|json)
* Formats: xml, json
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiStatusnetConfigAction extends ApiAction
{
var $keys = array(
'site' => array('name', 'server', 'theme', 'path', 'fancy', 'language',
'email', 'broughtby', 'broughtbyurl', 'closed',
'inviteonly', 'private'),
'license' => array('url', 'title', 'image'),
'nickname' => array('featured'),
'throttle' => array('enabled', 'count', 'timespan'),
'xmpp' => array('enabled', 'server', 'user')
);
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
return true;
}
/**
* Handle the request
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
switch ($this->format) {
case 'xml':
$this->initDocument('xml');
$this->elementStart('config');
// XXX: check that all sections and settings are legal XML elements
common_debug(var_export($this->keys, true));
foreach ($this->keys as $section => $settings) {
$this->elementStart($section);
foreach ($settings as $setting) {
$value = common_config($section, $setting);
if (is_array($value)) {
$value = implode(',', $value);
} else if ($value === false) {
$value = 'false';
} else if ($value === true) {
$value = 'true';
}
$this->element($setting, null, $value);
}
$this->elementEnd($section);
}
$this->elementEnd('config');
$this->endDocument('xml');
break;
case 'json':
$result = array();
foreach ($this->keys as $section => $settings) {
$result[$section] = array();
foreach ($settings as $setting) {
$result[$section][$setting]
= common_config($section, $setting);
}
}
$this->initDocument('json');
$this->showJsonObjects($result);
$this->endDocument('json');
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
}

View File

@ -0,0 +1,102 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* A version stamp for the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns a version number for this version of StatusNet, which
* should make things a bit easier for upgrades.
* URL: http://identi.ca/api/statusnet/version.(xml|json)
* Formats: xml, js
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiStatusnetVersionAction extends ApiPrivateAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
return true;
}
/**
* Handle the request
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
switch ($this->format) {
case 'xml':
$this->initDocument('xml');
$this->element('version', null, STATUSNET_VERSION);
$this->endDocument('xml');
break;
case 'json':
$this->initDocument('json');
print '"'.STATUSNET_VERSION.'"';
$this->endDocument('json');
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
}

View File

@ -0,0 +1,266 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Base class for showing subscription information in the API
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* This class outputs a list of profiles as Twitter-style user and status objects.
* It is used by the API methods /api/statuses/(friends|followers). To support the
* social graph methods it also can output a simple list of IDs.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiSubscriptionsAction extends ApiBareAuthAction
{
var $profiles = null;
var $tag = null;
var $lite = null;
var $ids_only = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->tag = $this->arg('tag');
// Note: Twitter no longer supports 'lite'
$this->lite = $this->arg('lite');
$this->ids_only = $this->arg('ids_only');
// If called as a social graph method, show 5000 per page, otherwise 100
$this->count = isset($this->ids_only) ?
5000 : (int)$this->arg('count', 100);
$this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return false;
}
$this->profiles = $this->getProfiles();
return true;
}
/**
* Handle the request
*
* Show the profiles
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(_('API method not found!'), $code = 404);
return;
}
$this->initDocument($this->format);
if (isset($this->ids_only)) {
$this->showIds();
} else {
$this->showProfiles(isset($this->lite) ? false : true);
}
$this->endDocument($this->format);
}
/**
* Get profiles - should get overrrided
*
* @return array Profiles
*/
function getProfiles()
{
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest profile in the stream
*/
function lastModified()
{
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
return strtotime($this->profiles[0]->created);
}
return null;
}
/**
* An entity tag for this action
*
* Returns an Etag based on the action name, language, user ID, and
* timestamps of the first and last profiles in the subscriptions list
* There's also an indicator to show whether this action is being called
* as /api/statuses/(friends|followers) or /api/(friends|followers)/ids
*
* @return string etag
*/
function etag()
{
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
$last = count($this->profiles) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->user->id,
isset($this->ids_only) ? 'IDs' : 'Profiles',
strtotime($this->profiles[0]->created),
strtotime($this->profiles[$last]->created))
)
. '"';
}
return null;
}
/**
* Show the profiles as Twitter-style useres and statuses
*
* @param boolean $include_statuses Whether to include the latest status
* with each user. Default true.
*
* @return void
*/
function showProfiles($include_statuses = true)
{
switch ($this->format) {
case 'xml':
$this->elementStart('users', array('type' => 'array'));
foreach ($this->profiles as $profile) {
$this->showProfile(
$profile,
$this->format,
null,
$include_statuses
);
}
$this->elementEnd('users');
break;
case 'json':
$arrays = array();
foreach ($this->profiles as $profile) {
$arrays[] = $this->twitterUserArray(
$profile,
$include_statuses
);
}
print json_encode($arrays);
break;
default:
$this->clientError(_('Unsupported format.'));
break;
}
}
/**
* Show the IDs of the profiles only. 5000 per page. To support
* the 'social graph' methods: /api/(friends|followers)/ids
*
* @return void
*/
function showIds()
{
switch ($this->format) {
case 'xml':
$this->elementStart('ids');
foreach ($this->profiles as $profile) {
$this->element('id', null, $profile->id);
}
$this->elementEnd('ids');
break;
case 'json':
$ids = array();
foreach ($this->profiles as $profile) {
$ids[] = (int)$profile->id;
}
print json_encode($ids);
break;
default:
$this->clientError(_('Unsupported format.'));
break;
}
}
}

View File

@ -0,0 +1,237 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a user's favorite 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 API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net> * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apibareauth.php';
/**
* Returns the 20 most recent favorite notices for the authenticating user or user
* specified by the ID parameter in the requested format.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiTimelineFavoritesAction extends ApiBareAuthAction
{
var $notices = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$this->notices = $this->getNotices();
return true;
}
/**
* Handle the request
*
* Just show the notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$this->showTimeline();
}
/**
* Show the timeline of notices
*
* @return void
*/
function showTimeline()
{
$profile = $this->user->getProfile();
$sitename = common_config('site', 'name');
$title = sprintf(
_('%s / Favorites from %s'),
$sitename,
$this->user->nickname
);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:Favorites:" . $this->user->id;
$link = common_local_url(
'favorites',
array('nickname' => $this->user->nickname)
);
$subtitle = sprintf(
_('%s updates favorited by %s / %s.'),
$sitename,
$profile->getBestName(),
$this->user->nickname
);
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
break;
case 'atom':
$selfuri = common_root_url() .
ltrim($_SERVER['QUERY_STRING'], 'p=');
$this->showAtomTimeline(
$this->notices, $title, $id, $link, $subtitle,
null, $selfuri
);
break;
case 'json':
$this->showJsonTimeline($this->notices);
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
break;
}
}
/**
* Get notices
*
* @return array notices
*/
function getNotices()
{
$notices = array();
if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
$notice = $this->user->favoriteNotices(
($this->page-1) * $this->count,
$this->count,
true
);
} else {
$notice = $this->user->favoriteNotices(
($this->page-1) * $this->count,
$this->count,
false
);
}
while ($notice->fetch()) {
$notices[] = clone($notice);
}
return $notices;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
return strtotime($this->notices[0]->created);
}
return null;
}
/**
* An entity tag for this stream
*
* Returns an Etag based on the action name, language, user ID, and
* timestamps of the first and last notice in the timeline
*
* @return string etag
*/
function etag()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->user->id,
strtotime($this->notices[0]->created),
strtotime($this->notices[$last]->created))
)
. '"';
}
return null;
}
}

View File

@ -0,0 +1,247 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show the friends timeline
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* Returns the most recent notices (default 20) posted by the target user.
* This is the equivalent of 'You and friends' page accessed via Web.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiTimelineFriendsAction extends ApiBareAuthAction
{
var $notices = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
common_debug("api friends_timeline");
$this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$this->notices = $this->getNotices();
return true;
}
/**
* Handle the request
*
* Just show the notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$this->showTimeline();
}
/**
* Show the timeline of notices
*
* @return void
*/
function showTimeline()
{
$profile = $this->user->getProfile();
$sitename = common_config('site', 'name');
$title = sprintf(_("%s and friends"), $this->user->nickname);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:FriendsTimeline:" . $this->user->id;
$link = common_local_url(
'all', array('nickname' => $this->user->nickname)
);
$subtitle = sprintf(
_('Updates from %1$s and friends on %2$s!'),
$this->user->nickname, $sitename
);
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
break;
case 'atom':
$target_id = $this->arg('id');
if (isset($target_id)) {
$selfuri = common_root_url() .
'api/statuses/friends_timeline/' .
$target_id . '.atom';
} else {
$selfuri = common_root_url() .
'api/statuses/friends_timeline.atom';
}
$this->showAtomTimeline(
$this->notices, $title, $id, $link,
$subtitle, null, $selfuri
);
break;
case 'json':
$this->showJsonTimeline($this->notices);
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
break;
}
}
/**
* Get notices
*
* @return array notices
*/
function getNotices()
{
$notices = array();
if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
$notice = $this->user->noticeInbox(
($this->page-1) * $this->count,
$this->count, $this->since_id,
$this->max_id, $this->since
);
} else {
$notice = $this->user->noticesWithFriends(
($this->page-1) * $this->count,
$this->count, $this->since_id,
$this->max_id, $this->since
);
}
while ($notice->fetch()) {
$notices[] = clone($notice);
}
return $notices;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
return strtotime($this->notices[0]->created);
}
return null;
}
/**
* An entity tag for this stream
*
* Returns an Etag based on the action name, language, user ID, and
* timestamps of the first and last notice in the timeline
*
* @return string etag
*/
function etag()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->user->id,
strtotime($this->notices[0]->created),
strtotime($this->notices[$last]->created))
)
. '"';
}
return null;
}
}

View File

@ -0,0 +1,237 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a group's 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 API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the most recent notices (default 20) posted to the group specified by ID
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiTimelineGroupAction extends ApiPrivateAuthAction
{
var $group = null;
var $notices = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->group = $this->getTargetGroup($this->arg('id'));
return true;
}
/**
* Handle the request
*
* Just show the notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (empty($this->group)) {
$this->clientError(_('Group not found!'), 404, $this->format);
return false;
}
$this->notices = $this->getNotices();
$this->showTimeline();
}
/**
* Show the timeline of notices
*
* @return void
*/
function showTimeline()
{
$sitename = common_config('site', 'name');
$title = sprintf(_("%s timeline"), $this->group->nickname);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:GroupTimeline:" . $this->group->id;
$link = common_local_url(
'showgroup',
array('nickname' => $this->group->nickname)
);
$subtitle = sprintf(
_('Updates from %1$s on %2$s!'),
$this->group->nickname,
$sitename
);
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
break;
case 'atom':
$selfuri = common_root_url() .
'api/statusnet/groups/timeline/' .
$this->group->nickname . '.atom';
$this->showAtomTimeline(
$this->notices,
$title,
$id,
$link,
$subtitle,
null,
$selfuri
);
break;
case 'json':
$this->showJsonTimeline($this->notices);
break;
default:
$this->clientError(
_('API method not found!'),
404,
$this->format
);
break;
}
}
/**
* Get notices
*
* @return array notices
*/
function getNotices()
{
$notices = array();
$notice = $this->group->getNotices(
($this->page-1) * $this->count,
$this->count,
$this->since_id,
$this->max_id,
$this->since
);
while ($notice->fetch()) {
$notices[] = clone($notice);
}
return $notices;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
return strtotime($this->notices[0]->created);
}
return null;
}
/**
* An entity tag for this stream
*
* Returns an Etag based on the action name, language, group ID and
* timestamps of the first and last notice in the timeline
*
* @return string etag
*/
function etag()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->group->id,
strtotime($this->notices[0]->created),
strtotime($this->notices[$last]->created))
)
. '"';
}
return null;
}
}

View File

@ -0,0 +1,233 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show notices mentioning a user (@nickname)
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* Returns the most recent (default 20) mentions (status containing @nickname)
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiTimelineMentionsAction extends ApiBareAuthAction
{
var $notices = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$this->notices = $this->getNotices();
return true;
}
/**
* Handle the request
*
* Just show the notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$this->showTimeline();
}
/**
* Show the timeline of notices
*
* @return void
*/
function showTimeline()
{
$profile = $this->user->getProfile();
$sitename = common_config('site', 'name');
$title = sprintf(
_('%1$s / Updates mentioning %2$s'),
$sitename, $this->user->nickname
);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:Mentions:" . $this->user->id;
$link = common_local_url(
'replies',
array('nickname' => $this->user->nickname)
);
$subtitle = sprintf(
_('%1$s updates that reply to updates from %2$s / %3$s.'),
$sitename, $this->user->nickname, $profile->getBestName()
);
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
break;
case 'atom':
$selfuri = common_root_url() .
ltrim($_SERVER['QUERY_STRING'], 'p=');
$this->showAtomTimeline(
$this->notices, $title, $id, $link, $subtitle,
null, $selfuri
);
break;
case 'json':
$this->showJsonTimeline($this->notices);
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
break;
}
}
/**
* Get notices
*
* @return array notices
*/
function getNotices()
{
$notices = array();
$notice = $this->user->getReplies(
($this->page - 1) * $this->count, $this->count,
$this->since_id, $this->max_id, $this->since
);
while ($notice->fetch()) {
$notices[] = clone($notice);
}
return $notices;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
return strtotime($this->notices[0]->created);
}
return null;
}
/**
* An entity tag for this stream
*
* Returns an Etag based on the action name, language, user ID, and
* timestamps of the first and last notice in the timeline
*
* @return string etag
*/
function etag()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->user->id,
strtotime($this->notices[0]->created),
strtotime($this->notices[$last]->created))
)
. '"';
}
return null;
}
}

View File

@ -0,0 +1,213 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show the public timeline
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the most recent notices (default 20) posted by everybody
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiTimelinePublicAction extends ApiPrivateAuthAction
{
var $notices = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->notices = $this->getNotices();
return true;
}
/**
* Handle the request
*
* Just show the notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$this->showTimeline();
}
/**
* Show the timeline of notices
*
* @return void
*/
function showTimeline()
{
$sitename = common_config('site', 'name');
$title = sprintf(_("%s public timeline"), $sitename);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:PublicTimeline";
$link = common_root_url();
$subtitle = sprintf(_("%s updates from everyone!"), $sitename);
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
break;
case 'atom':
$selfuri = common_root_url() . 'api/statuses/public_timeline.atom';
$this->showAtomTimeline(
$this->notices, $title, $id, $link,
$subtitle, null, $selfuri
);
break;
case 'json':
$this->showJsonTimeline($this->notices);
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
break;
}
}
/**
* Get notices
*
* @return array notices
*/
function getNotices()
{
$notices = array();
$notice = Notice::publicStream(
($this->page - 1) * $this->count, $this->count, $this->since_id,
$this->max_id, $this->since
);
while ($notice->fetch()) {
$notices[] = clone($notice);
}
return $notices;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
return strtotime($this->notices[0]->created);
}
return null;
}
/**
* An entity tag for this stream
*
* Returns an Etag based on the action name, language, and
* timestamps of the first and last notice in the timeline
*
* @return string etag
*/
function etag()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
strtotime($this->notices[0]->created),
strtotime($this->notices[$last]->created))
)
. '"';
}
return null;
}
}

224
actions/apitimelinetag.php Normal file
View File

@ -0,0 +1,224 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show the latest notices for a given tag
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the 20 most recent notices tagged by a given tag
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiTimelineTagAction extends ApiPrivateAuthAction
{
var $notices = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->tag = $this->arg('tag');
$this->notices = $this->getNotices();
return true;
}
/**
* Handle the request
*
* Just show the notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$this->showTimeline();
}
/**
* Show the timeline of notices
*
* @return void
*/
function showTimeline()
{
$sitename = common_config('site', 'name');
$title = sprintf(_("Notices tagged with %s"), $this->tag);
$link = common_local_url(
'tag',
array('tag' => $this->tag)
);
$subtitle = sprintf(
_('Updates tagged with %1$s on %2$s!'),
$this->tag,
$sitename
);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:TagTimeline:".$tag;
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline($this->notices, $title, $link, $subtitle);
break;
case 'atom':
$selfuri = common_root_url() .
'api/statusnet/tags/timeline/' .
$this->tag . '.atom';
$this->showAtomTimeline(
$this->notices,
$title,
$id,
$link,
$subtitle,
null,
$selfuri
);
break;
case 'json':
$this->showJsonTimeline($this->notices);
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
break;
}
}
/**
* Get notices
*
* @return array notices
*/
function getNotices()
{
$notices = array();
$notice = Notice_tag::getStream(
$this->tag,
($this->page - 1) * $this->count,
$this->count + 1
);
while ($notice->fetch()) {
$notices[] = clone($notice);
}
return $notices;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
return strtotime($this->notices[0]->created);
}
return null;
}
/**
* An entity tag for this stream
*
* Returns an Etag based on the action name, language, and
* timestamps of the first and last notice in the timeline
*
* @return string etag
*/
function etag()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->tag,
strtotime($this->notices[0]->created),
strtotime($this->notices[$last]->created))
)
. '"';
}
return null;
}
}

248
actions/apitimelineuser.php Normal file
View File

@ -0,0 +1,248 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a user's timeline
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* Returns the most recent notices (default 20) posted by the authenticating
* user. Another user's timeline can be requested via the id parameter. This
* is the API equivalent of the user profile web page.
*
* @category API
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author mac65 <mac65@mac65.com>
* @author Mike Cochrane <mikec@mikenz.geek.nz>
* @author Robin Millette <robin@millette.info>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiTimelineUserAction extends ApiBareAuthAction
{
var $notices = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) {
$this->clientError(_('No such user.'), 404, $this->format);
return;
}
$this->notices = $this->getNotices();
return true;
}
/**
* Handle the request
*
* Just show the notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$this->showTimeline();
}
/**
* Show the timeline of notices
*
* @return void
*/
function showTimeline()
{
$profile = $this->user->getProfile();
$sitename = common_config('site', 'name');
$title = sprintf(_("%s timeline"), $this->user->nickname);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:UserTimeline:" . $this->user->id;
$link = common_local_url(
'showstream',
array('nickname' => $this->user->nickname)
);
$subtitle = sprintf(
_('Updates from %1$s on %2$s!'),
$this->user->nickname, $sitename
);
// FriendFeed's SUP protocol
// Also added RSS and Atom feeds
$suplink = common_local_url('sup', null, null, $this->user->id);
header('X-SUP-ID: ' . $suplink);
switch($this->format) {
case 'xml':
$this->showXmlTimeline($this->notices);
break;
case 'rss':
$this->showRssTimeline(
$this->notices, $title, $link,
$subtitle, $suplink
);
break;
case 'atom':
if (isset($apidata['api_arg'])) {
$selfuri = common_root_url() .
'api/statuses/user_timeline/' .
$apidata['api_arg'] . '.atom';
} else {
$selfuri = common_root_url() .
'api/statuses/user_timeline.atom';
}
$this->showAtomTimeline(
$this->notices, $title, $id, $link,
$subtitle, $suplink, $selfuri
);
break;
case 'json':
$this->showJsonTimeline($this->notices);
break;
default:
$this->clientError(_('API method not found!'), $code = 404);
break;
}
}
/**
* Get notices
*
* @return array notices
*/
function getNotices()
{
$notices = array();
$notice = $this->user->getNotices(
($this->page-1) * $this->count, $this->count,
$this->since_id, $this->max_id, $this->since
);
while ($notice->fetch()) {
$notices[] = clone($notice);
}
return $notices;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
return true;
}
/**
* When was this feed last modified?
*
* @return string datestamp of the latest notice in the stream
*/
function lastModified()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
return strtotime($this->notices[0]->created);
}
return null;
}
/**
* An entity tag for this stream
*
* Returns an Etag based on the action name, language, user ID, and
* timestamps of the first and last notice in the timeline
*
* @return string etag
*/
function etag()
{
if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1;
return '"' . implode(
':',
array($this->arg('action'),
common_language(),
$this->user->id,
strtotime($this->notices[0]->created),
strtotime($this->notices[$last]->created))
)
. '"';
}
return null;
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a user's followers (subscribers)
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* Ouputs the authenticating user's followers (subscribers), each with
* current Twitter-style status inline. They are ordered by the order
* in which they subscribed to the user, 100 at a time.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiUserFollowersAction extends ApiSubscriptionsAction
{
/**
* Get the user's subscribers (followers) as an array of profiles
*
* @return array Profiles
*/
function getProfiles()
{
$offset = ($this->page - 1) * $this->count;
$limit = $this->count + 1;
$subs = null;
if (isset($this->tag)) {
$subs = $this->user->getTaggedSubscribers(
$this->tag, $offset, $limit
);
} else {
$subs = $this->user->getSubscribers(
$offset,
$limit
);
}
$profiles = array();
if (!empty($subs)) {
while ($subs->fetch()) {
$profiles[] = clone($subs);
}
}
return $profiles;
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a user's friends (subscriptions)
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apibareauth.php';
/**
* Ouputs the authenticating user's friends (subscriptions), each with
* current Twitter-style status inline. They are ordered by the date
* in which the user subscribed to them, 100 at a time.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiUserFriendsAction extends ApiSubscriptionsAction
{
/**
* Get the user's subscriptions (friends) as an array of profiles
*
* @return array Profiles
*/
function getProfiles()
{
$offset = ($this->page - 1) * $this->count;
$limit = $this->count + 1;
$subs = null;
if (isset($this->tag)) {
$subs = $this->user->getTaggedSubscriptions(
$this->tag, $offset, $limit
);
} else {
$subs = $this->user->getSubscriptions(
$offset,
$limit
);
}
$profiles = array();
if (!empty($subs)) {
while ($subs->fetch()) {
$profiles[] = clone($subs);
}
}
return $profiles;
}
}

126
actions/apiusershow.php Normal file
View File

@ -0,0 +1,126 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a user's profile information
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author mac65 <mac65@mac65.com>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Ouputs information for a user, specified by ID or screen name.
* The user's most recent status will be returned inline.
*
* @category API
* @package StatusNet
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author mac65 <mac65@mac65.com>
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class ApiUserShowAction extends ApiPrivateAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$email = $this->arg('email');
// XXX: email field deprecated in Twitter's API
if (!empty($email)) {
$this->user = User::staticGet('email', $email);
} else {
$this->user = $this->getTargetUser($this->arg('id'));
}
return true;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (empty($this->user)) {
$this->clientError(_('Not found.'), 404, $this->format);
return;
}
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(_('API method not found!'), $code = 404);
return;
}
$profile = $this->user->getProfile();
if (empty($profile)) {
$this->clientError(_('User has no profile.'));
return;
}
$twitter_user = $this->twitterUserArray($this->user->getProfile(), true);
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}
}

View File

@ -244,11 +244,25 @@ class AvatarsettingsAction extends AccountSettingsAction
function handlePost()
{
// Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini
if (empty($_FILES)
&& empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0)
) {
$msg = _('The server was unable to handle that much POST ' .
'data (%s bytes) due to its current configuration.');
$this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return;
}
// CSRF protection
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->show_form(_('There was a problem with your session token. '.
$this->showForm(_('There was a problem with your session token. '.
'Try again, please.'));
return;
}

View File

@ -42,9 +42,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*/
class BlockAction extends Action
class BlockAction extends ProfileFormAction
{
var $profile = null;
/**
* Take arguments for running
*
@ -52,28 +54,22 @@ class BlockAction extends Action
*
* @return boolean success flag
*/
function prepare($args)
{
parent::prepare($args);
if (!common_logged_in()) {
$this->clientError(_('Not logged in.'));
if (!parent::prepare($args)) {
return false;
}
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->clientError(_('There was a problem with your session token. Try again, please.'));
return;
}
$id = $this->trimmed('blockto');
if (!$id) {
$this->clientError(_('No profile specified.'));
return false;
}
$this->profile = Profile::staticGet('id', $id);
if (!$this->profile) {
$this->clientError(_('No profile with that ID.'));
$cur = common_current_user();
assert(!empty($cur)); // checked by parent
if ($cur->hasBlocked($this->profile)) {
$this->clientError(_("You already blocked that user."));
return false;
}
return true;
}
@ -86,18 +82,16 @@ class BlockAction extends Action
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($this->arg('no')) {
$cur = common_current_user();
$other = Profile::staticGet('id', $this->arg('blockto'));
common_redirect(common_local_url('showstream', array('nickname' => $other->nickname)),
303);
$this->returnToArgs();
} elseif ($this->arg('yes')) {
$this->blockProfile();
} elseif ($this->arg('blockto')) {
$this->handlePost();
$this->returnToArgs();
} else {
$this->showPage();
}
}
@ -138,7 +132,7 @@ class BlockAction extends Action
'unable to subscribe to you in the future, and '.
'you will not be notified of any @-replies from them.'));
$this->element('input', array('id' => 'blockto-' . $id,
'name' => 'blockto',
'name' => 'profileid',
'type' => 'hidden',
'value' => $id));
foreach ($this->args as $k => $v) {
@ -146,8 +140,8 @@ class BlockAction extends Action
$this->hidden($k, $v);
}
}
$this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user from this group"));
$this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user from this group'));
$this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user"));
$this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}
@ -157,36 +151,17 @@ class BlockAction extends Action
*
* @return void
*/
function blockProfile()
function handlePost()
{
$cur = common_current_user();
if ($cur->hasBlocked($this->profile)) {
$this->clientError(_('You have already blocked this user.'));
return;
}
$result = $cur->block($this->profile);
if (!$result) {
$this->serverError(_('Failed to save block information.'));
return;
}
// Now, gotta figure where we go back to
foreach ($this->args as $k => $v) {
if ($k == 'returnto-action') {
$action = $v;
} elseif (substr($k, 0, 9) == 'returnto-') {
$args[substr($k, 9)] = $v;
}
}
if ($action) {
common_redirect(common_local_url($action, $args), 303);
} else {
common_redirect(common_local_url('subscribers',
array('nickname' => $cur->nickname)),
303);
}
}
}

75
actions/bookmarklet.php Normal file
View File

@ -0,0 +1,75 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Handler for posting new notices
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Bookmarklet
* @package StatusNet
* @author Sarven Capadisli <csarven@status.net>
* @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR . '/actions/newnotice.php';
/**
* Action for posting a notice
*
* @category Bookmarklet
* @package StatusNet
* @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
class BookmarkletAction extends NewnoticeAction
{
function showTitle()
{
$this->element('title', null, _('Post to ').common_config('site', 'name'));
}
function showHeader()
{
$this->elementStart('div', array('id' => 'header'));
$this->elementStart('address');
$this->element('a', array('class' => 'url',
'href' => common_local_url('public')),
'');
$this->elementEnd('address');
if (common_logged_in()) {
$this->showNoticeForm();
}
$this->elementEnd('div');
}
function showCore()
{
}
function showFooter()
{
}
}

View File

@ -67,11 +67,7 @@ class ConfirmaddressAction extends Action
parent::handle($args);
if (!common_logged_in()) {
common_set_returnto($this->selfUrl());
if (!common_config('site', 'openidonly')) {
common_redirect(common_local_url('login'));
} else {
common_redirect(common_local_url('openidlogin'));
}
common_redirect(common_local_url('login'));
return;
}
$code = $this->trimmed('code');

View File

@ -32,15 +32,45 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/deleteaction.php';
class DeletenoticeAction extends DeleteAction
class DeletenoticeAction extends Action
{
var $error = null;
var $error = null;
var $user = null;
var $notice = null;
var $profile = null;
var $user_profile = null;
function prepare($args)
{
parent::prepare($args);
$this->user = common_current_user();
$notice_id = $this->trimmed('notice');
$this->notice = Notice::staticGet($notice_id);
if (!$this->notice) {
common_user_error(_('No such notice.'));
exit;
}
$this->profile = $this->notice->getProfile();
$this->user_profile = $this->user->getProfile();
return true;
}
function handle($args)
{
parent::handle($args);
if (!common_logged_in()) {
common_user_error(_('Not logged in.'));
exit;
} else if ($this->notice->profile_id != $this->user_profile->id &&
!$this->user->hasRight(Right::DELETEOTHERSNOTICE)) {
common_user_error(_('Can\'t delete this notice.'));
exit;
}
// XXX: Ajax!
if ($_SERVER['REQUEST_METHOD'] == 'POST') {

164
actions/deleteuser.php Normal file
View File

@ -0,0 +1,164 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Action class to delete a user
*
* 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 Action
* @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);
}
/**
* Delete a user
*
* @category Action
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*/
class DeleteuserAction extends ProfileFormAction
{
var $user = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
function prepare($args)
{
if (!parent::prepare($args)) {
return false;
}
$cur = common_current_user();
assert(!empty($cur)); // checked by parent
if (!$cur->hasRight(Right::DELETEUSER)) {
$this->clientError(_("You cannot delete users."));
return false;
}
$this->user = User::staticGet('id', $this->profile->id);
if (empty($this->user)) {
$this->clientError(_("You can only delete local users."));
return false;
}
return true;
}
/**
* Handle request
*
* Shows a page with list of favorite notices
*
* @param array $args $_REQUEST args; handled in prepare()
*
* @return void
*/
function handle($args)
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($this->arg('no')) {
$this->returnToArgs();
} elseif ($this->arg('yes')) {
$this->handlePost();
$this->returnToArgs();
} else {
$this->showPage();
}
}
}
function showContent() {
$this->areYouSureForm();
}
function title() {
return _('Delete user');
}
function showNoticeForm() {
// nop
}
/**
* Confirm with user.
*
* Shows a confirmation form.
*
* @return void
*/
function areYouSureForm()
{
$id = $this->profile->id;
$this->elementStart('form', array('id' => 'deleteuser-' . $id,
'method' => 'post',
'class' => 'form_settings form_entity_block',
'action' => common_local_url('deleteuser')));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
$this->element('legend', _('Delete user'));
$this->element('p', null,
_('Are you sure you want to delete this user? '.
'This will clear all data about the user from the '.
'database, without a backup.'));
$this->element('input', array('id' => 'deleteuserto-' . $id,
'name' => 'profileid',
'type' => 'hidden',
'value' => $id));
foreach ($this->args as $k => $v) {
if (substr($k, 0, 9) == 'returnto-') {
$this->hidden($k, $v);
}
}
$this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user"));
$this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Delete this user'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}
/**
* Actually delete a user.
*
* @return void
*/
function handlePost()
{
$this->user->delete();
}
}

View File

@ -0,0 +1,585 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Design administration panel
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @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')) {
exit(1);
}
/**
* Administer design settings
*
* @category Admin
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @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 DesignadminpanelAction extends AdminPanelAction
{
/* The default site design */
var $design = null;
/**
* Returns the page title
*
* @return string page title
*/
function title()
{
return _('Design');
}
/**
* Instructions for using this form.
*
* @return string instructions
*/
function getInstructions()
{
return _('Design settings for this StatusNet site.');
}
/**
* Get the default design and show the design admin panel form
*
* @return void
*/
function showForm()
{
$this->design = Design::siteDesign();
$form = new DesignAdminPanelForm($this);
$form->show();
return;
}
/**
* Save settings from the form
*
* @return void
*/
function saveSettings()
{
if ($this->arg('save')) {
$this->saveDesignSettings();
} else if ($this->arg('defaults')) {
$this->restoreDefaults();
} else {
$this->clientError(_('Unexpected form submission.'));
}
}
/**
* Save the new design settings
*
* @return void
*/
function saveDesignSettings()
{
// Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini
if (empty($_FILES)
&& empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0)
) {
$msg = _('The server was unable to handle that much POST ' .
'data (%s bytes) due to its current configuration.');
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return;
}
// check for an image upload
$bgimage = $this->saveBackgroundImage();
common_debug("background image: $bgimage");
static $settings = array('theme', 'logo');
$values = array();
foreach ($settings as $setting) {
$values[$setting] = $this->trimmed($setting);
}
$this->validate($values);
// assert(all values are valid);
$bgcolor = new WebColor($this->trimmed('design_background'));
$ccolor = new WebColor($this->trimmed('design_content'));
$sbcolor = new WebColor($this->trimmed('design_sidebar'));
$tcolor = new WebColor($this->trimmed('design_text'));
$lcolor = new WebColor($this->trimmed('design_links'));
$onoff = $this->arg('design_background-image_onoff');
$on = false;
$off = false;
if ($onoff == 'on') {
$on = true;
} else {
$off = true;
}
$tile = $this->boolean('design_background-image_repeat');
$config = new Config();
$config->query('BEGIN');
foreach ($settings as $setting) {
Config::save('site', $setting, $values[$setting]);
}
if (isset($bgimage)) {
Config::save('design', 'backgroundimage', $bgimage);
}
Config::save('design', 'backgroundcolor', $bgcolor->intValue());
Config::save('design', 'contentcolor', $ccolor->intValue());
Config::save('design', 'sidebarcolor', $sbcolor->intValue());
Config::save('design', 'textcolor', $tcolor->intValue());
Config::save('design', 'linkcolor', $lcolor->intValue());
// Hack to use Design's bit setter
$scratch = new Design();
$scratch->setDisposition($on, $off, $tile);
Config::save('design', 'disposition', $scratch->disposition);
$config->query('COMMIT');
return;
}
/**
* Restore the default design
*
* @return void
*/
function restoreDefaults()
{
$this->deleteSetting('site', 'logo');
$this->deleteSetting('site', 'theme');
$settings = array(
'theme', 'backgroundimage', 'backgroundcolor', 'contentcolor',
'sidebarcolor', 'textcolor', 'linkcolor', 'disposition'
);
foreach ($settings as $setting) {
$this->deleteSetting('design', $setting);
}
// XXX: Should we restore the default dir settings, etc.? --Z
}
/**
* Save the background image if the user uploaded one
*
* @return string $filename the filename of the image
*/
function saveBackgroundImage()
{
$filename = null;
if ($_FILES['design_background-image_file']['error'] ==
UPLOAD_ERR_OK) {
$filepath = null;
try {
$imagefile =
ImageFile::fromUpload('design_background-image_file');
} catch (Exception $e) {
$this->clientError('Unable to save background image.');
return;
}
// Note: site design background image has a special filename
$filename = Design::filename('site-design-background',
image_type_to_extension($imagefile->type),
common_timestamp());
$filepath = Design::path($filename);
move_uploaded_file($imagefile->filepath, $filepath);
// delete any old backround img laying around
if (isset($this->design->backgroundimage)) {
@unlink(Design::path($design->backgroundimage));
}
return $filename;
}
}
/**
* Attempt to validate setting values
*
* @return void
*/
function validate(&$values)
{
if (!empty($values['logo']) &&
!Validate::uri($values['logo'], array('allowed_schemes' => array('http', 'https')))) {
$this->clientError(_("Invalid logo URL."));
}
if (!in_array($values['theme'], Theme::listAvailable())) {
$this->clientError(sprintf(_("Theme not available: %s"), $values['theme']));
}
}
/**
* Add the Farbtastic stylesheet
*
* @return void
*/
function showStylesheets()
{
parent::showStylesheets();
$this->cssLink('css/farbtastic.css','base','screen, projection, tv');
}
/**
* Add the Farbtastic scripts
*
* @return void
*/
function showScripts()
{
parent::showScripts();
$this->script('js/farbtastic/farbtastic.js');
$this->script('js/userdesign.go.js');
$this->autofocus('design_background-image_file');
}
}
class DesignAdminPanelForm extends AdminForm
{
/**
* ID of the form
*
* @return int ID of the form
*/
function id()
{
return 'form_design_admin_panel';
}
/**
* class of the form
*
* @return string class of the form
*/
function formClass()
{
return 'form_settings';
}
/**
* HTTP method used to submit the form
*
* For image data we need to send multipart/form-data
* so we set that here too
*
* @return string the method to use for submitting
*/
function method()
{
$this->enctype = 'multipart/form-data';
return 'post';
}
/**
* Action of the form
*
* @return string URL of the action
*/
function action()
{
return common_local_url('designadminpanel');
}
/**
* Data elements of the form
*
* @return void
*/
function formData()
{
$this->out->elementStart('fieldset', array('id' => 'settings_design_logo'));
$this->out->element('legend', null, _('Change logo'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('logo', _('Site logo'), 'Logo for the site (full URL)');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_design_theme'));
$this->out->element('legend', null, _('Change theme'));
$this->out->elementStart('ul', 'form_data');
$themes = Theme::listAvailable();
// XXX: listAvailable() can return an empty list if you
// screw up your settings, so just in case:
if (empty($themes)) {
$themes = array('default', 'default');
}
asort($themes);
$themes = array_combine($themes, $themes);
$this->li();
$this->out->dropdown('theme', _('Site theme'),
$themes, _('Theme for the site.'),
false, $this->value('theme'));
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$design = $this->out->design;
$this->out->elementStart('fieldset', array('id' =>
'settings_design_background-image'));
$this->out->element('legend', null, _('Change background image'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->out->element('label', array('for' => 'design_background-image_file'),
_('Background'));
$this->out->element('input', array('name' => 'design_background-image_file',
'type' => 'file',
'id' => 'design_background-image_file'));
$this->out->element('p', 'form_guide',
sprintf(_('You can upload a background image for the site. ' .
'The maximum file size is %1$s.'), ImageFile::maxFileSize()));
$this->out->element('input', array('name' => 'MAX_FILE_SIZE',
'type' => 'hidden',
'id' => 'MAX_FILE_SIZE',
'value' => ImageFile::maxFileSizeInt()));
$this->unli();
if (!empty($design->backgroundimage)) {
$this->out->elementStart('li', array('id' =>
'design_background-image_onoff'));
$this->out->element('img', array('src' =>
Design::url($design->backgroundimage)));
$attrs = array('name' => 'design_background-image_onoff',
'type' => 'radio',
'id' => 'design_background-image_on',
'class' => 'radio',
'value' => 'on');
if ($design->disposition & BACKGROUND_ON) {
$attrs['checked'] = 'checked';
}
$this->out->element('input', $attrs);
$this->out->element('label', array('for' => 'design_background-image_on',
'class' => 'radio'),
_('On'));
$attrs = array('name' => 'design_background-image_onoff',
'type' => 'radio',
'id' => 'design_background-image_off',
'class' => 'radio',
'value' => 'off');
if ($design->disposition & BACKGROUND_OFF) {
$attrs['checked'] = 'checked';
}
$this->out->element('input', $attrs);
$this->out->element('label', array('for' => 'design_background-image_off',
'class' => 'radio'),
_('Off'));
$this->out->element('p', 'form_guide', _('Turn background image on or off.'));
$this->unli();
$this->li();
$this->out->checkbox('design_background-image_repeat',
_('Tile background image'),
($design->disposition & BACKGROUND_TILE) ? true : false);
$this->unli();
}
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_design_color'));
$this->out->element('legend', null, _('Change colours'));
$this->out->elementStart('ul', 'form_data');
try {
$bgcolor = new WebColor($design->backgroundcolor);
$this->li();
$this->out->element('label', array('for' => 'swatch-1'), _('Background'));
$this->out->element('input', array('name' => 'design_background',
'type' => 'text',
'id' => 'swatch-1',
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->unli();
$ccolor = new WebColor($design->contentcolor);
$this->li();
$this->out->element('label', array('for' => 'swatch-2'), _('Content'));
$this->out->element('input', array('name' => 'design_content',
'type' => 'text',
'id' => 'swatch-2',
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->unli();
$sbcolor = new WebColor($design->sidebarcolor);
$this->li();
$this->out->element('label', array('for' => 'swatch-3'), _('Sidebar'));
$this->out->element('input', array('name' => 'design_sidebar',
'type' => 'text',
'id' => 'swatch-3',
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->unli();
$tcolor = new WebColor($design->textcolor);
$this->li();
$this->out->element('label', array('for' => 'swatch-4'), _('Text'));
$this->out->element('input', array('name' => 'design_text',
'type' => 'text',
'id' => 'swatch-4',
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->unli();
$lcolor = new WebColor($design->linkcolor);
$this->li();
$this->out->element('label', array('for' => 'swatch-5'), _('Links'));
$this->out->element('input', array('name' => 'design_links',
'type' => 'text',
'id' => 'swatch-5',
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->unli();
} catch (WebColorException $e) {
common_log(LOG_ERR, 'Bad color values in site design: ' .
$e->getMessage());
}
$this->out->elementEnd('fieldset');
$this->out->elementEnd('ul');
}
/**
* Action elements
*
* @return void
*/
function formActions()
{
$this->out->submit('defaults', _('Use defaults'), 'submit form_action-default',
'defaults', _('Restore default designs'));
$this->out->element('input', array('id' => 'settings_design_reset',
'type' => 'reset',
'value' => 'Reset',
'class' => 'submit form_action-primary',
'title' => _('Reset back to default')));
$this->out->submit('save', _('Save'), 'submit form_action-secondary',
'save', _('Save design'));
}
}

View File

@ -58,12 +58,24 @@ class DocAction extends Action
function handle($args)
{
parent::handle($args);
$this->title = $this->trimmed('title');
$this->filename = INSTALLDIR.'/doc-src/'.$this->title;
if (!file_exists($this->filename)) {
$this->clientError(_('No such document.'));
return;
$this->title = $this->trimmed('title');
$this->output = null;
if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) {
$this->filename = INSTALLDIR.'/doc-src/'.$this->title;
if (!file_exists($this->filename)) {
$this->clientError(_('No such document.'));
return;
}
$c = file_get_contents($this->filename);
$this->output = common_markup_to_html($c);
Event::handle('EndLoadDoc', array($this->title, &$this->output));
}
$this->showPage();
}
@ -93,9 +105,7 @@ class DocAction extends Action
*/
function showContent()
{
$c = file_get_contents($this->filename);
$output = common_markup_to_html($c);
$this->raw($output);
$this->raw($this->output);
}
/**

View File

@ -64,11 +64,6 @@ class EditgroupAction extends GroupDesignAction
{
parent::prepare($args);
if (!common_config('inboxes','enabled')) {
$this->serverError(_('Inboxes must be enabled for groups to work'));
return false;
}
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to create a group.'));
return false;
@ -202,8 +197,8 @@ class EditgroupAction extends GroupDesignAction
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).'));
return;
} else if (!is_null($description) && mb_strlen($description) > 140) {
$this->showForm(_('description is too long (max 140 chars).'));
} else if (User_group::descriptionTooLong($description)) {
$this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription()));
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).'));

View File

@ -95,7 +95,7 @@ class EmailsettingsAction extends AccountSettingsAction
'class' => 'form_settings',
'action' =>
common_local_url('emailsettings')));
$this->elementStart('fieldset');
$this->elementStart('fieldset', array('id' => 'settings_email_address'));
$this->element('legend', null, _('Address'));
$this->hidden('token', common_session_token());
@ -194,6 +194,7 @@ class EmailsettingsAction extends AccountSettingsAction
$this->elementEnd('ul');
$this->submit('save', _('Save'));
$this->elementEnd('fieldset');
$this->elementEnd('fieldset');
$this->elementEnd('form');
}
@ -326,7 +327,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) {

View File

@ -153,8 +153,7 @@ class FavoritedAction extends Action
$message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.');
}
else {
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to add a notice to your favorites!'),
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
$message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!');
}
$this->elementStart('div', 'guide');

View File

@ -74,6 +74,7 @@ class FavoritesrssAction extends Rss10Action
$this->clientError(_('No such user.'));
return false;
} else {
$this->notices = $this->getNotices($this->limit);
return true;
}
}

View File

@ -1,5 +1,16 @@
<?php
/*
/**
* Handler for remote subscription finish callback
*
* 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.
*
@ -15,285 +26,121 @@
*
* 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.'/lib/omb.php');
require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
require_once INSTALLDIR.'/lib/omb.php';
/**
* Handler for remote subscription finish callback
*
* When a remote user subscribes a local user, a redirect to this action is
* issued after the remote user authorized his service to subscribe.
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@status.net>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*/
class FinishremotesubscribeAction extends Action
{
/**
* Class handler.
*
* @param array $args query arguments
*
* @return nothing
*
**/
function handle($args)
{
parent::handle($args);
if (common_logged_in()) {
$this->clientError(_('You can use the local subscription!'));
return;
}
/* Restore session data. RemotesubscribeAction should have stored
this entry. */
$service = unserialize($_SESSION['oauth_authorization_request']);
$omb = $_SESSION['oauth_authorization_request'];
if (!$omb) {
if (!$service) {
$this->clientError(_('Not expecting this response!'));
return;
}
common_debug('stored request: '.print_r($omb,true), __FILE__);
common_debug('stored request: '. print_r($service, true), __FILE__);
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('finishuserauthorization'));
$token = $req->get_parameter('oauth_token');
# I think this is the success metric
if ($token != $omb['token']) {
$this->clientError(_('Not authorized.'));
return;
}
$version = $req->get_parameter('omb_version');
if ($version != OMB_VERSION_01) {
$this->clientError(_('Unknown version of OMB protocol.'));
return;
}
$nickname = $req->get_parameter('omb_listener_nickname');
if (!$nickname) {
$this->clientError(_('No nickname provided by remote server.'));
return;
}
$profile_url = $req->get_parameter('omb_listener_profile');
if (!$profile_url) {
$this->clientError(_('No profile URL returned by server.'));
return;
}
if (!Validate::uri($profile_url, array('allowed_schemes' => array('http', 'https')))) {
$this->clientError(_('Invalid profile URL returned by server.'));
return;
}
if ($profile_url == common_local_url('showstream', array('nickname' => $nickname))) {
$this->clientError(_('You can use the local subscription!'));
return;
}
common_debug('listenee: "'.$omb['listenee'].'"', __FILE__);
$user = User::staticGet('nickname', $omb['listenee']);
/* Create user objects for both users. Do it early for request
validation. */
$user = User::staticGet('uri', $service->getListeneeURI());
if (!$user) {
$this->clientError(_('User being listened to doesn\'t exist.'));
$this->clientError(_('User being listened to does not exist.'));
return;
}
$other = User::staticGet('uri', $omb['listener']);
$other = User::staticGet('uri', $service->getListenerURI());
if ($other) {
$this->clientError(_('You can use the local subscription!'));
return;
}
$fullname = $req->get_parameter('omb_listener_fullname');
$homepage = $req->get_parameter('omb_listener_homepage');
$bio = $req->get_parameter('omb_listener_bio');
$location = $req->get_parameter('omb_listener_location');
$avatar_url = $req->get_parameter('omb_listener_avatar');
$remote = Remote_profile::staticGet('uri', $service->getListenerURI());
list($newtok, $newsecret) = $this->access_token($omb);
if (!$newtok || !$newsecret) {
$this->clientError(_('Couldn\'t convert request tokens to access tokens.'));
return;
}
# XXX: possible attack point; subscribe and return someone else's profile URI
$remote = Remote_profile::staticGet('uri', $omb['listener']);
if ($remote) {
$exists = true;
$profile = Profile::staticGet($remote->id);
$orig_remote = clone($remote);
$orig_profile = clone($profile);
# XXX: compare current postNotice and updateProfile URLs to the ones
# stored in the DB to avoid (possibly...) above attack
} else {
$exists = false;
$remote = new Remote_profile();
$remote->uri = $omb['listener'];
$profile = new Profile();
}
$profile->nickname = $nickname;
$profile->profileurl = $profile_url;
if (!is_null($fullname)) {
$profile->fullname = $fullname;
}
if (!is_null($homepage)) {
$profile->homepage = $homepage;
}
if (!is_null($bio)) {
$profile->bio = $bio;
}
if (!is_null($location)) {
$profile->location = $location;
}
if ($exists) {
$profile->update($orig_profile);
} else {
$profile->created = DB_DataObject_Cast::dateTime(); # current time
$id = $profile->insert();
if (!$id) {
$this->serverError(_('Error inserting new profile'));
return;
}
$remote->id = $id;
}
if ($avatar_url) {
if (!$this->add_avatar($profile, $avatar_url)) {
$this->serverError(_('Error inserting avatar'));
return;
}
}
$remote->postnoticeurl = $omb['post_notice_url'];
$remote->updateprofileurl = $omb['update_profile_url'];
if ($exists) {
if (!$remote->update($orig_remote)) {
$this->serverError(_('Error updating remote profile'));
return;
}
} else {
$remote->created = DB_DataObject_Cast::dateTime(); # current time
if (!$remote->insert()) {
$this->serverError(_('Error inserting remote profile'));
return;
}
}
$profile = Profile::staticGet($remote->id);
if ($user->hasBlocked($profile)) {
$this->clientError(_('That user has blocked you from subscribing.'));
return;
}
$sub = new Subscription();
$sub->subscriber = $remote->id;
$sub->subscribed = $user->id;
$sub_exists = false;
if ($sub->find(true)) {
$sub_exists = true;
$orig_sub = clone($sub);
} else {
$sub_exists = false;
$sub->created = DB_DataObject_Cast::dateTime(); # current time
}
$sub->token = $newtok;
$sub->secret = $newsecret;
if ($sub_exists) {
$result = $sub->update($orig_sub);
} else {
$result = $sub->insert();
}
if (!$result) {
common_log_db_error($sub, ($sub_exists) ? 'UPDATE' : 'INSERT', __FILE__);
$this->clientError(_('Couldn\'t insert new subscription.'));
/* Perform the handling itself via libomb. */
try {
$service->finishAuthorization();
} catch (OAuthException $e) {
if ($e->getMessage() == 'The authorized token does not equal the ' .
'submitted token.') {
$this->clientError(_('You are not authorized.'));
return;
} else {
$this->clientError(_('Could not convert request token to ' .
'access token.'));
return;
}
} catch (OMB_RemoteServiceException $e) {
$this->clientError(_('Remote service uses unknown version of ' .
'OMB protocol.'));
return;
} catch (Exception $e) {
common_debug('Got exception ' . print_r($e, true), __FILE__);
$this->clientError($e->getMessage());
return;
}
# Notify user, if necessary
/* The service URLs are not accessible from datastore, so setting them
after insertion of the profile. */
$orig_remote = clone($remote);
mail_subscribe_notify_profile($user, $profile);
$remote->postnoticeurl =
$service->getServiceURI(OMB_ENDPOINT_POSTNOTICE);
$remote->updateprofileurl =
$service->getServiceURI(OMB_ENDPOINT_UPDATEPROFILE);
# Clear the data
if (!$remote->update($orig_remote)) {
$this->serverError(_('Error updating remote profile'));
return;
}
/* Clear the session data. */
unset($_SESSION['oauth_authorization_request']);
# If we show subscriptions in reverse chron order, this should
# show up close to the top of the page
/* If we show subscriptions in reverse chronological order, the new one
should show up close to the top of the page. */
common_redirect(common_local_url('subscribers', array('nickname' =>
$user->nickname)),
303);
}
function add_avatar($profile, $url)
{
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
copy($url, $temp_filename);
$imagefile = new ImageFile($profile->id, $temp_filename);
$filename = Avatar::filename($profile->id,
image_type_to_extension($imagefile->type),
null,
common_timestamp());
rename($temp_filename, Avatar::path($filename));
return $profile->setOriginal($filename);
}
function access_token($omb)
{
common_debug('starting request for access token', __FILE__);
$con = omb_oauth_consumer();
$tok = new OAuthToken($omb['token'], $omb['secret']);
common_debug('using request token "'.$tok.'"', __FILE__);
$url = $omb['access_token_url'];
common_debug('using access token url "'.$url.'"', __FILE__);
# XXX: Is this the right thing to do? Strip off GET params and make them
# POST params? Seems wrong to me.
$parsed = parse_url($url);
$params = array();
parse_str($parsed['query'], $params);
$req = OAuthRequest::from_consumer_and_token($con, $tok, "POST", $url, $params);
$req->set_parameter('omb_version', OMB_VERSION_01);
# XXX: test to see if endpoint accepts this signature method
$req->sign_request(omb_hmac_sha1(), $con, $tok);
# We re-use this tool's fetcher, since it's pretty good
common_debug('posting to access token url "'.$req->get_normalized_http_url().'"', __FILE__);
common_debug('posting request data "'.$req->to_postdata().'"', __FILE__);
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(),
array('User-Agent: StatusNet/' . STATUSNET_VERSION));
common_debug('got result: "'.print_r($result,true).'"', __FILE__);
if ($result->status != 200) {
return null;
}
parse_str($result->body, $return);
return array($return['oauth_token'], $return['oauth_token_secret']);
}
}

View File

@ -108,11 +108,29 @@ class FoafAction extends Action
if ($this->profile->bio) {
$this->element('bio:olb', null, $this->profile->bio);
}
// XXX: more structured location data
if ($this->profile->location) {
$location = $this->profile->getLocation();
if ($location) {
$attr = array();
if ($location->getRdfURL()) {
$attr['rdf:about'] = $location->getRdfURL();
}
$location_name = $location->getName();
$this->elementStart('based_near');
$this->elementStart('geo:SpatialThing');
$this->element('name', null, $this->profile->location);
$this->elementStart('geo:SpatialThing', $attr);
if ($location_name) {
$this->element('name', null, $location_name);
}
if ($location->lat) {
$this->element('geo:lat', null, $location->lat);
}
if ($location->lon) {
$this->element('geo:long', null, $location->lat);
}
if ($location->getURL()) {
$this->element('page', array('rdf:resource'=>$location->getURL()));
}
$this->elementEnd('geo:SpatialThing');
$this->elementEnd('based_near');
}

173
actions/foafgroup.php Normal file
View File

@ -0,0 +1,173 @@
<?php
/*
* StatusNet the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Mail
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Toby Inkster <mail@tobyinkster.co.uk>
* @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 FoafGroupAction extends Action
{
function isReadOnly($args)
{
return true;
}
function prepare($args)
{
parent::prepare($args);
$nickname_arg = $this->arg('nickname');
if (empty($nickname_arg)) {
$this->clientError(_('No such group.'), 404);
return false;
}
$this->nickname = common_canonical_nickname($nickname_arg);
// Permanent redirect on non-canonical nickname
if ($nickname_arg != $this->nickname) {
common_redirect(common_local_url('foafgroup',
array('nickname' => $this->nickname)),
301);
return false;
}
$this->group = User_group::staticGet('nickname', $this->nickname);
if (!$this->group) {
$this->clientError(_('No such group.'), 404);
return false;
}
common_set_returnto($this->selfUrl());
return true;
}
function handle($args)
{
parent::handle($args);
header('Content-Type: application/rdf+xml');
$this->startXML();
$this->elementStart('rdf:RDF', array('xmlns:rdf' =>
'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'xmlns:dcterms' =>
'http://purl.org/dc/terms/',
'xmlns:sioc' =>
'http://rdfs.org/sioc/ns#',
'xmlns:foaf' =>
'http://xmlns.com/foaf/0.1/',
'xmlns:statusnet' =>
'http://status.net/ont/',
'xmlns' => 'http://xmlns.com/foaf/0.1/'));
$this->showPpd(common_local_url('foafgroup', array('nickname' => $this->nickname)), $this->group->permalink());
$this->elementStart('Group', array('rdf:about' =>
$this->group->permalink()));
if ($this->group->fullname) {
$this->element('name', null, $this->group->fullname);
}
if ($this->group->description) {
$this->element('dcterms:description', null, $this->group->description);
}
if ($this->group->nickname) {
$this->element('dcterms:identifier', null, $this->group->nickname);
$this->element('nick', null, $this->group->nickname);
}
foreach ($this->group->getAliases() as $alias) {
$this->element('nick', null, $alias);
}
if ($this->group->homeUrl()) {
$this->element('weblog', array('rdf:resource' => $this->group->homeUrl()));
}
if ($this->group->homepage) {
$this->element('page', array('rdf:resource' => $this->group->homepage));
}
if ($this->group->homepage_logo) {
$this->element('depiction', array('rdf:resource' => $this->group->homepage_logo));
}
$members = $this->group->getMembers();
$member_details = array();
while ($members->fetch()) {
$member_uri = common_local_url('userbyid', array('id'=>$members->id));
$member_details[$member_uri] = array(
'nickname' => $members->nickname
);
$this->element('member', array('rdf:resource' => $member_uri));
}
$admins = $this->group->getAdmins();
while ($admins->fetch()) {
$admin_uri = common_local_url('userbyid', array('id'=>$admins->id));
$member_details[$admin_uri]['is_admin'] = true;
$this->element('statusnet:groupAdmin', array('rdf:resource' => $admin_uri));
}
$this->elementEnd('Group');
ksort($member_details);
foreach ($member_details as $uri => $details) {
if ($details['is_admin'])
{
$this->elementStart('Agent', array('rdf:about' => $uri));
$this->element('nick', null, $details['nickname']);
$this->elementStart('holdsAccount');
$this->elementStart('sioc:User', array('rdf:about'=>$uri.'#acct'));
$this->elementStart('sioc:has_function');
$this->elementStart('statusnet:GroupAdminRole');
$this->element('sioc:scope', array('rdf:resource' => $this->group->permalink()));
$this->elementEnd('statusnet:GroupAdminRole');
$this->elementEnd('sioc:has_function');
$this->elementEnd('sioc:User');
$this->elementEnd('holdsAccount');
$this->elementEnd('Agent');
}
else
{
$this->element('Agent', array(
'foaf:nick' => $details['nickname'],
'rdf:about' => $uri,
));
}
}
$this->elementEnd('rdf:RDF');
$this->endXML();
}
function showPpd($foaf_url, $person_uri)
{
$this->elementStart('Document', array('rdf:about' => $foaf_url));
$this->element('primaryTopic', array('rdf:resource' => $person_uri));
$this->elementEnd('Document');
}
}

145
actions/getfile.php Normal file
View File

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

View File

@ -151,17 +151,19 @@ class GroupblockAction extends Action
function areYouSureForm()
{
$id = $this->profile->id;
$this->elementStart('form', array('id' => 'block-' . $id,
'method' => 'post',
'class' => 'form_settings form_entity_block',
'action' => common_local_url('groupblock')));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
$this->element('legend', _('Block user'));
$this->element('p', null,
sprintf(_('Are you sure you want to block user "%s" from the group "%s"? '.
'They will be removed from the group, unable to post, and '.
'unable to subscribe to the group in the future.'),
$this->profile->getBestName(),
$this->group->getBestName()));
$this->elementStart('form', array('id' => 'block-' . $id,
'method' => 'post',
'class' => 'block',
'action' => common_local_url('groupblock')));
$this->hidden('token', common_session_token());
$this->hidden('blockto-' . $this->profile->id,
$this->profile->id,
'blockto');
@ -173,8 +175,9 @@ class GroupblockAction extends Action
$this->hidden($k, $v);
}
}
$this->submit('no', _('No'));
$this->submit('yes', _('Yes'));
$this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user from this group"));
$this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user from this group'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}

View File

@ -68,11 +68,6 @@ class GroupbyidAction extends Action
{
parent::prepare($args);
if (!common_config('inboxes','enabled')) {
$this->serverError(_('Inboxes must be enabled for groups to work'));
return false;
}
$id = $this->arg('id');
if (!$id) {

View File

@ -64,11 +64,6 @@ class GroupDesignSettingsAction extends DesignSettingsAction
{
parent::prepare($args);
if (!common_config('inboxes', 'enabled')) {
$this->serverError(_('Inboxes must be enabled for groups to work'));
return false;
}
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to edit a group.'));
return false;

View File

@ -66,11 +66,6 @@ class GrouplogoAction extends GroupDesignAction
{
parent::prepare($args);
if (!common_config('inboxes','enabled')) {
$this->serverError(_('Inboxes must be enabled for groups to work'));
return false;
}
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to create a group.'));
return false;

View File

@ -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();
}

View File

@ -76,11 +76,6 @@ class groupRssAction extends Rss10Action
{
parent::prepare($args);
if (!common_config('inboxes','enabled')) {
$this->serverError(_('Inboxes must be enabled for groups to work'));
return false;
}
$nickname_arg = $this->arg('nickname');
$nickname = common_canonical_nickname($nickname_arg);
@ -104,6 +99,7 @@ class groupRssAction extends Rss10Action
return false;
}
$this->notices = $this->getNotices($this->limit);
return true;
}

View File

@ -82,8 +82,7 @@ class GroupsearchAction extends SearchAction
$message = _('If you can\'t find the group you\'re looking for, you can [create it](%%action.newgroup%%) yourself.');
}
else {
$message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and [create the group](%%%%action.newgroup%%%%) yourself!'),
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
$message = _('Why not [register an account](%%action.register%%) and [create the group](%%action.newgroup%%) yourself!');
}
$this->elementStart('div', 'guide');
$this->raw(common_markup_to_html($message));

View File

@ -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;
}
@ -241,7 +241,7 @@ class InviteAction extends CurrentUserDesignAction
common_root_url(),
$personal,
common_local_url('showstream', array('nickname' => $user->nickname)),
common_local_url((!common_config('site', 'openidonly')) ? 'register' : 'openidlogin', array('code' => $invite->code)));
common_local_url('register', array('code' => $invite->code)));
mail_send($recipients, $headers, $body);
}

View File

@ -56,11 +56,6 @@ class JoingroupAction extends Action
{
parent::prepare($args);
if (!common_config('inboxes','enabled')) {
$this->serverError(_('Inboxes must be enabled for groups to work'));
return false;
}
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to join a group.'));
return false;

View File

@ -56,11 +56,6 @@ class LeavegroupAction extends Action
{
parent::prepare($args);
if (!common_config('inboxes','enabled')) {
$this->serverError(_('Inboxes must be enabled for groups to work.'));
return false;
}
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to leave a group.'));
return false;

View File

@ -67,8 +67,6 @@ class LoginAction extends Action
*
* Switches on request method; either shows the form or handles its input.
*
* Checks if only OpenID is allowed and redirects to openidlogin if so.
*
* @param array $args $_REQUEST data
*
* @return void
@ -77,12 +75,12 @@ class LoginAction extends Action
function handle($args)
{
parent::handle($args);
if (common_config('site', 'openidonly')) {
common_redirect(common_local_url('openidlogin'));
} else if (common_is_real_login()) {
if (common_is_real_login()) {
$this->clientError(_('Already logged in.'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->checkLogin();
} else if (isset($args['user_id']) && isset($args['token'])){
$this->checkLogin($args['user_id'],$args['token']);
} else {
common_ensure_session();
$this->showForm();
@ -99,23 +97,48 @@ class LoginAction extends Action
* @return void
*/
function checkLogin()
function checkLogin($user_id=null, $token=null)
{
// XXX: login throttle
if(isset($token) && isset($user_id)){
//Token based login (from the LoginCommand)
$login_token = Login_token::staticGet('user_id',$user_id);
if($login_token && $login_token->token == $token){
if($login_token->modified > time()+2*60){
//token has expired
//delete the token as it is useless
$login_token->delete();
$this->showForm(_('Invalid or expired token.'));
return;
}else{
//delete the token so it cannot be reused
$login_token->delete();
//it's a valid token - let them log in
$user = User::staticGet('id', $user_id);
//$user = User::staticGet('nickname', "candrews");
}
}else{
$this->showForm(_('Invalid or expired token.'));
return;
}
}else{
// Regular form submission login
// CSRF protection - token set in NoticeForm
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->clientError(_('There was a problem with your session token. '.
'Try again, please.'));
return;
// XXX: login throttle
// CSRF protection - token set in NoticeForm
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->clientError(_('There was a problem with your session token. '.
'Try again, please.'));
return;
}
$nickname = $this->trimmed('nickname');
$password = $this->arg('password');
$user = common_check_user($nickname, $password);
}
$nickname = common_canonical_nickname($this->trimmed('nickname'));
$password = $this->arg('password');
$user = common_check_user($nickname, $password);
if (!$user) {
$this->showForm(_('Incorrect username or password.'));
return;
@ -123,7 +146,7 @@ class LoginAction extends Action
// success!
if (!common_set_user($user)) {
$this->serverError(_('Error setting user.'));
$this->serverError(_('Error setting user. You are probably not authorized.'));
return;
}
@ -141,7 +164,7 @@ class LoginAction extends Action
} else {
$url = common_local_url('all',
array('nickname' =>
$nickname));
$user->nickname));
}
common_redirect($url, 303);
@ -259,11 +282,6 @@ class LoginAction extends Action
return _('For security reasons, please re-enter your ' .
'user name and password ' .
'before changing your settings.');
} else if (common_config('openid', 'enabled')) {
return _('Login with your username and password. ' .
'Don\'t have a username yet? ' .
'[Register](%%action.register%%) a new account, or ' .
'try [OpenID](%%action.openidlogin%%). ');
} else {
return _('Login with your username and password. ' .
'Don\'t have a username yet? ' .

View File

@ -32,8 +32,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/openid.php';
/**
* Logout action class.
*

View File

@ -59,7 +59,7 @@ class MicrosummaryAction extends Action
$user = User::staticGet('nickname', $nickname);
if (!$user) {
$this->clientError(_('No such user'), 404);
$this->clientError(_('No such user.'), 404);
return;
}

View File

@ -61,11 +61,6 @@ class NewgroupAction extends Action
{
parent::prepare($args);
if (!common_config('inboxes','enabled')) {
$this->serverError(_('Inboxes must be enabled for groups to work'));
return false;
}
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to create a group.'));
return false;
@ -146,8 +141,8 @@ class NewgroupAction extends Action
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).'));
return;
} else if (!is_null($description) && mb_strlen($description) > 140) {
$this->showForm(_('description is too long (max 140 chars).'));
} else if (User_group::descriptionTooLong($description)) {
$this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription()));
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).'));
@ -191,45 +186,13 @@ class NewgroupAction extends Action
assert(!is_null($cur));
$group = new User_group();
$group->query('BEGIN');
$group->nickname = $nickname;
$group->fullname = $fullname;
$group->homepage = $homepage;
$group->description = $description;
$group->location = $location;
$group->created = common_sql_now();
$result = $group->insert();
if (!$result) {
common_log_db_error($group, 'INSERT', __FILE__);
$this->serverError(_('Could not create group.'));
}
$result = $group->setAliases($aliases);
if (!$result) {
$this->serverError(_('Could not create aliases.'));
}
$member = new Group_member();
$member->group_id = $group->id;
$member->profile_id = $cur->id;
$member->is_admin = 1;
$member->created = $group->created;
$result = $member->insert();
if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__);
$this->serverError(_('Could not set group membership.'));
}
$group->query('COMMIT');
$group = User_group::register(array('nickname' => $nickname,
'fullname' => $fullname,
'homepage' => $homepage,
'description' => $description,
'location' => $location,
'aliases' => $aliases,
'userid' => $cur->id));
common_redirect($group->homeUrl(), 303);
}

View File

@ -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;
}
@ -111,7 +113,7 @@ class NewmessageAction extends Action
$this->other = User::staticGet('id', $this->to);
if (!$this->other) {
$this->clientError(_('No such user'), 404);
$this->clientError(_('No such user.'), 404);
return false;
}
@ -144,9 +146,10 @@ class NewmessageAction extends Action
} else {
$content_shortened = common_shorten_links($this->content);
if (mb_strlen($content_shortened) > 140) {
$this->showForm(_('That\'s too long. ' .
'Max message size is 140 chars.'));
if (Message::contentTooLong($content_shortened)) {
$this->showForm(sprintf(_('That\'s too long. ' .
'Max message size is %d chars.'),
Message::maxContent()));
return;
}
}
@ -220,7 +223,21 @@ class NewmessageAction extends Action
}
$this->msg = $msg;
$this->showPage();
if ($this->trimmed('ajax')) {
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, _('New message'));
$this->elementEnd('head');
$this->elementStart('body');
$this->showNoticeForm();
$this->elementEnd('body');
$this->endHTML();
}
else {
$this->showPage();
}
}
function showPageNotice()

View File

@ -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,17 +134,12 @@ class NewnoticeAction extends Action
if (!$content) {
$this->clientError(_('No content!'));
} else {
$content_shortened = common_shorten_links($content);
if (mb_strlen($content_shortened) > 140) {
$this->clientError(_('That\'s too long. '.
'Max notice size is 140 chars.'));
}
return;
}
$inter = new CommandInterpreter();
$cmd = $inter->handle_command($user, $content_shortened);
$cmd = $inter->handle_command($user, $content);
if ($cmd) {
if ($this->boolean('ajax')) {
@ -181,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...
@ -188,84 +164,36 @@ 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;
$lat = $this->trimmed('lat');
$lon = $this->trimmed('lon');
$location_id = $this->trimmed('location_id');
$location_ns = $this->trimmed('location_ns');
case UPLOAD_ERR_OK:
$mimetype = $this->getUploadedFileType();
if (!$this->isRespectsQuota($user)) {
die('clientError() should trigger an exception before reaching here.');
}
break;
$upload = null;
$upload = MediaFile::fromUpload('attach');
case UPLOAD_ERR_INI_SIZE:
$this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
if (isset($upload)) {
case UPLOAD_ERR_FORM_SIZE:
$this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
$content_shortened .= ' ' . $upload->shortUrl();
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 (Notice::contentTooLong($content_shortened)) {
$upload->delete();
$this->clientError(
sprintf(
_('Max notice size is %d chars, including attachment URL.'),
Notice::maxContent()
)
);
}
}
if (isset($mimetype)) {
$filename = $this->saveFile($mimetype);
if (empty($filename)) {
$this->clientError(_('Couldn\'t save file.'));
}
$fileRecord = $this->storeFile($filename, $mimetype);
$fileurl = common_local_url('attachment',
array('attachment' => $fileRecord->id));
// not sure this is necessary -- Zach
$this->maybeAddRedir($fileRecord->id, $fileurl);
$short_fileurl = common_shorten_url($fileurl);
if (!$short_fileurl) {
// todo -- Consider forcing default shortener if none selected?
$short_fileurl = $fileurl;
}
$content_shortened .= ' ' . $short_fileurl;
if (mb_strlen($content_shortened) > 140) {
$this->deleteFile($filename);
$this->clientError(_('Max notice size is 140 chars, including attachment URL.'));
}
// 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);
($replyto == 'false') ? null : $replyto,
null, null,
$lat, $lon, $location_id, $location_ns);
if (is_string($notice)) {
if (isset($filename)) {
$this->deleteFile($filename);
}
$this->clientError($notice);
}
if (isset($mimetype)) {
$this->attachFile($notice, $fileRecord);
if (isset($upload)) {
$upload->attachToNotice($notice);
}
common_broadcast_notice($notice);
@ -295,87 +223,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
*

View File

@ -104,7 +104,7 @@ class NoticesearchAction extends SearchAction
{
$notice = new Notice();
$search_engine = $notice->getSearchEngine('identica_notices');
$search_engine = $notice->getSearchEngine('notice');
$search_engine->set_sort_mode('chron');
// Ask for an extra to see if there's more.
$search_engine->limit((($page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
@ -121,9 +121,7 @@ class NoticesearchAction extends SearchAction
$message = sprintf(_('Be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
}
else {
$message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'),
(!common_config('site','openidonly')) ? 'register' : 'openidlogin',
urlencode($q));
$message = sprintf(_('Why not [register an account](%%%%action.register%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
}
$this->elementStart('div', 'guide');

View File

@ -62,7 +62,7 @@ class NoticesearchrssAction extends Rss10Action
$notice = new Notice();
$search_engine = $notice->getSearchEngine('identica_notices');
$search_engine = $notice->getSearchEngine('notice');
$search_engine->set_sort_mode('chron');
if (!$limit) $limit = 20;

View File

@ -75,7 +75,7 @@ class OpensearchAction extends Action
$this->element('Url', array('type' => 'text/html', 'method' => 'get',
'template' => str_replace('---', '{searchTerms}', common_local_url($type, array('q' => '---')))));
$this->element('Image', array('height' => 16, 'width' => 16, 'type' => 'image/vnd.microsoft.icon'), common_path('favicon.ico'));
$this->element('Image', array('height' => 50, 'width' => 50, 'type' => 'image/png'), theme_path('logo.png'));
$this->element('Image', array('height' => 50, 'width' => 50, 'type' => 'image/png'), Theme::path('logo.png'));
$this->element('AdultContent', null, 'false');
$this->element('Language', null, common_language());
$this->element('OutputEncoding', null, 'UTF-8');

View File

@ -96,27 +96,28 @@ class OthersettingsAction extends AccountSettingsAction
common_local_url('othersettings')));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
// I18N
$services = array(
'' => 'None',
'ur1.ca' => 'ur1.ca (free service)',
'2tu.us' => '2tu.us (free service)',
'ptiturl.com' => 'ptiturl.com',
'bit.ly' => 'bit.ly',
'tinyurl.com' => 'tinyurl.com',
'is.gd' => 'is.gd',
'snipr.com' => 'snipr.com',
'metamark.net' => 'metamark.net'
);
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
$this->dropdown('urlshorteningservice', _('Shorten URLs with'),
$services, _('Automatic shortening service to use.'),
false, $user->urlshorteningservice);
$this->elementEnd('li');
$shorteners = array();
Event::handle('GetUrlShorteners', array(&$shorteners));
$services = array();
foreach($shorteners as $name=>$value)
{
$services[$name]=$name;
if($value['freeService']){
$services[$name].=_(' (free service)');
}
}
if($services)
{
asort($services);
$this->elementStart('li');
$this->dropdown('urlshorteningservice', _('Shorten URLs with'),
$services, _('Automatic shortening service to use.'),
false, $user->urlshorteningservice);
$this->elementEnd('li');
}
$this->elementStart('li');
$this->checkbox('viewdesigns', _('View profile designs'),
$user->viewdesigns, _('Show or hide profile designs.'));

View File

@ -86,6 +86,7 @@ class PasswordsettingsAction extends AccountSettingsAction
function showContent()
{
$user = common_current_user();
$this->elementStart('form', array('method' => 'POST',
'id' => 'form_password',
'class' => 'form_settings',
@ -164,21 +165,28 @@ class PasswordsettingsAction extends AccountSettingsAction
$this->showForm(_('Incorrect old password'));
return;
}
}else{
$oldpassword = null;
}
$original = clone($user);
$success = false;
if(! Event::handle('StartChangePassword', array($user, $oldpassword, $newpassword))){
//no handler changed the password, so change the password internally
$original = clone($user);
$user->password = common_munge_password($newpassword, $user->id);
$user->password = common_munge_password($newpassword, $user->id);
$val = $user->validate();
if ($val !== true) {
$this->showForm(_('Error saving user; invalid.'));
return;
}
$val = $user->validate();
if ($val !== true) {
$this->showForm(_('Error saving user; invalid.'));
return;
}
if (!$user->update($original)) {
$this->serverError(_('Can\'t save new password.'));
return;
if (!$user->update($original)) {
$this->serverError(_('Can\'t save new password.'));
return;
}
Event::handle('EndChangePassword', array($user));
}
$this->showForm(_('Password saved.'), true);

320
actions/pathsadminpanel.php Normal file
View File

@ -0,0 +1,320 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Paths administration panel
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @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')) {
exit(1);
}
/**
* Paths settings
*
* @category Admin
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @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 PathsadminpanelAction extends AdminPanelAction
{
/**
* Returns the page title
*
* @return string page title
*/
function title()
{
return _('Paths');
}
/**
* Instructions for using this form.
*
* @return string instructions
*/
function getInstructions()
{
return _('Path and server settings for this StatusNet site.');
}
/**
* Show the paths admin panel form
*
* @return void
*/
function showForm()
{
$form = new PathsAdminPanelForm($this);
$form->show();
return;
}
/**
* Save settings from the form
*
* @return void
*/
function saveSettings()
{
static $settings = array(
'site' => array('path', 'locale_path'),
'theme' => array('server', 'dir', 'path'),
'avatar' => array('server', 'dir', 'path'),
'background' => array('server', 'dir', 'path')
);
$values = array();
foreach ($settings as $section => $parts) {
foreach ($parts as $setting) {
$values[$section][$setting] = $this->trimmed("$section-$setting");
}
}
$this->validate($values);
// assert(all values are valid);
$config = new Config();
$config->query('BEGIN');
foreach ($settings as $section => $parts) {
foreach ($parts as $setting) {
Config::save($section, $setting, $values[$section][$setting]);
}
}
$config->query('COMMIT');
return;
}
/**
* Attempt to validate setting values
*
* @return void
*/
function validate(&$values)
{
// Validate theme dir
if (!empty($values['theme']['dir']) && !is_readable($values['theme']['dir'])) {
$this->clientError(sprintf(_("Theme directory not readable: %s"), $values['theme']['dir']));
}
// Validate avatar dir
if (empty($values['avatar']['dir']) || !is_writable($values['avatar']['dir'])) {
$this->clientError(sprintf(_("Avatar directory not writable: %s"), $values['avatar']['dir']));
}
// Validate background dir
if (empty($values['background']['dir']) || !is_writable($values['background']['dir'])) {
$this->clientError(sprintf(_("Background directory not writable: %s"), $values['background']['dir']));
}
// Validate locales dir
// XXX: What else do we need to validate for lacales path here? --Z
if (!empty($values['site']['locale_path']) && !is_readable($values['site']['locale_path'])) {
$this->clientError(sprintf(_("Locales directory not readable: %s"), $values['site']['locale_path']));
}
}
}
class PathsAdminPanelForm extends AdminForm
{
/**
* ID of the form
*
* @return int ID of the form
*/
function id()
{
return 'form_paths_admin_panel';
}
/**
* class of the form
*
* @return string class of the form
*/
function formClass()
{
return 'form_settings';
}
/**
* Action of the form
*
* @return string URL of the action
*/
function action()
{
return common_local_url('pathsadminpanel');
}
/**
* Data elements of the form
*
* @return void
*/
function formData()
{
$this->out->elementStart('fieldset', array('id' => 'settings_paths_locale'));
$this->out->element('legend', null, _('Site'), 'site');
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('path', _('Path'), _('Site path'));
$this->unli();
$this->li();
$this->input('locale_path', _('Path to locales'), _('Directory path to locales'), 'site');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_paths_theme'));
$this->out->element('legend', null, _('Theme'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('server', _('Theme server'), 'Server for themes', 'theme');
$this->unli();
$this->li();
$this->input('path', _('Theme path'), 'Web path to themes', 'theme');
$this->unli();
$this->li();
$this->input('dir', _('Theme directory'), 'Directory where themes are located', 'theme');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_avatar-paths'));
$this->out->element('legend', null, _('Avatars'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('server', _('Avatar server'), 'Server for avatars', 'avatar');
$this->unli();
$this->li();
$this->input('path', _('Avatar path'), 'Web path to avatars', 'avatar');
$this->unli();
$this->li();
$this->input('dir', _('Avatar directory'), 'Directory where avatars are located', 'avatar');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' =>
'settings_design_background-paths'));
$this->out->element('legend', null, _('Backgrounds'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('server', _('Background server'), 'Server for backgrounds', 'background');
$this->unli();
$this->li();
$this->input('path', _('Background path'), 'Web path to backgrounds', 'background');
$this->unli();
$this->li();
$this->input('dir', _('Background directory'), 'Directory where backgrounds are located', 'background');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
}
/**
* Action elements
*
* @return void
*/
function formActions()
{
$this->out->submit('save', _('Save'), 'submit form_action-secondary',
'save', _('Save paths'));
}
/**
* Utility to simplify some of the duplicated code around
* params and settings. Overriding the input() in the base class
* to handle a whole bunch of cases of settings with the same
* name under different sections.
*
* @param string $setting Name of the setting
* @param string $title Title to use for the input
* @param string $instructions Instructions for this field
* @param string $section config section, default = 'site'
*
* @return void
*/
function input($setting, $title, $instructions, $section='site')
{
$this->out->input("$section-$setting", $title, $this->value($setting, $section), $instructions);
}
}

View File

@ -61,7 +61,7 @@ class PeoplesearchAction extends SearchAction
function showResults($q, $page)
{
$profile = new Profile();
$search_engine = $profile->getSearchEngine('identica_people');
$search_engine = $profile->getSearchEngine('profile');
$search_engine->set_sort_mode('chron');
// Ask for an extra to see if there's more.
$search_engine->limit((($page-1)*PROFILES_PER_PAGE), PROFILES_PER_PAGE + 1);

View File

@ -1,5 +1,16 @@
<?php
/*
/**
* Handle postnotice action
*
* 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.
*
@ -19,73 +30,67 @@
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/omb.php');
require_once INSTALLDIR.'/lib/omb.php';
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
/**
* Handler for postnotice action
*
* @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/
*/
class PostnoticeAction extends Action
{
/**
* For initializing members of the class.
*
* @param array $argarray misc. arguments
*
* @return boolean true
*/
function prepare($argarray)
{
parent::prepare($argarray);
try {
$this->checkNotice();
} catch (Exception $e) {
$this->clientError($e->getMessage());
return false;
}
return true;
}
function handle($args)
{
parent::handle($args);
try {
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('postnotice'));
# Note: server-to-server function!
$server = omb_oauth_server();
list($consumer, $token) = $server->verify_request($req);
if ($this->save_notice($req, $consumer, $token)) {
print "omb_version=".OMB_VERSION_01;
}
} catch (OAuthException $e) {
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
omb_oauth_server());
$srv->handlePostNotice();
} catch (Exception $e) {
$this->serverError($e->getMessage());
return;
}
}
function save_notice(&$req, &$consumer, &$token)
function checkNotice()
{
$version = $req->get_parameter('omb_version');
if ($version != OMB_VERSION_01) {
$this->clientError(_('Unsupported OMB version'), 400);
return false;
}
# First, check to see
$listenee = $req->get_parameter('omb_listenee');
$remote_profile = Remote_profile::staticGet('uri', $listenee);
if (!$remote_profile) {
$this->clientError(_('Profile unknown'), 403);
return false;
}
$sub = Subscription::staticGet('token', $token->key);
if (!$sub) {
$this->clientError(_('No such subscription'), 403);
return false;
}
$content = $req->get_parameter('omb_notice_content');
$content_shortened = common_shorten_links($content);
if (mb_strlen($content_shortened) > 140) {
$content = common_shorten_links($_POST['omb_notice_content']);
if (Notice::contentTooLong($content)) {
$this->clientError(_('Invalid notice content'), 400);
return false;
}
$notice_uri = $req->get_parameter('omb_notice');
if (!Validate::uri($notice_uri) &&
!common_valid_tag($notice_uri)) {
$this->clientError(_('Invalid notice uri'), 400);
return false;
$license = $_POST['omb_notice_license'];
$site_license = common_config('license', 'url');
if ($license && !common_compatible_license($license, $site_license)) {
throw new Exception(sprintf(_('Notice license %s is not ' .
'compatible with site license %s.'),
$license, $site_license));
}
$notice_url = $req->get_parameter('omb_notice_url');
if ($notice_url && !common_valid_http_url($notice_url)) {
$this->clientError(_('Invalid notice url'), 400);
return false;
}
$notice = Notice::staticGet('uri', $notice_uri);
if (!$notice) {
$notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri);
if (is_string($notice)) {
common_server_serror($notice, 500);
return false;
}
common_broadcast_notice($notice, true);
}
return true;
}
}
?>

View File

@ -117,9 +117,16 @@ class ProfilesettingsAction extends AccountSettingsAction
_('URL of your homepage, blog, or profile on another site'));
$this->elementEnd('li');
$this->elementStart('li');
$maxBio = Profile::maxBio();
if ($maxBio > 0) {
$bioInstr = sprintf(_('Describe yourself and your interests in %d chars'),
$maxBio);
} else {
$bioInstr = _('Describe yourself and your interests');
}
$this->textarea('bio', _('Bio'),
($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
_('Describe yourself and your interests in 140 chars'));
$bioInstr);
$this->elementEnd('li');
$this->elementStart('li');
$this->input('location', _('Location'),
@ -210,8 +217,9 @@ class ProfilesettingsAction extends AccountSettingsAction
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).'));
return;
} else if (!is_null($bio) && mb_strlen($bio) > 140) {
$this->showForm(_('Bio is too long (max 140 chars).'));
} else if (Profile::bioTooLong($bio)) {
$this->showForm(sprintf(_('Bio is too long (max %d chars).'),
Profile::maxBio()));
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).'));
@ -298,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__);
@ -305,7 +323,7 @@ class ProfilesettingsAction extends AccountSettingsAction
$result = $profile->update($orig_profile);
if (!$result) {
if ($result === false) {
common_log_db_error($profile, 'UPDATE', __FILE__);
$this->serverError(_('Couldn\'t save profile.'));
return;

View File

@ -114,8 +114,6 @@ class PublicAction extends Action
{
parent::handle($args);
header('X-XRDS-Location: '. common_local_url('publicxrds'));
$this->showPage();
}
@ -134,6 +132,13 @@ class PublicAction extends Action
}
}
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
*
@ -145,33 +150,15 @@ 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)')));
}
/**
* Extra head elements
*
* We include a <meta> element linking to the publicxrds page, for OpenID
* client-side authentication.
*
* @return void
*/
function extraHead()
{
// for client side of OpenID authentication
$this->element('meta', array('http-equiv' => 'X-XRDS-Location',
'content' => common_local_url('publicxrds')));
}
/**
* Show tabset for this page
*
@ -196,8 +183,7 @@ class PublicAction extends Action
}
else {
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post!'),
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
$message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
}
}
@ -244,11 +230,10 @@ class PublicAction extends Action
function showAnonymousMessage()
{
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
$m = sprintf(_('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
'based on the Free Software [StatusNet](http://status.net/) tool. ' .
'[Join now](%%%%action.%s%%%%) to share notices about yourself with friends, family, and colleagues! ' .
'([Read more](%%%%doc.help%%%%))'),
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
'based on the Free Software [StatusNet](http://status.net/) tool. ' .
'[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ' .
'([Read more](%%doc.help%%))');
} else {
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
'based on the Free Software [StatusNet](http://status.net/) tool.');

View File

@ -49,6 +49,20 @@ require_once INSTALLDIR.'/lib/rssaction.php';
*/
class PublicrssAction extends Rss10Action
{
/**
* Read arguments and initialize members
*
* @param array $args Arguments from $_REQUEST
* @return boolean success
*/
function prepare($args)
{
parent::prepare($args);
$this->notices = $this->getNotices($this->limit);
return true;
}
/**
* Initialization.
*

View File

@ -72,8 +72,7 @@ class PublictagcloudAction extends Action
$message .= _('Be the first to post one!');
}
else {
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post one!'),
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
$message .= _('Why not [register an account](%%action.register%%) and be the first to post one!');
}
$this->elementStart('div', 'guide');

View File

@ -33,15 +33,17 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/openid.php';
require_once INSTALLDIR.'/plugins/OpenID/openid.php';
require_once INSTALLDIR.'/lib/xrdsoutputter.php';
/**
* Public XRDS for OpenID
* 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/
*
@ -69,54 +71,11 @@ class PublicxrdsAction extends Action
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');
$this->elementEnd('XRDS');
$this->endXML();
}
/**
* Show service.
*
* @param string $type XRDS type
* @param string $uri URI
* @param array $params type parameters, null by default
* @param array $sigs type signatures, null by default
* @param string $localId local ID, null by default
*
* @return void
*/
function showService($type, $uri, $params=null, $sigs=null, $localId=null)
{
$this->elementStart('Service');
if ($uri) {
$this->element('URI', null, $uri);
}
$this->element('Type', null, $type);
if ($params) {
foreach ($params as $param) {
$this->element('Type', null, $param);
}
}
if ($sigs) {
foreach ($sigs as $sig) {
$this->element('Type', null, $sig);
}
}
if ($localId) {
$this->element('LocalID', null, $localId);
}
$this->elementEnd('Service');
$xrdsOutputter = new XRDSOutputter();
$xrdsOutputter->startXRDS();
Event::handle('StartPublicXRDS', array($this,&$xrdsOutputter));
Event::handle('EndPublicXRDS', array($this,&$xrdsOutputter));
$xrdsOutputter->endXRDS();
}
}

View File

@ -149,13 +149,13 @@ class RecoverpasswordAction extends Action
$this->elementStart('div', 'instructions');
if ($this->mode == 'recover') {
$this->element('p', null,
_('If you\'ve forgotten or lost your' .
_('If you have forgotten or lost your' .
' password, you can get a new one sent to' .
' the email address you have stored' .
' in your account.'));
} else if ($this->mode == 'reset') {
$this->element('p', null,
_('You\'ve been identified. Enter a' .
_('You have been identified. Enter a' .
' new password below. '));
}
$this->elementEnd('div');
@ -185,10 +185,10 @@ class RecoverpasswordAction extends Action
'class' => 'form_settings',
'action' => common_local_url('recoverpassword')));
$this->elementStart('fieldset');
$this->element('legend', null, _('Password recover'));
$this->element('legend', null, _('Password recovery'));
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
$this->input('nicknameoremail', _('Nickname or email'),
$this->input('nicknameoremail', _('Nickname or email address'),
$this->trimmed('nicknameoremail'),
_('Your nickname on this server, ' .
'or your registered email address.'));

View File

@ -55,6 +55,12 @@ class RegisterAction extends Action
var $registered = false;
/**
* Are we processing an invite?
*/
var $invite = null;
/**
* Prepare page to run
*
@ -116,8 +122,6 @@ class RegisterAction extends Action
*
* Checks if registration is closed and shows an error if so.
*
* Checks if only OpenID is allowed and redirects to openidlogin if so.
*
* @param array $args $_REQUEST data
*
* @return void
@ -129,8 +133,6 @@ class RegisterAction extends Action
if (common_config('site', 'closed')) {
$this->clientError(_('Registration not allowed.'));
} else if (common_config('site', 'openidonly')) {
common_redirect(common_local_url('openidlogin'));
} else if (common_logged_in()) {
$this->clientError(_('Already logged in.'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
@ -195,7 +197,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,
@ -217,8 +219,9 @@ class RegisterAction extends Action
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).'));
return;
} else if (!is_null($bio) && mb_strlen($bio) > 140) {
$this->showForm(_('Bio is too long (max 140 chars).'));
} else if (Profile::bioTooLong($bio)) {
$this->showForm(sprintf(_('Bio is too long (max %d chars).'),
Profile::maxBio()));
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).'));
@ -335,22 +338,11 @@ class RegisterAction extends Action
} else if ($this->error) {
$this->element('p', 'error', $this->error);
} else {
if (common_config('openid', 'enabled')) {
$instr =
common_markup_to_html(_('With this form you can create '.
' a new account. ' .
'You can then post notices and '.
'link up to friends and colleagues. '.
'(Have an [OpenID](http://openid.net/)? ' .
'Try our [OpenID registration]'.
'(%%action.openidlogin%%)!)'));
} else {
$instr =
common_markup_to_html(_('With this form you can create '.
' a new account. ' .
'You can then post notices and '.
'link up to friends and colleagues.'));
}
$instr =
common_markup_to_html(_('With this form you can create '.
' a new account. ' .
'You can then post notices and '.
'link up to friends and colleagues. '));
$this->elementStart('div', 'instructions');
$this->raw($instr);
@ -463,10 +455,16 @@ class RegisterAction extends Action
'or profile on another site'));
$this->elementEnd('li');
$this->elementStart('li');
$maxBio = Profile::maxBio();
if ($maxBio > 0) {
$bioInstr = sprintf(_('Describe yourself and your interests in %d chars'),
$maxBio);
} else {
$bioInstr = _('Describe yourself and your interests');
}
$this->textarea('bio', _('Bio'),
$this->trimmed('bio'),
_('Describe yourself and your '.
'interests in 140 chars'));
$bioInstr);
$this->elementEnd('li');
$this->elementStart('li');
$this->input('location', _('Location'),

View File

@ -1,5 +1,16 @@
<?php
/*
/**
* Handler for remote subscription
*
* 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.
*
@ -15,11 +26,24 @@
*
* 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.'/lib/omb.php');
require_once INSTALLDIR.'/lib/omb.php';
require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
require_once INSTALLDIR.'/extlib/libomb/profile.php';
/**
* Handler for remote subscription
*
* @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/
*/
class RemotesubscribeAction extends Action
{
@ -36,7 +60,7 @@ class RemotesubscribeAction extends Action
return false;
}
$this->nickname = $this->trimmed('nickname');
$this->nickname = $this->trimmed('nickname');
$this->profile_url = $this->trimmed('profile_url');
return true;
@ -47,7 +71,7 @@ class RemotesubscribeAction extends Action
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
# CSRF protection
/* Use a session token for CSRF protection. */
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->showForm(_('There was a problem with your session token. '.
@ -71,13 +95,11 @@ class RemotesubscribeAction extends Action
if ($this->err) {
$this->element('div', 'error', $this->err);
} else {
$inst = sprintf(_('To subscribe, you can [login](%%%%action.%s%%%%),' .
' or [register](%%%%action.%s%%%%) a new ' .
' account. If you already have an account ' .
' on a [compatible microblogging site](%%doc.openmublog%%), ' .
' enter your profile URL below.'),
(!common_config('site','openidonly')) ? 'login' : 'openidlogin',
(!common_config('site','openidonly')) ? 'register' : 'openidlogin');
$inst = _('To subscribe, you can [login](%%action.login%%),' .
' or [register](%%action.register%%) a new ' .
' account. If you already have an account ' .
' on a [compatible microblogging site](%%doc.openmublog%%), ' .
' enter your profile URL below.');
$output = common_markup_to_html($inst);
$this->elementStart('div', 'instructions');
$this->raw($output);
@ -92,8 +114,8 @@ class RemotesubscribeAction extends Action
function showContent()
{
# id = remotesubscribe conflicts with the
# button on profile page
/* The id 'remotesubscribe' conflicts with the
button on profile page. */
$this->elementStart('form', array('id' => 'form_remote_subscribe',
'method' => 'post',
'class' => 'form_settings',
@ -119,13 +141,13 @@ class RemotesubscribeAction extends Action
function remoteSubscription()
{
$user = $this->getUser();
if (!$user) {
if (!$this->nickname) {
$this->showForm(_('No such user.'));
return;
}
$user = User::staticGet('nickname', $this->nickname);
$this->profile_url = $this->trimmed('profile_url');
if (!$this->profile_url) {
@ -133,233 +155,36 @@ class RemotesubscribeAction extends Action
return;
}
if (!Validate::uri($this->profile_url, array('allowed_schemes' => array('http', 'https')))) {
if (!common_valid_http_url($this->profile_url)) {
$this->showForm(_('Invalid profile URL (bad format)'));
return;
}
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$yadis = Auth_Yadis_Yadis::discover($this->profile_url, $fetcher);
if (!$yadis || $yadis->failed) {
$this->showForm(_('Not a valid profile URL (no YADIS document).'));
try {
$service = new OMB_Service_Consumer($this->profile_url,
common_root_url(),
omb_oauth_datastore());
} catch (OMB_InvalidYadisException $e) {
$this->showForm(_('Not a valid profile URL (no YADIS document or ' .
'no or invalid XRDS defined).'));
return;
}
# XXX: a little liberal for sites that accidentally put whitespace before the xml declaration
$xrds =& Auth_Yadis_XRDS::parseXRDS(trim($yadis->response_text));
if (!$xrds) {
$this->showForm(_('Not a valid profile URL (no XRDS defined).'));
if ($service->getServiceURI(OAUTH_ENDPOINT_REQUEST) ==
common_local_url('requesttoken') ||
User::staticGet('uri', $service->getRemoteUserURI())) {
$this->showForm(_('Thats a local profile! Login to subscribe.'));
return;
}
$omb = $this->getOmb($xrds);
if (!$omb) {
$this->showForm(_('Not a valid profile URL (incorrect services).'));
try {
$service->requestToken();
} catch (OMB_RemoteServiceException $e) {
$this->showForm(_('Couldnt get a request token.'));
return;
}
if (omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]) ==
common_local_url('requesttoken'))
{
$this->showForm(_('That\'s a local profile! Login to subscribe.'));
return;
}
if (User::staticGet('uri', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]))) {
$this->showForm(_('That\'s a local profile! Login to subscribe.'));
return;
}
list($token, $secret) = $this->requestToken($omb);
if (!$token || !$secret) {
$this->showForm(_('Couldn\'t get a request token.'));
return;
}
$this->requestAuthorization($user, $omb, $token, $secret);
}
function getUser()
{
$user = null;
if ($this->nickname) {
$user = User::staticGet('nickname', $this->nickname);
}
return $user;
}
function getOmb($xrds)
{
static $omb_endpoints = array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE);
static $oauth_endpoints = array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE,
OAUTH_ENDPOINT_ACCESS);
$omb = array();
# XXX: the following code could probably be refactored to eliminate dupes
$oauth_services = omb_get_services($xrds, OAUTH_DISCOVERY);
if (!$oauth_services) {
return null;
}
$oauth_service = $oauth_services[0];
$oauth_xrd = $this->getXRD($oauth_service, $xrds);
if (!$oauth_xrd) {
return null;
}
if (!$this->addServices($oauth_xrd, $oauth_endpoints, $omb)) {
return null;
}
$omb_services = omb_get_services($xrds, OMB_NAMESPACE);
if (!$omb_services) {
return null;
}
$omb_service = $omb_services[0];
$omb_xrd = $this->getXRD($omb_service, $xrds);
if (!$omb_xrd) {
return null;
}
if (!$this->addServices($omb_xrd, $omb_endpoints, $omb)) {
return null;
}
# XXX: check that we got all the services we needed
foreach (array_merge($omb_endpoints, $oauth_endpoints) as $type) {
if (!array_key_exists($type, $omb) || !$omb[$type]) {
return null;
}
}
if (!omb_local_id($omb[OAUTH_ENDPOINT_REQUEST])) {
return null;
}
return $omb;
}
function getXRD($main_service, $main_xrds)
{
$uri = omb_service_uri($main_service);
if (strpos($uri, "#") !== 0) {
# FIXME: more rigorous handling of external service definitions
return null;
}
$id = substr($uri, 1);
$nodes = $main_xrds->allXrdNodes;
$parser = $main_xrds->parser;
foreach ($nodes as $node) {
$attrs = $parser->attributes($node);
if (array_key_exists('xml:id', $attrs) &&
$attrs['xml:id'] == $id) {
# XXX: trick the constructor into thinking this is the only node
$bogus_nodes = array($node);
return new Auth_Yadis_XRDS($parser, $bogus_nodes);
}
}
return null;
}
function addServices($xrd, $types, &$omb)
{
foreach ($types as $type) {
$matches = omb_get_services($xrd, $type);
if ($matches) {
$omb[$type] = $matches[0];
} else {
# no match for type
return false;
}
}
return true;
}
function requestToken($omb)
{
$con = omb_oauth_consumer();
$url = omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]);
# XXX: Is this the right thing to do? Strip off GET params and make them
# POST params? Seems wrong to me.
$parsed = parse_url($url);
$params = array();
parse_str($parsed['query'], $params);
$req = OAuthRequest::from_consumer_and_token($con, null, "POST", $url, $params);
$listener = omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]);
if (!$listener) {
return null;
}
$req->set_parameter('omb_listener', $listener);
$req->set_parameter('omb_version', OMB_VERSION_01);
# XXX: test to see if endpoint accepts this signature method
$req->sign_request(omb_hmac_sha1(), $con, null);
# We re-use this tool's fetcher, since it's pretty good
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(),
array('User-Agent: StatusNet/' . STATUSNET_VERSION));
if ($result->status != 200) {
return null;
}
parse_str($result->body, $return);
return array($return['oauth_token'], $return['oauth_token_secret']);
}
function requestAuthorization($user, $omb, $token, $secret)
{
$con = omb_oauth_consumer();
$tok = new OAuthToken($token, $secret);
$url = omb_service_uri($omb[OAUTH_ENDPOINT_AUTHORIZE]);
# XXX: Is this the right thing to do? Strip off GET params and make them
# POST params? Seems wrong to me.
$parsed = parse_url($url);
$params = array();
parse_str($parsed['query'], $params);
$req = OAuthRequest::from_consumer_and_token($con, $tok, 'GET', $url, $params);
# We send over a ton of information. This lets the other
# server store info about our user, and it lets the current
# user decide if they really want to authorize the subscription.
$req->set_parameter('omb_version', OMB_VERSION_01);
$req->set_parameter('omb_listener', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]));
$req->set_parameter('omb_listenee', $user->uri);
$req->set_parameter('omb_listenee_profile', common_profile_url($user->nickname));
$req->set_parameter('omb_listenee_nickname', $user->nickname);
$req->set_parameter('omb_listenee_license', common_config('license', 'url'));
/* Create an OMB_Profile from $user. */
$profile = $user->getProfile();
if (!$profile) {
common_log_db_error($user, 'SELECT', __FILE__);
@ -367,49 +192,16 @@ class RemotesubscribeAction extends Action
return;
}
if (!is_null($profile->fullname)) {
$req->set_parameter('omb_listenee_fullname', $profile->fullname);
}
if (!is_null($profile->homepage)) {
$req->set_parameter('omb_listenee_homepage', $profile->homepage);
}
if (!is_null($profile->bio)) {
$req->set_parameter('omb_listenee_bio', $profile->bio);
}
if (!is_null($profile->location)) {
$req->set_parameter('omb_listenee_location', $profile->location);
}
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
if ($avatar) {
$req->set_parameter('omb_listenee_avatar', $avatar->url);
}
# XXX: add a nonce to prevent replay attacks
$req->set_parameter('oauth_callback', common_local_url('finishremotesubscribe'));
# XXX: test to see if endpoint accepts this signature method
$req->sign_request(omb_hmac_sha1(), $con, $tok);
# store all our info here
$omb['listenee'] = $user->nickname;
$omb['listener'] = omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]);
$omb['token'] = $token;
$omb['secret'] = $secret;
# call doesn't work after bounce back so we cache; maybe serialization issue...?
$omb['access_token_url'] = omb_service_uri($omb[OAUTH_ENDPOINT_ACCESS]);
$omb['post_notice_url'] = omb_service_uri($omb[OMB_ENDPOINT_POSTNOTICE]);
$omb['update_profile_url'] = omb_service_uri($omb[OMB_ENDPOINT_UPDATEPROFILE]);
$target_url = $service->requestAuthorization(
profile_to_omb_profile($user->uri, $profile),
common_local_url('finishremotesubscribe'));
common_ensure_session();
$_SESSION['oauth_authorization_request'] = $omb;
$_SESSION['oauth_authorization_request'] = serialize($service);
# Redirect to authorization service
common_redirect($req->to_url(), 303);
return;
/* Redirect to the remote service for authorization. */
common_redirect($target_url, 303);
}
}
?>

View File

@ -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)));
}
/**
@ -192,9 +206,7 @@ class RepliesAction extends OwnerDesignAction
}
}
else {
$message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'),
(!common_config('site','openidonly')) ? 'register' : 'openidlogin',
$this->user->nickname);
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
}
$this->elementStart('div', 'guide');

View File

@ -38,6 +38,7 @@ class RepliesrssAction extends Rss10Action
$this->clientError(_('No such user.'));
return false;
} else {
$this->notices = $this->getNotices($this->limit);
return true;
}
}

View File

@ -34,6 +34,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
}
require_once INSTALLDIR.'/lib/omb.php';
require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
/**
* Request token action class.
@ -52,7 +53,7 @@ class RequesttokenAction extends Action
*
* @return boolean false
*/
function isReadOnly($args)
function isReadOnly()
{
return false;
}
@ -68,14 +69,12 @@ class RequesttokenAction extends Action
{
parent::handle($args);
try {
common_remove_magic_from_request();
$req = OAuthRequest::from_request('POST', common_local_url('requesttoken'));
$server = omb_oauth_server();
$token = $server->fetch_request_token($req);
print $token.'&omb_version='.OMB_VERSION_01;
} catch (OAuthException $e) {
$srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
omb_oauth_server());
$srv->writeRequestToken();
} catch (Exception $e) {
$this->serverError($e->getMessage());
}
}
}
?>

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