Merge branch '1.0.x' of git://gitorious.org/statusnet/mainline

Conflicts:
	lib/action.php
	plugins/OStatus/actions/ostatusinit.php
This commit is contained in:
Ian Denhardt 2010-12-20 15:17:31 -05:00
commit e36399974e
2139 changed files with 307974 additions and 86695 deletions

2
.gitignore vendored
View File

@ -25,3 +25,5 @@ good-config.php
lac08.log lac08.log
php.log php.log
.DS_Store .DS_Store
nbproject
*.mo

View File

@ -118,16 +118,16 @@ EndShowHTML: Showing after the html element
- $action: the current action - $action: the current action
StartPublicGroupNav: Showing the public group nav menu StartPublicGroupNav: Showing the public group nav menu
- $action: the current action - $menu: the menu widget; use $menu->action for output
EndPublicGroupNav: At the end of the public group nav menu EndPublicGroupNav: At the end of the public group nav menu
- $action: the current action - $menu: the menu widget; use $menu->action for output
StartSubGroupNav: Showing the subscriptions group nav menu StartSubGroupNav: Showing the subscriptions group nav menu
- $action: the current action - $menu: the menu widget; use $menu->action for output
EndSubGroupNav: At the end of the subscriptions group nav menu EndSubGroupNav: At the end of the subscriptions group nav menu
- $action: the current action - $menu: the menu widget; use $menu->action for output
StartInitializeRouter: Before the router instance has been initialized; good place to add routes StartInitializeRouter: Before the router instance has been initialized; good place to add routes
- $m: the Net_URL_Mapper that has just been set up - $m: the Net_URL_Mapper that has just been set up
@ -258,10 +258,28 @@ EndShowExportData: just after showing the <div> with export data (feeds)
- $action: action object being shown - $action: action object being shown
StartShowNoticeItem: just before showing the notice item StartShowNoticeItem: just before showing the notice item
- $action: action object being shown - $item: The NoticeListItem object being shown
EndShowNoticeItem: just after showing the notice item EndShowNoticeItem: just after showing the notice item
- $action: action object being shown - $item: the NoticeListItem object being shown
StartShowNoticeInfo: just before showing notice info
- $item: The NoticeListItem object being shown
EndShowNoticeInfo: just after showing notice info
- $item: The NoticeListItem object being shown
StartShowNoticeOptions: just before showing notice options like fave, repeat, etc.
- $item: the NoticeListItem object being shown
EndShowNoticeOptions: just after showing notice options like fave, repeat, etc.
- $item: the NoticeListItem object being shown
StartShowFaveForm: just before showing the fave form
- $item: the NoticeListItem object being shown
EndShowFaveForm: just after showing the fave form
- $item: the NoticeListItem object being shown
StartShowPageNotice: just before showing the page notice (instructions or error) StartShowPageNotice: just before showing the page notice (instructions or error)
- $action: action object being shown - $action: action object being shown
@ -284,6 +302,20 @@ StartProfileSaveForm: before starting to save a profile settings form
EndProfileSaveForm: after saving a profile settings form (after commit, no profile or user object!) EndProfileSaveForm: after saving a profile settings form (after commit, no profile or user object!)
- $action: action object being shown - $action: action object being shown
StartEmailFormData: just before showing text entry fields on email settings page
- $action: action object being shown
EndEmailFormData: just after showing text entry fields on email settings page
- $action: action object being shown
StartEmailSaveForm: before starting to save a email settings form
- $action: action object being shown
- &$user: user being saved
EndEmailSaveForm: after saving a email settings form (after commit)
- $action: action object being shown
- &$user: user being saved
StartRegistrationFormData: just before showing text entry fields on registration page StartRegistrationFormData: just before showing text entry fields on registration page
- $action: action object being shown - $action: action object being shown
@ -347,6 +379,14 @@ GetValidDaemons: Just before determining which daemons to run
HandleQueuedNotice: Handle a queued notice at queue time (or immediately if no queue) HandleQueuedNotice: Handle a queued notice at queue time (or immediately if no queue)
- &$notice: notice to handle - &$notice: notice to handle
StartHtmlElement: Reight before outputting the HTML element - allows plugins to add namespaces
- $action: the current action
- &$attrs: attributes for the HTML element
EndHtmlElement: Right after outputting the HTML element
- $action: the current action
- &$attrs: attributes for the HTML element
StartShowHeadElements: Right after the <head> tag StartShowHeadElements: Right after the <head> tag
- $action: the current action - $action: the current action
@ -551,6 +591,12 @@ EndPublicXRDS: End XRDS output (right before the closing XRDS tag)
- $action: the current action - $action: the current action
- &$xrdsoutputter - XRDSOutputter object to write to - &$xrdsoutputter - XRDSOutputter object to write to
StartHostMetaLinks: Start /.well-known/host-meta links
- &links: array containing the links elements to be written
EndHostMetaLinks: End /.well-known/host-meta links
- &links: array containing the links elements to be written
StartCheckPassword: Check a username/password StartCheckPassword: Check a username/password
- $nickname: The nickname to check - $nickname: The nickname to check
- $password: The password to check - $password: The password to check
@ -774,6 +820,22 @@ EndDisfavorNotice: After saving a notice as a favorite
- $profile: profile of the person faving (can be remote!) - $profile: profile of the person faving (can be remote!)
- $notice: notice being faved - $notice: notice being faved
StartFavorNoticeForm: starting the data in the form for favoring a notice
- $FavorForm: the favor form being shown
- $notice: notice being favored
EndFavorNoticeForm: Ending the data in the form for favoring a notice
- $FavorForm: the favor form being shown
- $notice: notice being favored
StartDisFavorNoticeForm: starting the data in the form for disfavoring a notice
- $DisfavorForm: the disfavor form being shown
- $notice: notice being difavored
EndDisFavorNoticeForm: Ending the data in the form for disfavoring a notice
- $DisfavorForm: the disfavor form being shown
- $notice: notice being disfavored
StartFindMentions: start finding mentions in a block of text StartFindMentions: start finding mentions in a block of text
- $sender: sender profile - $sender: sender profile
- $text: plain text version of the notice - $text: plain text version of the notice
@ -836,230 +898,122 @@ EndDeleteUser: handling the post for deleting a user
- $action: action being shown - $action: action being shown
- $user: user being deleted - $user: user being deleted
StartActivityStart: starting the output for a notice activity <event> StartNoticeAsActivity: before converting a notice to an activity
- &$notice: notice being output - $notice: notice being converted
- &$xs: XMLStringer for output - &$activity: initially empty activity
- &$attrs: <entry> attributes (mostly namespace declarations, if any)
EndActivityStart: end the opening tag for an activity <event> EndNoticeAsActivity: after converting a notice to an activity (good time to customize!)
- &$notice: notice being output - $notice: notice being converted
- &$xs: XMLStringer for output - &$activity: activity, now more-or-less full
- $attrs: <entry> attributes (mostly namespace declarations, if any)
StartActivitySource: before outputting the <source> element for a notice activity StartNoticeSaveWeb: before saving a notice through the Web interface
- &$notice: notice being output - $action: action being executed (instance of NewNoticeAction)
- &$xs: XMLStringer for output - &$authorId: integer ID of the author
- &$text: text of the notice
- &$options: additional options (location, replies, etc.)
EndActivitySource: after outputting the <source> element for a notice activity EndNoticeSaveWeb: after saving a notice through the Web interface
- &$notice: notice being output - $action: action being executed (instance of NewNoticeAction)
- &$xs: XMLStringer for output - $notice: notice that was saved
StartActivityTitle: before outputting notice activity title StartRssEntryArray: at the start of copying a notice to an array
- &$notice: notice being output - $notice: the notice being copied
- &$xs: XMLStringer for output - &$entry: the entry (empty at beginning)
- &$title: title of the notice, mutable
EndActivityTitle: after outputting notice activity title EndRssEntryArray: at the end of copying a notice to an array
- $notice: notice being output - $notice: the notice being copied
- &$xs: XMLStringer for output - &$entry: the entry, with all the fields filled up
- $title: title of the notice
StartActivityAuthor: before outputting atom author NoticeDeleteRelated: at the beginning of deleting related fields to a notice
- &$notice: notice being output - $notice: notice being deleted
- &$xs: XMLStringer for output
- &$atomAuthor: string for XML representing atom author
EndActivityAuthor: after outputting atom author StartShowHeadTitle: when beginning to show the <title> element
- &$notice: notice being output - $action: action being shown
- &$xs: XMLStringer for output
- &$atomAuthor: string for XML representing atom author
StartActivityActor: before outputting activity actor element for a notice activity entry EndShowHeadTitle: when done showing the <title>
- &$notice: notice being output - $action: action being shown
- &$xs: XMLStringer for output
- &$actor: string for XML representing activity actor
EndActivityActor: after outputting activity actor element for a notice activity entry StartShowPageTitle: when beginning to show the page title <h1>
- &$notice: notice being output - $action: action being shown
- &$xs: XMLStringer for output
- &$actor: string for XML representing activity actor
StartActivityLink: before outputting activity HTML link element for a notice activity entry EndShowPageTitle: when done showing the page title <h1>
- &$notice: notice being output - $action: action being shown
- &$xs: XMLStringer for output
- &$url: URL for activity HTML link element for a notice activity entry
EndActivityLink: before outputting activity HTML link element for a notice activity entry StartDeleteOwnNotice: when a user starts to delete their own notice
- &$notice: notice being output - $user: the user doing the delete
- &$xs: XMLStringer for output - $notice: the notice being deleted
- $url: URL for activity HTML link element for a notice activity entry
StartActivityId: before outputting atom:id element for a notice activity entry EndDeleteOwnNotice: when a user has deleted their own notice
- &$notice: notice being output - $user: the user doing the delete
- &$xs: XMLStringer for output - $notice: the notice being deleted
- &$id: atom:id (notice URI by default)
EndActivityId: after outputting atom:id element for a notice activity entry StartShowFeedLinkList: before showing the feed list in the sidebar
- &$notice: notice being output - $action: action being executed
- &$xs: XMLStringer for output - $feeds: list of feeds to show
- $id: atom:id (notice URI by default)
StartActivityPublished: before outputting atom:published element for a notice activity entry EndShowFeedLinkList: after showing the feed list in the sidebar
- &$notice: notice being output - $action: action being executed
- &$xs: XMLStringer for output - $feeds: list of feeds shown
- &$published: atom:published value (notice created by default)
EndActivityPublished: before outputting atom:published element for a notice activity entry StartShowFeedLink: before showing an individual feed item
- &$notice: notice being output - $action: action being executed
- &$xs: XMLStringer for output - $feed: feed to show
- $published: atom:published value (notice created by default)
StartActivityUpdated: before outputting atom:updated element for a notice activity entry EndShowFeedLink: after showing an individual feed
- &$notice: notice being output - $action: action being executed
- &$xs: XMLStringer for output - $feed: feed to show
- &$updated: atom:updated value (same as atom:published by default)
EndActivityUpdated: after outputting atom:updated element for a notice activity entry StartShowNoticeForm: before showing the notice form (before <form>)
- &$notice: notice being output - $action: action being executed
- &$xs: XMLStringer for output
- $updated: atom:updated value (same as atom:published by default)
StartActivityContent: before outputting atom:content element for a notice activity entry EndShowNoticeForm: after showing the notice form (after <form>)
- &$notice: notice being output - $action: action being executed
- &$xs: XMLStringer for output
- &$content: atom:content value (notice rendered HTML by default)
EndActivityContent: after outputting atom:content element for a notice activity entry StartGrantRole: when a role is being assigned
- &$notice: notice being output - $profile: profile that will have the role
- &$xs: XMLStringer for output - $role: string name of the role
- $content: atom:content value (notice rendered HTML by default)
StartActivityVerb: before outputting activity:verb element for a notice activity entry EndGrantRole: when a role has been successfully assigned
- &$notice: notice being output - $profile: profile that will have the role
- &$xs: XMLStringer for output - $role: string name of the role
- &$verb: activity:verb URI ('http://activitystrea.ms/schema/1.0/post' by default)
EndActivityVerb: after outputting activity:verb element for a notice activity entry StartRevokeRole: when a role is being revoked
- &$notice: notice being output - $profile: profile that will lose the role
- &$xs: XMLStringer for output - $role: string name of the role
- $verb: activity:verb URI ('http://activitystrea.ms/schema/1.0/post' by default)
StartActivityDefaultObjectType: before outputting activity:object-type element for a notice activity entry EndRevokeRole: when a role has been revoked
- &$notice: notice being output - $profile: profile that lost the role
- &$xs: XMLStringer for output - $role: string name of the role
- &$type: activity:object-type URI for default object ('http://activitystrea.ms/schema/1.0/note' by default)
EndActivityDefaultObjectType: after outputting activity:verb element for a notice activity entry StartAtomPubNewActivity: When a new activity comes in through Atom Pub API
- &$notice: notice being output - &$activity: received activity
- &$xs: XMLStringer for output
- $type: activity:object-type URI for default object ('http://activitystrea.ms/schema/1.0/note' by default)
StartActivityObjects: before outputting activity:object elements for a notice activity entry EndAtomPubNewActivity: When a new activity comes in through Atom Pub API
- &$notice: notice being output - $activity: received activity
- &$xs: XMLStringer for output - $notice: notice that was created
- &$objects: array of ActivityObject objects to output (empty by default)
EndActivityObjects: after outputting activity:object elements for a notice activity entry StartXrdActionAliases: About to set aliases for the XRD object for a user
- &$notice: notice being output - &$xrd: XRD object being shown
- &$xs: XMLStringer for output - $user: User being shown
- $objects: array of ActivityObject objects to output (empty by default)
StartActivityNoticeInfo: before outputting statusnet:notice-info element for a notice activity entry EndXrdActionAliases: Done with aliases for the XRD object for a user
- &$notice: notice being output - &$xrd: XRD object being shown
- &$xs: XMLStringer for output - $user: User being shown
- &$noticeInfoAttr: array of attributes for notice info element
EndActivityNoticeInfo: after outputting statusnet:notice-info element for a notice activity entry StartXrdActionLinks: About to set links for the XRD object for a user
- &$notice: notice being output - &$xrd: XRD object being shown
- &$xs: XMLStringer for output - $user: User being shown
- $noticeInfoAttr: array of attributes for notice info element
StartActivityInReplyTo: before outputting thr:in-reply-to element for a notice activity entry EndXrdActionLinks: Done with links for the XRD object for a user
- &$notice: notice being output - &$xrd: XRD object being shown
- &$xs: XMLStringer for output - $user: User being shown
- &$replyNotice: Notice object the main notice is in-reply-to
EndActivityInReplyTo: after outputting thr:in-reply-to element for a notice activity entry AdminPanelCheck: When checking whether the current user can access a given admin panel
- &$notice: notice being output - $name: Name of the admin panel
- &$xs: XMLStringer for output - &$isOK: Boolean whether the user is allowed to use the panel
- $replyNotice: Notice object the main notice is in-reply-to
StartActivityConversation: before outputting ostatus:conversation link element for a notice activity entry StartAdminPanelNav: Before displaying the first item in the list of admin panels
- &$notice: notice being output - $nav The AdminPanelNav widget
- &$xs: XMLStringer for output
- &$conv: Conversation object
EndActivityConversation: after outputting ostatus:conversation link element for a notice activity entry EndAdminPanelNav: After displaying the last item in the list of admin panels
- &$notice: notice being output - $nav The AdminPanelNav widget
- &$xs: XMLStringer for output
- $conv: Conversation object
StartActivityAttentionProfiles: before outputting ostatus:attention link element for people in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$replyProfiles: array of profiles of people being replied to
EndActivityAttentionProfiles: after outputting ostatus:attention link element for people in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $replyProfiles: array of Profile object of people being replied to
StartActivityAttentionGroups: before outputting ostatus:attention link element for groups in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$groups: array of Group objects of groups being addressed
EndActivityAttentionGroups: after outputting ostatus:attention link element for groups in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $groups: array of Group objects of groups being addressed
StartActivityForward: before outputting ostatus:forward link element in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$repeat: Notice that was repeated
EndActivityForward: after outputting ostatus:forward link element in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $repeat: Notice that was repeated
StartActivityCategories: before outputting atom:category elements in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$tags: array of strings for tags on the notice (used for categories)
EndActivityCategories: after outputting atom:category elements in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $tags: array of strings for tags on the notice (used for categories)
StartActivityEnclosures: before outputting enclosure link elements in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$enclosures: array of enclosure objects (see File::getEnclosure() for details)
EndActivityEnclosures: after outputting enclosure link elements in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $enclosures: array of enclosure objects (see File::getEnclosure() for details)
StartActivityGeo: before outputting geo:rss element in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- &$lat: latitude
- &$lon: longitude
EndActivityGeo: after outputting geo:rss element in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output
- $lat: latitude
- $lon: longitude
StartActivityEnd: before the closing </entry> in a notice activity entry (last chance for data!)
- &$notice: notice being output
- &$xs: XMLStringer for output
EndActivityEnd: after the closing </entry> in a notice activity entry
- &$notice: notice being output
- &$xs: XMLStringer for output

157
README
View File

@ -2,8 +2,8 @@
README README
------ ------
StatusNet 0.9.4beta2 StatusNet 0.9.6 "Man on the Moon"
11 August 2010 29 October 2010
This is the README file for StatusNet, the Open Source microblogging This is the README file for StatusNet, the Open Source microblogging
platform. It includes installation instructions, descriptions of platform. It includes installation instructions, descriptions of
@ -38,7 +38,8 @@ more, please see the Open Software Service Definition 1.1:
http://www.opendefinition.org/ossd http://www.opendefinition.org/ossd
StatusNet, Inc. <http://status.net/> also offers this software as a StatusNet, Inc. <http://status.net/> also offers this software as a
Web service, requiring no installation on your part. The software run Web service, requiring no installation on your part. See
<http://status.net/signup> for details. The software run
on status.net is identical to the software available for download, so on status.net is identical to the software available for download, so
you can move back and forth between a hosted version or a version you can move back and forth between a hosted version or a version
installed on your own servers. installed on your own servers.
@ -72,6 +73,20 @@ License along with this program, in the file "COPYING". If not, see
of using the software, and if you do not wish to share your of using the software, and if you do not wish to share your
modifications, *YOU MAY NOT INSTALL STATUSNET*. modifications, *YOU MAY NOT INSTALL STATUSNET*.
Documentation in the /doc-src/ directory is available under the
Creative Commons Attribution 3.0 Unported license, with attribution to
"StatusNet". See http://creativecommons.org/licenses/by/3.0/ for details.
CSS and images in the /theme/ directory are available under the
Creative Commons Attribution 3.0 Unported license, with attribution to
"StatusNet". See http://creativecommons.org/licenses/by/3.0/ for details.
Our understanding and intention is that if you add your own theme that
uses only CSS and images, those files are not subject to the copyleft
requirements of the Affero General Public License 3.0. See
http://wordpress.org/news/2009/07/themes-are-gpl-too/ . This is not
legal advice; consult your lawyer.
Additional library software has been made available in the 'extlib' Additional library software has been made available in the 'extlib'
directory. All of it is Free Software and can be distributed under directory. All of it is Free Software and can be distributed under
liberal terms, but those terms may differ in detail from the AGPL's liberal terms, but those terms may differ in detail from the AGPL's
@ -81,31 +96,43 @@ for additional terms.
New this version New this version
================ ================
This is a security, bug and feature release since version 0.9.3 released on This is a security, bug and feature release since version 0.9.5 released on
29 June 2010. 10 September 2010.
For best compatibility with client software and site federation, and a lot of For best compatibility with client software and site federation, and a lot of
bug fixes, it is highly recommended that all public sites upgrade to the new bug fixes, it is highly recommended that all public sites upgrade to the new
version. version.
Changes from 0.9.4beta1:
- fix for daemon config switching on multi-site setup
Notable changes this version: Notable changes this version:
- OpenID and OAuth libraries patched for potential timing attack - Site moderators can now delete groups.
- OStatus feed i/o updated for Activity Streams - New themes: clean, shiny, mnml, victorian
- Correctness fixes on XRD, other discovery bits - New YammerImport plugin allows site admins to import non-private profiles and
- Support for contacting SNI-based SSL virtual hosts when SSL message from an authenticated Yammer site.
certificate verification is enabled (requires PHP 5.3.2+ or - New experimental plugins: AnonFavorites, SlicedFavorites, GroupFavorited,
enabling CURL backend with $config['http']['curl'] = true) ForceGroup, ShareNotice
- Experimental SubMirror plugin - OAuth upgraded to 1.0a
- Multi-site status_network table mode has been tweaked to support - Localization updates now include plugins, thanks to translatewiki.net!
multiple tags better - SSL link generation should be more consistent; alternate SSL URLs can be
- Many updates to user interface translation from TranslateWiki set in the admin UI for more parts of the system.
- Many other bugfixes - Experimental backupuser.php, restoreuser.php command-line scripts to
dump/restore a user's complete activity stream. Can be used to transfer
accounts manually between sites, or to save a backup before deleting.
- Unicode fixes for OStatus notices
- Header metadata on notice pages to aid in manual reposting on Facebook
- Lots of little fixes...
A full changelog is available at http://status.net/wiki/StatusNet_0.9.4. Changes from 0.9.6 release candidate 1:
- fix for broken group pages when logged out
- fix for stuck ping queue entries when bad profile
- fix for bogus single-user nickname config entry error
- i18n updates
- nofollow updates
- SSL-only mode secure cookie fix
- experimental ApiLogger plugin for usage data gathering
- experimental follow-everyone plugin
A full changelog is available at http://status.net/wiki/StatusNet_0.9.6.
Prerequisites Prerequisites
============= =============
@ -193,14 +220,12 @@ and the URLs are listed here for your convenience.
version may render your StatusNet site unable to send or receive XMPP version may render your StatusNet site unable to send or receive XMPP
messages. messages.
- Facebook library. Used for the Facebook application. - Facebook library. Used for the Facebook application.
- PEAR Services_oEmbed. Used for some multimedia integration. - PEAR Validate is used for URL and email validation.
- PEAR HTTP_Request is an oEmbed dependency.
- PEAR Validate is an oEmbed dependency.
- PEAR Net_URL2 is an oEmbed dependency.
- Console_GetOpt for parsing command-line options. - Console_GetOpt for parsing command-line options.
- libomb. a library for implementing OpenMicroBlogging 0.1, the - libomb. a library for implementing OpenMicroBlogging 0.1, the
predecessor to OStatus. predecessor to OStatus.
- HTTP_Request2, a library for making HTTP requests. - HTTP_Request2, a library for making HTTP requests.
- PEAR Net_URL2 is an HTTP_Request2 dependency.
A design goal of StatusNet is that the basic Web functionality should A design goal of StatusNet is that the basic Web functionality should
work on even the most restrictive commercial hosting services. work on even the most restrictive commercial hosting services.
@ -218,9 +243,9 @@ especially if you've previously installed PHP/MySQL packages.
1. Unpack the tarball you downloaded on your Web server. Usually a 1. Unpack the tarball you downloaded on your Web server. Usually a
command like this will work: command like this will work:
tar zxf statusnet-0.9.4.tar.gz tar zxf statusnet-0.9.6.tar.gz
...which will make a statusnet-0.9.2 subdirectory in your current ...which will make a statusnet-0.9.6 subdirectory in your current
directory. (If you don't have shell access on your Web server, you directory. (If you don't have shell access on your Web server, you
may have to unpack the tarball on your local computer and FTP the may have to unpack the tarball on your local computer and FTP the
files to the server.) files to the server.)
@ -228,7 +253,7 @@ especially if you've previously installed PHP/MySQL packages.
2. Move the tarball to a directory of your choosing in your Web root 2. Move the tarball to a directory of your choosing in your Web root
directory. Usually something like this will work: directory. Usually something like this will work:
mv statusnet-0.9.4 /var/www/statusnet mv statusnet-0.9.6 /var/www/statusnet
This will make your StatusNet instance available in the statusnet path of This will make your StatusNet instance available in the statusnet path of
your server, like "http://example.net/statusnet". "microblog" or your server, like "http://example.net/statusnet". "microblog" or
@ -587,7 +612,7 @@ subdirectory to add a new language to your system. You'll need to
compile the ".po" files into ".mo" files, however. compile the ".po" files into ".mo" files, however.
Contributions of translation information to StatusNet are very easy: Contributions of translation information to StatusNet are very easy:
you can use the Web interface at TranslateWiki.net to add one you can use the Web interface at translatewiki.net to add one
or a few or lots of new translations -- or even new languages. You can or a few or lots of new translations -- or even new languages. You can
also download more up-to-date .po files there, if you so desire. also download more up-to-date .po files there, if you so desire.
@ -643,7 +668,7 @@ with this situation.
If you've been using StatusNet 0.7, 0.6, 0.5 or lower, or if you've If you've been using StatusNet 0.7, 0.6, 0.5 or lower, or if you've
been tracking the "git" version of the software, you will probably been tracking the "git" version of the software, you will probably
want to upgrade and keep your existing data. There is no automated want to upgrade and keep your existing data. There is no automated
upgrade procedure in StatusNet 0.9.2. Try these step-by-step upgrade procedure in StatusNet 0.9.6. Try these step-by-step
instructions; read to the end first before trying them. instructions; read to the end first before trying them.
0. Download StatusNet and set up all the prerequisites as if you were 0. Download StatusNet and set up all the prerequisites as if you were
@ -664,10 +689,11 @@ instructions; read to the end first before trying them.
5. Once all writing processes to your site are turned off, make a 5. Once all writing processes to your site are turned off, make a
final backup of the Web directory and database. final backup of the Web directory and database.
6. Move your StatusNet directory to a backup spot, like "statusnet.bak". 6. Move your StatusNet directory to a backup spot, like "statusnet.bak".
7. Unpack your StatusNet 0.9.2 tarball and move it to "statusnet" or 7. Unpack your StatusNet 0.9.6 tarball and move it to "statusnet" or
wherever your code used to be. wherever your code used to be.
8. Copy the config.php file and avatar directory from your old 8. Copy the config.php file and the contents of the avatar/, background/,
directory to your new directory. file/, and local/ subdirectories from your old directory to your new
directory.
9. Copy htaccess.sample to .htaccess in the new directory. Change the 9. Copy htaccess.sample to .htaccess in the new directory. Change the
RewriteBase to use the correct path. RewriteBase to use the correct path.
10. Rebuild the database. (You can safely skip this step and go to #12 10. Rebuild the database. (You can safely skip this step and go to #12
@ -835,6 +861,8 @@ notice: A plain string that will appear on every page. A good place
be escaped. be escaped.
logo: URL of an image file to use as the logo for the site. Overrides logo: URL of an image file to use as the logo for the site. Overrides
the logo in the theme, if any. the logo in the theme, if any.
ssllogo: URL of an image file to use as the logo on SSL pages. If unset,
theme logo is used instead.
ssl: Whether to use SSL and https:// URLs for some or all pages. ssl: Whether to use SSL and https:// URLs for some or all pages.
Possible values are 'always' (use it for all pages), 'never' Possible values are 'always' (use it for all pages), 'never'
(don't use it for any pages), or 'sometimes' (use it for (don't use it for any pages), or 'sometimes' (use it for
@ -1092,6 +1120,9 @@ path: Path part of theme URLs, before the theme name. Relative to the
which means to use the site path + '/theme'. which means to use the site path + '/theme'.
ssl: Whether to use SSL for theme elements. Default is null, which means ssl: Whether to use SSL for theme elements. Default is null, which means
guess based on site SSL settings. guess based on site SSL settings.
sslserver: SSL server to use when page is HTTPS-encrypted. If
unspecified, site ssl server and so on will be used.
sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
javascript javascript
---------- ----------
@ -1103,6 +1134,9 @@ path: Path part of Javascript URLs. Defaults to null,
which means to use the site path + '/js/'. which means to use the site path + '/js/'.
ssl: Whether to use SSL for JavaScript files. Default is null, which means ssl: Whether to use SSL for JavaScript files. Default is null, which means
guess based on site SSL settings. guess based on site SSL settings.
sslserver: SSL server to use when page is HTTPS-encrypted. If
unspecified, site ssl server and so on will be used.
sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
xmpp xmpp
---- ----
@ -1330,6 +1364,11 @@ ssl: whether to use HTTPS for file URLs. Defaults to null, meaning to
filecommand: command to use for determining the type of a file. May be filecommand: command to use for determining the type of a file. May be
skipped if fileinfo extension is installed. Defaults to skipped if fileinfo extension is installed. Defaults to
'/usr/bin/file'. '/usr/bin/file'.
sslserver: if specified, this server will be used when creating HTTPS
URLs. Otherwise, the site SSL server will be used, with /file/ path.
sslpath: if this and the sslserver are specified, this path will be used
when creating HTTPS URLs. Otherwise, the attachments|path value
will be used.
group group
----- -----
@ -1386,8 +1425,9 @@ dir: directory to write backgrounds too. Default is '/background/'
subdir of install dir. subdir of install dir.
path: path to backgrounds. Default is sub-path of install path; note path: path to backgrounds. Default is sub-path of install path; note
that you may need to change this if you change site-path too. that you may need to change this if you change site-path too.
ssl: Whether or not to use HTTPS for background files. Defaults to sslserver: SSL server to use when page is HTTPS-encrypted. If
null, meaning to guess from site-wide SSL settings. unspecified, site ssl server and so on will be used.
sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
ping ping
---- ----
@ -1452,7 +1492,8 @@ If an installation has only one user, this can simplify a lot of the
interface. It also makes the user's profile the root URL. interface. It also makes the user's profile the root URL.
enabled: Whether to run in "single user mode". Default false. enabled: Whether to run in "single user mode". Default false.
nickname: nickname of the single user. nickname: nickname of the single user. If no nickname is specified,
the site owner account will be used (if present).
robotstxt robotstxt
--------- ---------
@ -1468,6 +1509,33 @@ disallow: Array of (virtual) directories to disallow. Default is 'main',
'search', 'message', 'settings', 'admin'. Ignored when site 'search', 'message', 'settings', 'admin'. Ignored when site
is private, in which case the entire site ('/') is disallowed. is private, in which case the entire site ('/') is disallowed.
api
---
Options for the Twitter-like API.
realm: HTTP Basic Auth realm (see http://tools.ietf.org/html/rfc2617
for details). Some third-party tools like ping.fm want this to be
'Identi.ca API', so set it to that if you want to. default = null,
meaning 'something based on the site name'.
nofollow
--------
We optionally put 'rel="nofollow"' on some links in some pages. The
following configuration settings let you fine-tune how or when things
are nofollowed. See http://en.wikipedia.org/wiki/Nofollow for more
information on what 'nofollow' means.
subscribers: whether to nofollow links to subscribers on the profile
and personal pages. Default is true.
members: links to members on the group page. Default true.
peopletag: links to people listed in the peopletag page. Default true.
external: external links in notices. One of three values: 'sometimes',
'always', 'never'. If 'sometimes', then external links are not
nofollowed on profile, notice, and favorites page. Default is
'sometimes'.
url url
--- ---
@ -1484,6 +1552,19 @@ maxnoticelength: If a notice is strictly longer than this limit, all
URLs in the notice will be shortened. Users can override. URLs in the notice will be shortened. Users can override.
-1 means the text limit for notices. -1 means the text limit for notices.
router
------
We use a router class for mapping URLs to code. This section controls
how that router works.
cache: whether to cache the router in memcache (or another caching
mechanism). Defaults to true, but may be set to false for
developers (who might be actively adding pages, so won't want the
router cached) or others who see strange behavior. You're unlikely
to need this unless you're a developer.
Plugins Plugins
======= =======
@ -1541,7 +1622,7 @@ repository (see below), and you get a compilation error ("unexpected
T_STRING") in the browser, check to see that you don't have any T_STRING") in the browser, check to see that you don't have any
conflicts in your code. conflicts in your code.
If you upgraded to StatusNet 0.9.2 without reading the "Notice If you upgraded to StatusNet 0.9.x without reading the "Notice
inboxes" section above, and all your users' 'Personal' tabs are empty, inboxes" section above, and all your users' 'Personal' tabs are empty,
read the "Notice inboxes" section above. read the "Notice inboxes" section above.
@ -1652,6 +1733,10 @@ if anyone's been overlooked in error.
* mEDI * mEDI
* Brett Taylor * Brett Taylor
* Brigitte Schuster * Brigitte Schuster
* Siebrand Mazeland and the amazing volunteer translators at translatewiki.net
* Brion Vibber, StatusNet, Inc.
* James Walker, StatusNet, Inc.
* Samantha Doherty, designer, StatusNet, Inc.
Thanks also to the developers of our upstream library code and to the Thanks also to the developers of our upstream library code and to the
thousands of people who have tried out Identi.ca, installed StatusNet, thousands of people who have tried out Identi.ca, installed StatusNet,

View File

@ -40,7 +40,6 @@ if (!defined('STATUSNET')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class AccessadminpanelAction extends AdminPanelAction class AccessadminpanelAction extends AdminPanelAction
{ {
/** /**
@ -48,10 +47,9 @@ class AccessadminpanelAction extends AdminPanelAction
* *
* @return string page title * @return string page title
*/ */
function title() function title()
{ {
// TRANS: Page title // TRANS: Page title for Access admin panel that allows configuring site access.
return _('Access'); return _('Access');
} }
@ -60,10 +58,9 @@ class AccessadminpanelAction extends AdminPanelAction
* *
* @return string instructions * @return string instructions
*/ */
function getInstructions() function getInstructions()
{ {
// TRANS: Page notice // TRANS: Page notice.
return _('Site access settings'); return _('Site access settings');
} }
@ -72,7 +69,6 @@ class AccessadminpanelAction extends AdminPanelAction
* *
* @return void * @return void
*/ */
function showForm() function showForm()
{ {
$form = new AccessAdminPanelForm($this); $form = new AccessAdminPanelForm($this);
@ -85,7 +81,6 @@ class AccessadminpanelAction extends AdminPanelAction
* *
* @return void * @return void
*/ */
function saveSettings() function saveSettings()
{ {
static $booleans = array('site' => array('private', 'inviteonly', 'closed')); static $booleans = array('site' => array('private', 'inviteonly', 'closed'));
@ -110,7 +105,6 @@ class AccessadminpanelAction extends AdminPanelAction
return; return;
} }
} }
class AccessAdminPanelForm extends AdminForm class AccessAdminPanelForm extends AdminForm
@ -120,7 +114,6 @@ class AccessAdminPanelForm extends AdminForm
* *
* @return int ID of the form * @return int ID of the form
*/ */
function id() function id()
{ {
return 'form_site_admin_panel'; return 'form_site_admin_panel';
@ -131,7 +124,6 @@ class AccessAdminPanelForm extends AdminForm
* *
* @return string class of the form * @return string class of the form
*/ */
function formClass() function formClass()
{ {
return 'form_settings'; return 'form_settings';
@ -142,7 +134,6 @@ class AccessAdminPanelForm extends AdminForm
* *
* @return string URL of the action * @return string URL of the action
*/ */
function action() function action()
{ {
return common_local_url('accessadminpanel'); return common_local_url('accessadminpanel');
@ -153,7 +144,6 @@ class AccessAdminPanelForm extends AdminForm
* *
* @return void * @return void
*/ */
function formData() function formData()
{ {
$this->out->elementStart('fieldset', array('id' => 'settings_admin_access')); $this->out->elementStart('fieldset', array('id' => 'settings_admin_access'));
@ -161,7 +151,7 @@ class AccessAdminPanelForm extends AdminForm
$this->out->element('legend', null, _('Registration')); $this->out->element('legend', null, _('Registration'));
$this->out->elementStart('ul', 'form_data'); $this->out->elementStart('ul', 'form_data');
$this->li(); $this->li();
// TRANS: Checkbox instructions for admin setting "Private" // TRANS: Checkbox instructions for admin setting "Private".
$instructions = _('Prohibit anonymous users (not logged in) from viewing site?'); $instructions = _('Prohibit anonymous users (not logged in) from viewing site?');
// TRANS: Checkbox label for prohibiting anonymous users from viewing site. // TRANS: Checkbox label for prohibiting anonymous users from viewing site.
$this->out->checkbox('private', _m('LABEL', 'Private'), $this->out->checkbox('private', _m('LABEL', 'Private'),
@ -170,7 +160,7 @@ class AccessAdminPanelForm extends AdminForm
$this->unli(); $this->unli();
$this->li(); $this->li();
// TRANS: Checkbox instructions for admin setting "Invite only" // TRANS: Checkbox instructions for admin setting "Invite only".
$instructions = _('Make registration invitation only.'); $instructions = _('Make registration invitation only.');
// TRANS: Checkbox label for configuring site as invite only. // TRANS: Checkbox label for configuring site as invite only.
$this->out->checkbox('inviteonly', _('Invite only'), $this->out->checkbox('inviteonly', _('Invite only'),
@ -179,7 +169,7 @@ class AccessAdminPanelForm extends AdminForm
$this->unli(); $this->unli();
$this->li(); $this->li();
// TRANS: Checkbox instructions for admin setting "Closed" (no new registrations) // TRANS: Checkbox instructions for admin setting "Closed" (no new registrations).
$instructions = _('Disable new registrations.'); $instructions = _('Disable new registrations.');
// TRANS: Checkbox label for disabling new user registrations. // TRANS: Checkbox label for disabling new user registrations.
$this->out->checkbox('closed', _('Closed'), $this->out->checkbox('closed', _('Closed'),
@ -195,12 +185,11 @@ class AccessAdminPanelForm extends AdminForm
* *
* @return void * @return void
*/ */
function formActions() function formActions()
{ {
// TRANS: Title / tooltip for button to save access settings in site admin panel // TRANS: Title for button to save access settings in site admin panel.
$title = _('Save access settings'); $title = _('Save access settings');
// TRANS: Tooltip for button to save access settings in site admin panel.
$this->out->submit('submit', _m('BUTTON', 'Save'), 'submit', null, $title); $this->out->submit('submit', _m('BUTTON', 'Save'), 'submit', null, $title);
} }
} }

View File

@ -67,4 +67,3 @@ class AccesstokenAction extends Action
} }
} }
} }
?>

View File

@ -64,7 +64,7 @@ class AllAction extends ProfileAction
} }
if ($this->page > 1 && $this->notice->N == 0) { if ($this->page > 1 && $this->notice->N == 0) {
// TRANS: Server error when page not found (404) // TRANS: Server error when page not found (404).
$this->serverError(_('No such page.'), $code = 404); $this->serverError(_('No such page.'), $code = 404);
} }
@ -76,6 +76,7 @@ class AllAction extends ProfileAction
parent::handle($args); parent::handle($args);
if (!$this->user) { if (!$this->user) {
// TRANS: Client error when user not found for an action.
$this->clientError(_('No such user.')); $this->clientError(_('No such user.'));
return; return;
} }
@ -89,7 +90,7 @@ class AllAction extends ProfileAction
// TRANS: Page title. %1$s is user nickname, %2$d is page number // TRANS: Page title. %1$s is user nickname, %2$d is page number
return sprintf(_('%1$s and friends, page %2$d'), $this->user->nickname, $this->page); return sprintf(_('%1$s and friends, page %2$d'), $this->user->nickname, $this->page);
} else { } else {
// TRANS: Page title. %1$s is user nickname // TRANS: Page title. %s is user nickname
return sprintf(_("%s and friends"), $this->user->nickname); return sprintf(_("%s and friends"), $this->user->nickname);
} }
} }
@ -103,7 +104,7 @@ class AllAction extends ProfileAction
'nickname' => 'nickname' =>
$this->user->nickname) $this->user->nickname)
), ),
// TRANS: %1$s is user nickname // TRANS: %s is user nickname.
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
new Feed(Feed::RSS2, new Feed(Feed::RSS2,
common_local_url( common_local_url(
@ -112,7 +113,7 @@ class AllAction extends ProfileAction
'id' => $this->user->nickname 'id' => $this->user->nickname
) )
), ),
// TRANS: %1$s is user nickname // TRANS: %s is user nickname.
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
new Feed(Feed::ATOM, new Feed(Feed::ATOM,
common_local_url( common_local_url(
@ -121,7 +122,7 @@ class AllAction extends ProfileAction
'id' => $this->user->nickname 'id' => $this->user->nickname
) )
), ),
// TRANS: %1$s is user nickname // TRANS: %s is user nickname.
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)) sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))
); );
} }
@ -134,18 +135,23 @@ class AllAction extends ProfileAction
function showEmptyListMessage() function showEmptyListMessage()
{ {
// TRANS: %1$s is user nickname // TRANS: Empty list message. %s is a user nickname.
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->user->nickname) . ' '; $message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->user->nickname) . ' ';
if (common_logged_in()) { if (common_logged_in()) {
$current_user = common_current_user(); $current_user = common_current_user();
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
// TRANS: Encouragement displayed on logged in user's empty timeline.
// TRANS: This message contains Markdown links. Keep "](" together.
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.'); $message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
} else { } else {
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@" // TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@".
// TRANS: This message contains Markdown links. Keep "](" together.
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
} }
} else { } else {
// TRANS: Encoutagement displayed on empty timeline user pages for anonymous users.
// TRANS: %s is a user nickname. This message contains Markdown links. Keep "](" together.
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->user->nickname); $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->user->nickname);
} }
@ -178,10 +184,10 @@ class AllAction extends ProfileAction
{ {
$user = common_current_user(); $user = common_current_user();
if ($user && ($user->id == $this->user->id)) { if ($user && ($user->id == $this->user->id)) {
// TRANS: H1 text // TRANS: H1 text for page when viewing a list for self.
$this->element('h1', null, _("You and friends")); $this->element('h1', null, _("You and friends"));
} else { } else {
// TRANS: H1 text. %1$s is user nickname // TRANS: H1 text for page. %s is a user nickname.
$this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname)); $this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname));
} }
} }

View File

@ -1,5 +1,4 @@
<?php <?php
/** /**
* RSS feed for user and friends timeline action class. * RSS feed for user and friends timeline action class.
* *
@ -57,6 +56,7 @@ class AllrssAction extends Rss10Action
* @param array $args Web and URL arguments * @param array $args Web and URL arguments
* *
* @return boolean false if user doesn't exist * @return boolean false if user doesn't exist
*
*/ */
function prepare($args) function prepare($args)
{ {
@ -65,6 +65,7 @@ class AllrssAction extends Rss10Action
$this->user = User::staticGet('nickname', $nickname); $this->user = User::staticGet('nickname', $nickname);
if (!$this->user) { if (!$this->user) {
// TRANS: Client error when user not found for an rss related action.
$this->clientError(_('No such user.')); $this->clientError(_('No such user.'));
return false; return false;
} else { } else {
@ -127,7 +128,7 @@ class AllrssAction extends Rss10Action
* Get image. * Get image.
* *
* @return string user avatar URL or null * @return string user avatar URL or null
*/ */
function getImage() function getImage()
{ {
$user = $this->user; $user = $this->user;
@ -139,4 +140,3 @@ class AllrssAction extends Rss10Action
return $avatar ? $avatar->url : null; return $avatar ? $avatar->url : null;
} }
} }

View File

@ -49,10 +49,8 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountRateLimitStatusAction extends ApiBareAuthAction class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
{ {
/** /**
* Handle the request * Handle the request
* *
@ -62,7 +60,6 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -119,11 +116,8 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

View File

@ -45,7 +45,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
{ {
/** /**
@ -54,9 +53,7 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -76,13 +73,13 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error message. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, $this->format 400, $this->format
); );
@ -91,6 +88,7 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed handling a non-existing API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -101,16 +99,14 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
// Note: Twitter no longer supports IM // Note: Twitter no longer supports IM
if (!in_array(strtolower($this->device), array('sms', 'im', 'none'))) { if (!in_array(strtolower($this->device), array('sms', 'im', 'none'))) {
$this->clientError( // TRANS: Client error displayed when no valid device parameter is provided for a user's delivery device setting.
_( $this->clientError(_( 'You must specify a parameter named ' .
'You must specify a parameter named ' . '\'device\' with a value of one of: sms, im, none.' ));
'\'device\' with a value of one of: sms, im, none.'
)
);
return; return;
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when no existing user is provided for a user's delivery device setting.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -136,6 +132,7 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
if ($result === false) { if ($result === false) {
common_log_db_error($this->user, 'UPDATE', __FILE__); common_log_db_error($this->user, 'UPDATE', __FILE__);
// TRANS: Server error displayed when a user's delivery device cannot be updated.
$this->serverError(_('Could not update user.')); $this->serverError(_('Could not update user.'));
return; return;
} }
@ -160,5 +157,4 @@ class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
$this->endDocument('json'); $this->endDocument('json');
} }
} }
} }

View File

@ -43,19 +43,15 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountUpdateProfileAction extends ApiAuthAction class ApiAccountUpdateProfileAction extends ApiAuthAction
{ {
/** /**
* Take arguments for running * Take arguments for running
* *
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -79,13 +75,13 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, $this->format 400, $this->format
); );
@ -94,6 +90,7 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -102,6 +99,7 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed if a user could not be found.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -109,6 +107,7 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
if (empty($profile)) { if (empty($profile)) {
// TRANS: Client error displayed if a user profile could not be found.
$this->clientError(_('User has no profile.')); $this->clientError(_('User has no profile.'));
return; return;
} }
@ -144,6 +143,7 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
if (!$result) { if (!$result) {
common_log_db_error($profile, 'UPDATE', __FILE__); common_log_db_error($profile, 'UPDATE', __FILE__);
// TRANS: Server error displayed if a user profile could not be saved.
$this->serverError(_('Could not save profile.')); $this->serverError(_('Could not save profile.'));
return; return;
} }
@ -162,5 +162,4 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
$this->endDocument('json'); $this->endDocument('json');
} }
} }
} }

View File

@ -42,10 +42,8 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
{ {
var $tile = false; var $tile = false;
/** /**
@ -56,7 +54,6 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -76,13 +73,13 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, $this->format 400, $this->format
); );
@ -91,6 +88,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -105,14 +103,18 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error when user not found updating a profile background image.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -124,7 +126,6 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
// is part of the img filename. // is part of the img filename.
if (empty($design)) { if (empty($design)) {
$this->user->query('BEGIN'); $this->user->query('BEGIN');
// save new design // save new design
@ -133,6 +134,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if (empty($id)) { if (empty($id)) {
common_log_db_error($id, 'INSERT', __FILE__); common_log_db_error($id, 'INSERT', __FILE__);
// TRANS: Client error displayed when saving design settings fails because of an empty id.
$this->clientError(_('Unable to save your design settings.')); $this->clientError(_('Unable to save your design settings.'));
return; return;
} }
@ -143,6 +145,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if (empty($result)) { if (empty($result)) {
common_log_db_error($original, 'UPDATE', __FILE__); common_log_db_error($original, 'UPDATE', __FILE__);
// TRANS: Client error displayed when saving design settings fails because of an empty result.
$this->clientError(_('Unable to save your design settings.')); $this->clientError(_('Unable to save your design settings.'));
$this->user->query('ROLLBACK'); $this->user->query('ROLLBACK');
return; return;
@ -184,6 +187,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
if ($result === false) { if ($result === false) {
common_log_db_error($design, 'UPDATE', __FILE__); common_log_db_error($design, 'UPDATE', __FILE__);
// TRANS: Error displayed when updating design settings fails.
$this->showForm(_('Could not update your design.')); $this->showForm(_('Could not update your design.'));
return; return;
} }
@ -191,6 +195,7 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
if (empty($profile)) { if (empty($profile)) {
// TRANS: Client error displayed when a user has no profile.
$this->clientError(_('User has no profile.')); $this->clientError(_('User has no profile.'));
return; return;
} }
@ -207,5 +212,4 @@ class ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
$this->endDocument('json'); $this->endDocument('json');
} }
} }
} }

View File

@ -43,10 +43,8 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountUpdateProfileColorsAction extends ApiAuthAction class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
{ {
var $profile_background_color = null; var $profile_background_color = null;
var $profile_text_color = null; var $profile_text_color = null;
var $profile_link_color = null; var $profile_link_color = null;
@ -59,9 +57,7 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -100,13 +96,13 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, $this->format 400, $this->format
); );
@ -115,6 +111,7 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method updating profile colours.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -125,7 +122,6 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
$design = $this->user->getDesign(); $design = $this->user->getDesign();
if (!empty($design)) { if (!empty($design)) {
$original = clone($design); $original = clone($design);
try { try {
@ -139,12 +135,11 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
if ($result === false) { if ($result === false) {
common_log_db_error($design, 'UPDATE', __FILE__); common_log_db_error($design, 'UPDATE', __FILE__);
// TRANS: Client error displayed when a database error occurs updating profile colours.
$this->clientError(_('Could not update your design.')); $this->clientError(_('Could not update your design.'));
return; return;
} }
} else { } else {
$this->user->query('BEGIN'); $this->user->query('BEGIN');
// save new design // save new design
@ -161,6 +156,7 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
if (empty($id)) { if (empty($id)) {
common_log_db_error($id, 'INSERT', __FILE__); common_log_db_error($id, 'INSERT', __FILE__);
// TRANS: Client error displayed when a database error occurs inserting profile colours.
$this->clientError(_('Unable to save your design settings.')); $this->clientError(_('Unable to save your design settings.'));
return; return;
} }
@ -171,6 +167,7 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
if (empty($result)) { if (empty($result)) {
common_log_db_error($original, 'UPDATE', __FILE__); common_log_db_error($original, 'UPDATE', __FILE__);
// TRANS: Client error displayed when a database error occurs updating profile colours.
$this->clientError(_('Unable to save your design settings.')); $this->clientError(_('Unable to save your design settings.'));
$this->user->query('ROLLBACK'); $this->user->query('ROLLBACK');
return; return;
@ -182,6 +179,7 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
if (empty($profile)) { if (empty($profile)) {
// TRANS: Client error displayed a user has no profile updating profile colours.
$this->clientError(_('User has no profile.')); $this->clientError(_('User has no profile.'));
return; return;
} }
@ -206,7 +204,6 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function setColors($design) function setColors($design)
{ {
$bgcolor = empty($this->profile_background_color) ? $bgcolor = empty($this->profile_background_color) ?
@ -242,5 +239,4 @@ class ApiAccountUpdateProfileColorsAction extends ApiAuthAction
return true; return true;
} }
} }

View File

@ -43,19 +43,15 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountUpdateProfileImageAction extends ApiAuthAction class ApiAccountUpdateProfileImageAction extends ApiAuthAction
{ {
/** /**
* Take arguments for running * Take arguments for running
* *
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -74,13 +70,13 @@ class ApiAccountUpdateProfileImageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, $this->format 400, $this->format
); );
@ -94,14 +90,17 @@ class ApiAccountUpdateProfileImageAction extends ApiAuthAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed updating profile image without having a user object.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -127,6 +126,7 @@ class ApiAccountUpdateProfileImageAction extends ApiAuthAction
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
if (empty($profile)) { if (empty($profile)) {
// TRANS: Client error displayed if a user profile could not be found updating a profile image.
$this->clientError(_('User has no profile.')); $this->clientError(_('User has no profile.'));
return; return;
} }
@ -147,5 +147,4 @@ class ApiAccountUpdateProfileImageAction extends ApiAuthAction
$this->endDocument('json'); $this->endDocument('json');
} }
} }
} }

View File

@ -48,10 +48,8 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiAccountVerifyCredentialsAction extends ApiAuthAction class ApiAccountVerifyCredentialsAction extends ApiAuthAction
{ {
/** /**
* Handle the request * Handle the request
* *
@ -61,12 +59,12 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
// TRANS: Client error displayed trying to execute an unknown API method verifying user credentials.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
return; return;
} }
@ -91,12 +89,9 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
* @param array $args other arguments * @param array $args other arguments
* *
* @return boolean true * @return boolean true
* */
**/
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

132
actions/apiatomservice.php Normal file
View File

@ -0,0 +1,132 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* An AtomPub service document for 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 Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
* @link http://status.net/
*/
require_once INSTALLDIR.'/lib/apibareauth.php';
/**
* Shows an AtomPub service document for a user
*
* @category API
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
* @link http://status.net/
*/
class ApiAtomServiceAction extends ApiBareAuthAction
{
/**
* 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;
}
return true;
}
/**
* Handle the arguments. In our case, show a service document.
*
* @param Array $args unused.
*
* @return void
*/
function handle($args)
{
parent::handle($args);
header('Content-Type: application/atomsvc+xml');
$this->startXML();
$this->elementStart('service', array('xmlns' => 'http://www.w3.org/2007/app',
'xmlns:atom' => 'http://www.w3.org/2005/Atom',
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/'));
$this->elementStart('workspace');
$this->element('atom:title', null, _('Main'));
$this->elementStart('collection',
array('href' => common_local_url('ApiTimelineUser',
array('id' => $this->user->id,
'format' => 'atom'))));
$this->element('atom:title',
null,
sprintf(_("%s timeline"),
$this->user->nickname));
$this->element('accept', null, 'application/atom+xml;type=entry');
$this->element('activity:verb', null, ActivityVerb::POST);
$this->elementEnd('collection');
$this->elementStart('collection',
array('href' => common_local_url('AtomPubSubscriptionFeed',
array('subscriber' => $this->user->id))));
$this->element('atom:title',
null,
sprintf(_("%s subscriptions"),
$this->user->nickname));
$this->element('accept', null, 'application/atom+xml;type=entry');
$this->element('activity:verb', null, ActivityVerb::FOLLOW);
$this->elementEnd('collection');
$this->elementStart('collection',
array('href' => common_local_url('AtomPubFavoriteFeed',
array('profile' => $this->user->id))));
$this->element('atom:title',
null,
sprintf(_("%s favorites"),
$this->user->nickname));
$this->element('accept', null, 'application/atom+xml;type=entry');
$this->element('activity:verb', null, ActivityVerb::FAVORITE);
$this->elementEnd('collection');
$this->elementStart('collection',
array('href' => common_local_url('AtomPubMembershipFeed',
array('profile' => $this->user->id))));
$this->element('atom:title',
null,
sprintf(_("%s memberships"),
$this->user->nickname));
$this->element('accept', null, 'application/atom+xml;type=entry');
$this->element('activity:verb', null, ActivityVerb::JOIN);
$this->elementEnd('collection');
$this->elementEnd('workspace');
$this->elementEnd('service');
$this->endXML();
}
}

View File

@ -46,7 +46,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiBlockCreateAction extends ApiAuthAction class ApiBlockCreateAction extends ApiAuthAction
{ {
var $other = null; var $other = null;
@ -59,7 +58,6 @@ class ApiBlockCreateAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -79,13 +77,13 @@ class ApiBlockCreateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -102,6 +100,7 @@ class ApiBlockCreateAction extends ApiAuthAction
if ($this->user->id == $this->other->id) { if ($this->user->id == $this->other->id) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when users try to block themselves.
_("You cannot block yourself!"), _("You cannot block yourself!"),
403, 403,
$this->format $this->format
@ -123,10 +122,8 @@ class ApiBlockCreateAction extends ApiAuthAction
$this->showProfile($this->other, $this->format); $this->showProfile($this->other, $this->format);
$this->endDocument($this->format); $this->endDocument($this->format);
} else { } else {
// TRANS: Server error displayed when blocking a user has failed.
$this->serverError(_('Block user failed.'), 500, $this->format); $this->serverError(_('Block user failed.'), 500, $this->format);
} }
} }
} }

View File

@ -45,7 +45,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiBlockDestroyAction extends ApiAuthAction class ApiBlockDestroyAction extends ApiAuthAction
{ {
var $other = null; var $other = null;
@ -56,9 +55,7 @@ class ApiBlockDestroyAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -78,13 +75,13 @@ class ApiBlockDestroyAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -93,6 +90,7 @@ class ApiBlockDestroyAction extends ApiAuthAction
} }
if (empty($this->user) || empty($this->other)) { if (empty($this->user) || empty($this->other)) {
// TRANS: Client error when user not found for an API action to remove a block for a user.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -111,10 +109,8 @@ class ApiBlockDestroyAction extends ApiAuthAction
$this->showProfile($this->other, $this->format); $this->showProfile($this->other, $this->format);
$this->endDocument($this->format); $this->endDocument($this->format);
} else { } else {
// TRANS: Server error displayed when unblocking a user has failed.
$this->serverError(_('Unblock user failed.')); $this->serverError(_('Unblock user failed.'));
} }
} }
} }

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiDirectMessageAction extends ApiAuthAction class ApiDirectMessageAction extends ApiAuthAction
{ {
var $messages = null; var $messages = null;
@ -64,9 +63,7 @@ class ApiDirectMessageAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -74,6 +71,7 @@ class ApiDirectMessageAction extends ApiAuthAction
$this->user = $this->auth_user; $this->user = $this->auth_user;
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error given when a user was not found (404).
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -86,10 +84,12 @@ class ApiDirectMessageAction extends ApiAuthAction
// Action was called by /api/direct_messages/sent.format // Action was called by /api/direct_messages/sent.format
$this->title = sprintf( $this->title = sprintf(
// TRANS: Title. %s is a user nickname.
_("Direct messages from %s"), _("Direct messages from %s"),
$this->user->nickname $this->user->nickname
); );
$this->subtitle = sprintf( $this->subtitle = sprintf(
// TRANS: Subtitle. %s is a user nickname.
_("All the direct messages sent from %s"), _("All the direct messages sent from %s"),
$this->user->nickname $this->user->nickname
); );
@ -98,10 +98,12 @@ class ApiDirectMessageAction extends ApiAuthAction
$this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id; $this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id;
} else { } else {
$this->title = sprintf( $this->title = sprintf(
// TRANS: Title. %s is a user nickname.
_("Direct messages to %s"), _("Direct messages to %s"),
$this->user->nickname $this->user->nickname
); );
$this->subtitle = sprintf( $this->subtitle = sprintf(
// TRANS: Subtitle. %s is a user nickname.
_("All the direct messages sent to %s"), _("All the direct messages sent to %s"),
$this->user->nickname $this->user->nickname
); );
@ -124,7 +126,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -136,7 +137,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showMessages() function showMessages()
{ {
switch($this->format) { switch($this->format) {
@ -153,6 +153,7 @@ class ApiDirectMessageAction extends ApiAuthAction
$this->showJsonDirectMessages(); $this->showJsonDirectMessages();
break; break;
default: default:
// TRANS: Client error given when an API method was not found (404).
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -163,7 +164,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return array notices * @return array notices
*/ */
function getMessages() function getMessages()
{ {
$message = new Message(); $message = new Message();
@ -202,7 +202,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -213,7 +212,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->messages)) { if (!empty($this->messages)) {
@ -228,7 +226,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showXmlDirectMessages() function showXmlDirectMessages()
{ {
$this->initDocument('xml'); $this->initDocument('xml');
@ -249,7 +246,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showJsonDirectMessages() function showJsonDirectMessages()
{ {
$this->initDocument('json'); $this->initDocument('json');
@ -270,7 +266,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showRssDirectMessages() function showRssDirectMessages()
{ {
$this->initDocument('rss'); $this->initDocument('rss');
@ -305,7 +300,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showAtomDirectMessages() function showAtomDirectMessages()
{ {
$this->initDocument('atom'); $this->initDocument('atom');
@ -347,7 +341,6 @@ class ApiDirectMessageAction extends ApiAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->messages)) { if (!empty($this->messages)) {
@ -357,6 +350,7 @@ class ApiDirectMessageAction extends ApiAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
strtotime($this->messages[0]->created), strtotime($this->messages[0]->created),
strtotime($this->messages[$last]->created) strtotime($this->messages[$last]->created)
@ -367,5 +361,4 @@ class ApiDirectMessageAction extends ApiAuthAction
return null; return null;
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiDirectMessageNewAction extends ApiAuthAction class ApiDirectMessageNewAction extends ApiAuthAction
{ {
var $other = null; var $other = null;
@ -61,9 +60,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -71,6 +68,7 @@ class ApiDirectMessageNewAction extends ApiAuthAction
$this->user = $this->auth_user; $this->user = $this->auth_user;
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error when user not found for an API direct message action.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -99,13 +97,13 @@ class ApiDirectMessageNewAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -115,16 +113,18 @@ class ApiDirectMessageNewAction extends ApiAuthAction
if (empty($this->content)) { if (empty($this->content)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when no message text was submitted (406).
_('No message text!'), _('No message text!'),
406, 406,
$this->format $this->format
); );
} else { } else {
$content_shortened = common_shorten_links($this->content); $content_shortened = $this->auth_user->shortenLinks($this->content);
if (Message::contentTooLong($content_shortened)) { if (Message::contentTooLong($content_shortened)) {
$this->clientError( $this->clientError(
sprintf( // TRANS: Client error displayed when message content is too long.
_('That\'s too long. Max message size is %d chars.'), // TRANS: %d is the maximum number of characters for a message.
sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()),
Message::maxContent() Message::maxContent()
), ),
406, 406,
@ -135,10 +135,12 @@ class ApiDirectMessageNewAction extends ApiAuthAction
} }
if (empty($this->other)) { if (empty($this->other)) {
// TRANS: Client error displayed if a recipient user could not be found (403).
$this->clientError(_('Recipient user not found.'), 403, $this->format); $this->clientError(_('Recipient user not found.'), 403, $this->format);
return; return;
} else if (!$this->user->mutuallySubscribed($this->other)) { } else if (!$this->user->mutuallySubscribed($this->other)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to direct message another user who's not a friend (403).
_('Can\'t send direct messages to users who aren\'t your friend.'), _('Can\'t send direct messages to users who aren\'t your friend.'),
403, 403,
$this->format $this->format
@ -148,10 +150,9 @@ class ApiDirectMessageNewAction extends ApiAuthAction
// Note: sending msgs to yourself is allowed by Twitter // Note: sending msgs to yourself is allowed by Twitter
$errmsg = 'Don\'t send a message to yourself; ' . // TRANS: Client error displayed trying to direct message self (403).
'just say it to yourself quietly instead.'; $this->clientError(_('Do not send a message to yourself; ' .
'just say it to yourself quietly instead.'), 403, $this->format);
$this->clientError(_($errmsg), 403, $this->format);
return; return;
} }
@ -175,6 +176,4 @@ class ApiDirectMessageNewAction extends ApiAuthAction
$this->showSingleJsondirectMessage($message); $this->showSingleJsondirectMessage($message);
} }
} }
} }

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiFavoriteCreateAction extends ApiAuthAction class ApiFavoriteCreateAction extends ApiAuthAction
{ {
var $notice = null; var $notice = null;
@ -59,9 +58,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -81,13 +78,13 @@ class ApiFavoriteCreateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -97,6 +94,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -106,6 +104,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
if (empty($this->notice)) { if (empty($this->notice)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when requesting a status with a non-existing ID.
_('No status found with that ID.'), _('No status found with that ID.'),
404, 404,
$this->format $this->format
@ -117,6 +116,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
if ($this->user->hasFave($this->notice)) { if ($this->user->hasFave($this->notice)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to mark a notice favourite that already is a favourite.
_('This status is already a favorite.'), _('This status is already a favorite.'),
403, 403,
$this->format $this->format
@ -128,6 +128,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
if (empty($fave)) { if (empty($fave)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when marking a notice as favourite fails.
_('Could not create favorite.'), _('Could not create favorite.'),
403, 403,
$this->format $this->format
@ -165,5 +166,4 @@ class ApiFavoriteCreateAction extends ApiAuthAction
// XXX: notify by SMS // XXX: notify by SMS
} }
} }
} }

View File

@ -48,10 +48,8 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiFavoriteDestroyAction extends ApiAuthAction class ApiFavoriteDestroyAction extends ApiAuthAction
{ {
var $notice = null; var $notice = null;
/** /**
@ -60,9 +58,7 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -82,13 +78,13 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -98,6 +94,7 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -107,6 +104,7 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
if (empty($this->notice)) { if (empty($this->notice)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to remove a favourite with an invalid ID.
_('No status found with that ID.'), _('No status found with that ID.'),
404, 404,
$this->format $this->format
@ -120,6 +118,7 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
if (!$fave->find(true)) { if (!$fave->find(true)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to remove a favourite that was not a favourite.
_('That status is not a favorite.'), _('That status is not a favorite.'),
403, 403,
$this->favorite $this->favorite
@ -132,6 +131,7 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
if (!$result) { if (!$result) {
common_log_db_error($fave, 'DELETE', __FILE__); common_log_db_error($fave, 'DELETE', __FILE__);
$this->clientError( $this->clientError(
// TRANS: Client error displayed when removing a favourite has failed.
_('Could not delete favorite.'), _('Could not delete favorite.'),
404, 404,
$this->format $this->format
@ -147,5 +147,4 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
$this->show_single_json_status($this->notice); $this->show_single_json_status($this->notice);
} }
} }
} }

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiFriendshipsCreateAction extends ApiAuthAction class ApiFriendshipsCreateAction extends ApiAuthAction
{ {
var $other = null; var $other = null;
@ -61,7 +60,6 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -81,13 +79,13 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -97,6 +95,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -106,6 +105,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
if (empty($this->other)) { if (empty($this->other)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying follow who's profile could not be found.
_('Could not follow user: profile not found.'), _('Could not follow user: profile not found.'),
403, 403,
$this->format $this->format
@ -115,6 +115,8 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
if ($this->user->isSubscribed($this->other)) { if ($this->user->isSubscribed($this->other)) {
$errmsg = sprintf( $errmsg = sprintf(
// TRANS: Client error displayed when trying to follow a user that's already being followed.
// TRANS: %s is the nickname of the user that is already being followed.
_('Could not follow user: %s is already on your list.'), _('Could not follow user: %s is already on your list.'),
$this->other->nickname $this->other->nickname
); );
@ -133,5 +135,4 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
$this->showProfile($this->other, $this->format); $this->showProfile($this->other, $this->format);
$this->endDocument($this->format); $this->endDocument($this->format);
} }
} }

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiFriendshipsDestroyAction extends ApiAuthAction class ApiFriendshipsDestroyAction extends ApiAuthAction
{ {
var $other = null; var $other = null;
@ -61,7 +60,6 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -81,13 +79,13 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -97,6 +95,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -106,6 +105,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
if (empty($this->other)) { if (empty($this->other)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to unfollow a user that cannot be found.
_('Could not unfollow user: User not found.'), _('Could not unfollow user: User not found.'),
403, 403,
$this->format $this->format
@ -117,6 +117,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
if ($this->user->id == $this->other->id) { if ($this->user->id == $this->other->id) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to unfollow self.
_("You cannot unfollow yourself."), _("You cannot unfollow yourself."),
403, 403,
$this->format $this->format
@ -131,5 +132,4 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
$this->showProfile($this->other, $this->format); $this->showProfile($this->other, $this->format);
$this->endDocument($this->format); $this->endDocument($this->format);
} }
} }

View File

@ -47,7 +47,6 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiFriendshipsExistsAction extends ApiPrivateAuthAction class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
{ {
var $profile_a = null; var $profile_a = null;
@ -59,9 +58,7 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -81,14 +78,14 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (empty($this->profile_a) || empty($this->profile_b)) { if (empty($this->profile_a) || empty($this->profile_b)) {
$this->clientError( $this->clientError(
_('Two valid IDs or screen_names must be supplied.'), // TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
_('Two valid IDs or nick names must be supplied.'),
400, 400,
$this->format $this->format
); );
@ -122,10 +119,8 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

View File

@ -46,7 +46,6 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiFriendshipsShowAction extends ApiBareAuthAction class ApiFriendshipsShowAction extends ApiBareAuthAction
{ {
var $source = null; var $source = null;
@ -58,9 +57,7 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -93,7 +90,6 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
* *
* @return boolean true or false * @return boolean true or false
*/ */
function requiresAuth() function requiresAuth()
{ {
if (common_config('site', 'private')) { if (common_config('site', 'private')) {
@ -119,18 +115,19 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
// TRANS: Client error displayed trying to execute an unknown API method showing friendship.
$this->clientError(_('API method not found.'), 404); $this->clientError(_('API method not found.'), 404);
return; return;
} }
if (empty($this->source)) { if (empty($this->source)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when a source user could not be determined showing friendship.
_('Could not determine source user.'), _('Could not determine source user.'),
404 404
); );
@ -139,6 +136,7 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
if (empty($this->target)) { if (empty($this->target)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when a target user could not be determined showing friendship.
_('Could not find target user.'), _('Could not find target user.'),
404 404
); );
@ -161,7 +159,6 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
default: default:
break; break;
} }
} }
/** /**
@ -178,5 +175,4 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
{ {
return true; return true;
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupCreateAction extends ApiAuthAction class ApiGroupCreateAction extends ApiAuthAction
{ {
var $group = null; var $group = null;
@ -67,16 +66,14 @@ class ApiGroupCreateAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
$this->user = $this->auth_user; $this->user = $this->auth_user;
$this->nickname = $this->arg('nickname'); $this->nickname = Nickname::normalize($this->arg('nickname'));
$this->fullname = $this->arg('full_name'); $this->fullname = $this->arg('full_name');
$this->homepage = $this->arg('homepage'); $this->homepage = $this->arg('homepage');
$this->description = $this->arg('description'); $this->description = $this->arg('description');
@ -95,13 +92,13 @@ class ApiGroupCreateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -110,6 +107,7 @@ class ApiGroupCreateAction extends ApiAuthAction
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error given when a user was not found (404).
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -136,13 +134,13 @@ class ApiGroupCreateAction extends ApiAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error given when an API method was not found (404).
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
); );
break; break;
} }
} }
/** /**
@ -150,29 +148,11 @@ class ApiGroupCreateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function validateParams() function validateParams()
{ {
$valid = Validate::string( if ($this->groupNicknameExists($this->nickname)) {
$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( $this->clientError(
// TRANS: Client error trying to create a group with a nickname this is already in use.
_('Nickname already in use. Try another one.'), _('Nickname already in use. Try another one.'),
403, 403,
$this->format $this->format
@ -180,6 +160,7 @@ class ApiGroupCreateAction extends ApiAuthAction
return false; return false;
} else if (!User_group::allowedNickname($this->nickname)) { } else if (!User_group::allowedNickname($this->nickname)) {
$this->clientError( $this->clientError(
// TRANS: Client error in form for group creation.
_('Not a valid nickname.'), _('Not a valid nickname.'),
403, 403,
$this->format $this->format
@ -196,6 +177,7 @@ class ApiGroupCreateAction extends ApiAuthAction
) )
)) { )) {
$this->clientError( $this->clientError(
// TRANS: Client error in form for group creation.
_('Homepage is not a valid URL.'), _('Homepage is not a valid URL.'),
403, 403,
$this->format $this->format
@ -205,7 +187,8 @@ class ApiGroupCreateAction extends ApiAuthAction
!is_null($this->fullname) !is_null($this->fullname)
&& mb_strlen($this->fullname) > 255) { && mb_strlen($this->fullname) > 255) {
$this->clientError( $this->clientError(
_('Full name is too long (max 255 chars).'), // TRANS: Client error in form for group creation.
_('Full name is too long (maximum 255 characters).'),
403, 403,
$this->format $this->format
); );
@ -213,7 +196,11 @@ class ApiGroupCreateAction extends ApiAuthAction
} elseif (User_group::descriptionTooLong($this->description)) { } elseif (User_group::descriptionTooLong($this->description)) {
$this->clientError( $this->clientError(
sprintf( sprintf(
_('Description is too long (max %d chars).'), // TRANS: Client error shown when providing too long a description during group creation.
// TRANS: %d is the maximum number of allowed characters.
_m('Description is too long (maximum %d character).',
'Description is too long (maximum %d characters).',
User_group::maxDescription()),
User_group::maxDescription() User_group::maxDescription()
), ),
403, 403,
@ -224,7 +211,8 @@ class ApiGroupCreateAction extends ApiAuthAction
!is_null($this->location) !is_null($this->location)
&& mb_strlen($this->location) > 255) { && mb_strlen($this->location) > 255) {
$this->clientError( $this->clientError(
_('Location is too long (max 255 chars).'), // TRANS: Client error shown when providing too long a location during group creation.
_('Location is too long (maximum 255 characters).'),
403, 403,
$this->format $this->format
); );
@ -243,7 +231,11 @@ class ApiGroupCreateAction extends ApiAuthAction
if (count($this->aliases) > common_config('group', 'maxaliases')) { if (count($this->aliases) > common_config('group', 'maxaliases')) {
$this->clientError( $this->clientError(
sprintf( sprintf(
_('Too many aliases! Maximum %d.'), // TRANS: Client error shown when providing too many aliases during group creation.
// TRANS: %d is the maximum number of allowed aliases.
_m('Too many aliases! Maximum %d allowed.',
'Too many aliases! Maximum %d allowed.',
common_config('group', 'maxaliases')),
common_config('group', 'maxaliases') common_config('group', 'maxaliases')
), ),
403, 403,
@ -254,16 +246,10 @@ class ApiGroupCreateAction extends ApiAuthAction
foreach ($this->aliases as $alias) { foreach ($this->aliases as $alias) {
$valid = Validate::string( if (!Nickname::isValid($alias)) {
$alias, array(
'min_length' => 1,
'max_length' => 64,
'format' => NICKNAME_FMT
)
);
if (!$valid) {
$this->clientError( $this->clientError(
// TRANS: Client error shown when providing an invalid alias during group creation.
// TRANS: %s is the invalid alias.
sprintf(_('Invalid alias: "%s".'), $alias), sprintf(_('Invalid alias: "%s".'), $alias),
403, 403,
$this->format $this->format
@ -273,6 +259,8 @@ class ApiGroupCreateAction extends ApiAuthAction
if ($this->groupNicknameExists($alias)) { if ($this->groupNicknameExists($alias)) {
$this->clientError( $this->clientError(
sprintf( sprintf(
// TRANS: Client error displayed when trying to use an alias during group creation that is already in use.
// TRANS: %s is the alias that is already in use.
_('Alias "%s" already in use. Try another one.'), _('Alias "%s" already in use. Try another one.'),
$alias $alias
), ),
@ -286,6 +274,7 @@ class ApiGroupCreateAction extends ApiAuthAction
if (strcmp($alias, $this->nickname) == 0) { if (strcmp($alias, $this->nickname) == 0) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to use an alias during group creation that is the same as the group's nickname.
_('Alias can\'t be the same as nickname.'), _('Alias can\'t be the same as nickname.'),
403, 403,
$this->format $this->format
@ -294,7 +283,7 @@ class ApiGroupCreateAction extends ApiAuthAction
} }
} }
// Evarything looks OK // Everything looks OK
return true; return true;
} }
@ -306,7 +295,6 @@ class ApiGroupCreateAction extends ApiAuthAction
* *
* @return boolean true or false * @return boolean true or false
*/ */
function groupNicknameExists($nickname) function groupNicknameExists($nickname)
{ {
$local = Local_group::staticGet('nickname', $nickname); $local = Local_group::staticGet('nickname', $nickname);
@ -323,5 +311,4 @@ class ApiGroupCreateAction extends ApiAuthAction
return false; return false;
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupIsMemberAction extends ApiBareAuthAction class ApiGroupIsMemberAction extends ApiBareAuthAction
{ {
var $group = null; var $group = null;
@ -60,7 +59,6 @@ class ApiGroupIsMemberAction extends ApiBareAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
@ -82,17 +80,18 @@ class ApiGroupIsMemberAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when checking group membership for a non-existing user.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
if (empty($this->group)) { if (empty($this->group)) {
// TRANS: Client error displayed when checking group membership for a non-existing group.
$this->clientError(_('Group not found.'), 404, $this->format); $this->clientError(_('Group not found.'), 404, $this->format);
return false; return false;
} }
@ -112,6 +111,7 @@ class ApiGroupIsMemberAction extends ApiBareAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method showing group membership.
_('API method not found.'), _('API method not found.'),
400, 400,
$this->format $this->format
@ -129,10 +129,8 @@ class ApiGroupIsMemberAction extends ApiBareAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupJoinAction extends ApiAuthAction class ApiGroupJoinAction extends ApiAuthAction
{ {
var $group = null; var $group = null;
@ -60,9 +59,7 @@ class ApiGroupJoinAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -82,13 +79,13 @@ class ApiGroupJoinAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -97,17 +94,20 @@ class ApiGroupJoinAction extends ApiAuthAction
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when trying to have a non-existing user join a group.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
if (empty($this->group)) { if (empty($this->group)) {
// TRANS: Client error displayed when trying to join a group that does not exist.
$this->clientError(_('Group not found.'), 404, $this->format); $this->clientError(_('Group not found.'), 404, $this->format);
return false; return false;
} }
if ($this->user->isMember($this->group)) { if ($this->user->isMember($this->group)) {
$this->clientError( $this->clientError(
// TRANS: Server error displayed when trying to join a group the user is already a member of.
_('You are already a member of that group.'), _('You are already a member of that group.'),
403, 403,
$this->format $this->format
@ -117,6 +117,7 @@ class ApiGroupJoinAction extends ApiAuthAction
if (Group_block::isBlocked($this->group, $this->user->getProfile())) { if (Group_block::isBlocked($this->group, $this->user->getProfile())) {
$this->clientError( $this->clientError(
// TRANS: Server error displayed when trying to join a group the user is blocked from joining.
_('You have been blocked from that group by the admin.'), _('You have been blocked from that group by the admin.'),
403, 403,
$this->format $this->format
@ -136,6 +137,8 @@ class ApiGroupJoinAction extends ApiAuthAction
common_log_db_error($member, 'INSERT', __FILE__); common_log_db_error($member, 'INSERT', __FILE__);
$this->serverError( $this->serverError(
sprintf( sprintf(
// TRANS: Server error displayed when joining a group fails.
// TRANS: %1$s is a user nickname, $2$s is a group nickname.
_('Could not join user %1$s to group %2$s.'), _('Could not join user %1$s to group %2$s.'),
$this->user->nickname, $this->user->nickname,
$this->group->nickname $this->group->nickname
@ -153,6 +156,7 @@ class ApiGroupJoinAction extends ApiAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method joining a group.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -160,5 +164,4 @@ class ApiGroupJoinAction extends ApiAuthAction
break; break;
} }
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupLeaveAction extends ApiAuthAction class ApiGroupLeaveAction extends ApiAuthAction
{ {
var $group = null; var $group = null;
@ -60,9 +59,7 @@ class ApiGroupLeaveAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -82,13 +79,13 @@ class ApiGroupLeaveAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -97,11 +94,13 @@ class ApiGroupLeaveAction extends ApiAuthAction
} }
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when trying to have a non-existing user leave a group.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
if (empty($this->group)) { if (empty($this->group)) {
// TRANS: Client error displayed when trying to leave a group that does not exist.
$this->clientError(_('Group not found.'), 404, $this->format); $this->clientError(_('Group not found.'), 404, $this->format);
return false; return false;
} }
@ -112,6 +111,7 @@ class ApiGroupLeaveAction extends ApiAuthAction
$member->profile_id = $this->auth_user->id; $member->profile_id = $this->auth_user->id;
if (!$member->find(true)) { if (!$member->find(true)) {
// TRANS: Server error displayed when trying to leave a group the user is not a member of.
$this->serverError(_('You are not a member of this group.')); $this->serverError(_('You are not a member of this group.'));
return; return;
} }
@ -122,6 +122,8 @@ class ApiGroupLeaveAction extends ApiAuthAction
common_log_db_error($member, 'DELETE', __FILE__); common_log_db_error($member, 'DELETE', __FILE__);
$this->serverError( $this->serverError(
sprintf( sprintf(
// TRANS: Server error displayed when leaving a group fails.
// TRANS: %1$s is a user nickname, $2$s is a group nickname.
_('Could not remove user %1$s from group %2$s.'), _('Could not remove user %1$s from group %2$s.'),
$this->user->nickname, $this->user->nickname,
$this->group->nickname $this->group->nickname
@ -139,6 +141,7 @@ class ApiGroupLeaveAction extends ApiAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method leaving a group.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -146,5 +149,4 @@ class ApiGroupLeaveAction extends ApiAuthAction
break; break;
} }
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupListAction extends ApiBareAuthAction class ApiGroupListAction extends ApiBareAuthAction
{ {
var $groups = null; var $groups = null;
@ -60,9 +59,7 @@ class ApiGroupListAction extends ApiBareAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -88,13 +85,12 @@ class ApiGroupListAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
$sitename = common_config('site', 'name'); $sitename = common_config('site', 'name');
// TRANS: %s is a user name // TRANS: Used as title in check for group membership. %s is a user name.
$title = sprintf(_("%s's groups"), $this->user->nickname); $title = sprintf(_("%s's groups"), $this->user->nickname);
$taguribase = TagURI::base(); $taguribase = TagURI::base();
$id = "tag:$taguribase:Groups"; $id = "tag:$taguribase:Groups";
@ -104,8 +100,8 @@ class ApiGroupListAction extends ApiBareAuthAction
); );
$subtitle = sprintf( $subtitle = sprintf(
// TRANS: Meant to convey the user %2$s is a member of each of the groups listed on site %1$s // TRANS: Used as subtitle in check for group membership. %1$s is a user name, %2$s is the site name.
_("%1\$s groups %2\$s is a member of."), _('%1$s groups %2$s is a member of.'),
$sitename, $sitename,
$this->user->nickname $this->user->nickname
); );
@ -134,13 +130,13 @@ class ApiGroupListAction extends ApiBareAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method checking group membership.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
); );
break; break;
} }
} }
/** /**
@ -148,7 +144,6 @@ class ApiGroupListAction extends ApiBareAuthAction
* *
* @return array groups * @return array groups
*/ */
function getGroups() function getGroups()
{ {
$groups = array(); $groups = array();
@ -174,7 +169,6 @@ class ApiGroupListAction extends ApiBareAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -203,7 +197,6 @@ class ApiGroupListAction extends ApiBareAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->groups) && (count($this->groups) > 0)) { if (!empty($this->groups) && (count($this->groups) > 0)) {
@ -213,6 +206,7 @@ class ApiGroupListAction extends ApiBareAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->user->id, $this->user->id,
strtotime($this->groups[0]->created), strtotime($this->groups[0]->created),
@ -223,5 +217,4 @@ class ApiGroupListAction extends ApiBareAuthAction
return null; return null;
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupListAllAction extends ApiPrivateAuthAction class ApiGroupListAllAction extends ApiPrivateAuthAction
{ {
var $groups = null; var $groups = null;
@ -60,9 +59,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -82,17 +79,17 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
$sitename = common_config('site', 'name'); $sitename = common_config('site', 'name');
// TRANS: Message is used as a title. %s is a site name. // TRANS: Message is used as a title when listing the lastest 20 groups. %s is a site name.
$title = sprintf(_("%s groups"), $sitename); $title = sprintf(_("%s groups"), $sitename);
$taguribase = TagURI::base(); $taguribase = TagURI::base();
$id = "tag:$taguribase:Groups"; $id = "tag:$taguribase:Groups";
$link = common_local_url('groups'); $link = common_local_url('groups');
// TRANS: Message is used as a subtitle when listing the lastest 20 groups. %s is a site name.
$subtitle = sprintf(_("groups on %s"), $sitename); $subtitle = sprintf(_("groups on %s"), $sitename);
switch($this->format) { switch($this->format) {
@ -119,13 +116,13 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method listing the latest 20 groups.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
); );
break; break;
} }
} }
/** /**
@ -133,7 +130,6 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return array groups * @return array groups
*/ */
function getGroups() function getGroups()
{ {
$qry = 'SELECT user_group.* '. $qry = 'SELECT user_group.* '.
@ -165,7 +161,6 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -176,7 +171,6 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return string datestamp of the site's latest group * @return string datestamp of the site's latest group
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->groups) && (count($this->groups) > 0)) { if (!empty($this->groups) && (count($this->groups) > 0)) {
@ -194,7 +188,6 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->groups) && (count($this->groups) > 0)) { if (!empty($this->groups) && (count($this->groups) > 0)) {
@ -204,6 +197,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
strtotime($this->groups[0]->created), strtotime($this->groups[0]->created),
strtotime($this->groups[$last]->created)) strtotime($this->groups[$last]->created))
@ -213,5 +207,4 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
return null; return null;
} }
} }

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupMembershipAction extends ApiPrivateAuthAction class ApiGroupMembershipAction extends ApiPrivateAuthAction
{ {
var $group = null; var $group = null;
@ -61,9 +60,7 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -83,12 +80,12 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (empty($this->group)) { if (empty($this->group)) {
// TRANS: Client error displayed trying to show group membership on a non-existing group.
$this->clientError(_('Group not found.'), 404, $this->format); $this->clientError(_('Group not found.'), 404, $this->format);
return false; return false;
} }
@ -104,6 +101,7 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method showing group membership.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -117,7 +115,6 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
* *
* @return array $profiles list of profiles * @return array $profiles list of profiles
*/ */
function getProfiles() function getProfiles()
{ {
$profiles = array(); $profiles = array();
@ -143,7 +140,6 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -154,7 +150,6 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
* *
* @return string datestamp of the lastest profile in the group * @return string datestamp of the lastest profile in the group
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->profiles) && (count($this->profiles) > 0)) { if (!empty($this->profiles) && (count($this->profiles) > 0)) {
@ -173,7 +168,6 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->profiles) && (count($this->profiles) > 0)) { if (!empty($this->profiles) && (count($this->profiles) > 0)) {
@ -183,6 +177,7 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->group->id, $this->group->id,
strtotime($this->profiles[0]->created), strtotime($this->profiles[0]->created),
@ -193,5 +188,4 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
return null; return null;
} }
} }

View File

@ -50,7 +50,6 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiGroupShowAction extends ApiPrivateAuthAction class ApiGroupShowAction extends ApiPrivateAuthAction
{ {
var $group = null; var $group = null;
@ -61,9 +60,7 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -80,6 +77,7 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
common_redirect(common_local_url('ApiGroupShow', $args), 301); common_redirect(common_local_url('ApiGroupShow', $args), 301);
} else { } else {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to show a group that could not be found.
_('Group not found.'), _('Group not found.'),
404, 404,
$this->format $this->format
@ -100,7 +98,6 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -113,6 +110,7 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
$this->showSingleJsonGroup($this->group); $this->showSingleJsonGroup($this->group);
break; break;
default: default:
// TRANS: Client error displayed trying to execute an unknown API method showing a group.
$this->clientError(_('API method not found.'), 404, $this->format); $this->clientError(_('API method not found.'), 404, $this->format);
break; break;
} }
@ -123,7 +121,6 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->group)) { if (!empty($this->group)) {
@ -141,7 +138,6 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->group)) { if (!empty($this->group)) {
@ -149,6 +145,7 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->group->id, $this->group->id,
strtotime($this->group->modified)) strtotime($this->group->modified))
@ -168,10 +165,8 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

View File

@ -44,19 +44,15 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiHelpTestAction extends ApiPrivateAuthAction class ApiHelpTestAction extends ApiPrivateAuthAction
{ {
/** /**
* Take arguments for running * Take arguments for running
* *
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -70,7 +66,6 @@ class ApiHelpTestAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -85,6 +80,7 @@ class ApiHelpTestAction extends ApiPrivateAuthAction
$this->endDocument('json'); $this->endDocument('json');
} else { } else {
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method testing API connectivity.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -101,11 +97,8 @@ class ApiHelpTestAction extends ApiPrivateAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

View File

@ -43,7 +43,6 @@ require_once INSTALLDIR . '/lib/mediafile.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiMediaUploadAction extends ApiAuthAction class ApiMediaUploadAction extends ApiAuthAction
{ {
/** /**
@ -57,13 +56,13 @@ class ApiMediaUploadAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, $this->format 400, $this->format
); );
@ -77,9 +76,11 @@ class ApiMediaUploadAction extends ApiAuthAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
@ -96,6 +97,7 @@ class ApiMediaUploadAction extends ApiAuthAction
if (isset($upload)) { if (isset($upload)) {
$this->showResponse($upload); $this->showResponse($upload);
} else { } else {
// TRANS: Client error displayed when uploading a media file has failed.
$this->clientError(_('Upload failed.')); $this->clientError(_('Upload failed.'));
return; return;
} }
@ -123,7 +125,6 @@ class ApiMediaUploadAction extends ApiAuthAction
* Overrided clientError to show a more Twitpic-like error * Overrided clientError to show a more Twitpic-like error
* *
* @param String $msg an error message * @param String $msg an error message
*
*/ */
function clientError($msg) function clientError($msg)
{ {
@ -137,5 +138,4 @@ class ApiMediaUploadAction extends ApiAuthAction
$this->elementEnd('rsp'); $this->elementEnd('rsp');
$this->endDocument(); $this->endDocument();
} }
} }

View File

@ -2,7 +2,8 @@
/** /**
* StatusNet, the distributed open-source microblogging tool * StatusNet, the distributed open-source microblogging tool
* *
* Exchange an authorized OAuth request token for an access token * Action for getting OAuth token credentials (exchange an authorized
* request token for an access token)
* *
* PHP version 5 * PHP version 5
* *
@ -34,7 +35,8 @@ if (!defined('STATUSNET')) {
require_once INSTALLDIR . '/lib/apioauth.php'; require_once INSTALLDIR . '/lib/apioauth.php';
/** /**
* Exchange an authorized OAuth request token for an access token * Action for getting OAuth token credentials (exchange an authorized
* request token for an access token)
* *
* @category API * @category API
* @package StatusNet * @package StatusNet
@ -42,9 +44,10 @@ require_once INSTALLDIR . '/lib/apioauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiOauthAccessTokenAction extends ApiOauthAction class ApiOauthAccessTokenAction extends ApiOauthAction
{ {
protected $reqToken = null;
protected $verifier = null;
/** /**
* Class handler. * Class handler.
@ -63,32 +66,61 @@ class ApiOauthAccessTokenAction extends ApiOauthAction
$server->add_signature_method($hmac_method); $server->add_signature_method($hmac_method);
$atok = null; $atok = $app = null;
// XXX: Insist that oauth_token and oauth_verifier be populated?
// Spec doesn't say they MUST be.
try { try {
$req = OAuthRequest::from_request(); $req = OAuthRequest::from_request();
$atok = $server->fetch_access_token($req);
} catch (OAuthException $e) { $this->reqToken = $req->get_parameter('oauth_token');
$this->verifier = $req->get_parameter('oauth_verifier');
$app = $datastore->getAppByRequestToken($this->reqToken);
$atok = $server->fetch_access_token($req);
} catch (Exception $e) {
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage()); common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
common_debug(var_export($req, true)); common_debug(var_export($req, true));
$this->outputError($e->getMessage()); $code = $e->getCode();
return; $this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
} }
if (empty($atok)) { if (empty($atok)) {
common_debug('couldn\'t get access token.'); // Token exchange failed -- log it
print "Token exchange failed. Has the request token been authorized?\n";
$msg = sprintf(
'API OAuth - Failure exchanging OAuth request token for access token, '
. 'request token = %s, verifier = %s',
$this->reqToken,
$this->verifier
);
common_log(LOG_WARNING, $msg);
// TRANS: Client error given from the OAuth API when the request token or verifier is invalid.
$this->clientError(_("Invalid request token or verifier.", 400, 'text'));
} else { } else {
print $atok; common_log(
LOG_INFO,
sprintf(
"Issued access token '%s' for application %d (%s).",
$atok->key,
$app->id,
$app->name
)
);
$this->showAccessToken($atok);
} }
} }
function outputError($msg) /*
* Display OAuth token credentials
*
* @param OAuthToken token the access token
*/
function showAccessToken($token)
{ {
header('HTTP/1.1 401 Unauthorized'); header('Content-Type: application/x-www-form-urlencoded');
header('Content-Type: text/html; charset=utf-8'); print $token;
print $msg . "\n";
} }
} }

View File

@ -32,9 +32,10 @@ if (!defined('STATUSNET')) {
} }
require_once INSTALLDIR . '/lib/apioauth.php'; require_once INSTALLDIR . '/lib/apioauth.php';
require_once INSTALLDIR . '/lib/info.php';
/** /**
* Authorize an OAuth request token * Authorize an Oputh request token
* *
* @category API * @category API
* @package StatusNet * @package StatusNet
@ -42,10 +43,10 @@ require_once INSTALLDIR . '/lib/apioauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiOauthAuthorizeAction extends Action
class ApiOauthAuthorizeAction extends ApiOauthAction
{ {
var $oauth_token; var $oauthTokenParam;
var $reqToken;
var $callback; var $callback;
var $app; var $app;
var $nickname; var $nickname;
@ -57,7 +58,6 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
* *
* @return boolean false * @return boolean false
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return false; return false;
@ -67,12 +67,17 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
{ {
parent::prepare($args); parent::prepare($args);
$this->nickname = $this->trimmed('nickname'); $this->nickname = $this->trimmed('nickname');
$this->password = $this->arg('password'); $this->password = $this->arg('password');
$this->oauth_token = $this->arg('oauth_token'); $this->oauthTokenParam = $this->arg('oauth_token');
$this->callback = $this->arg('oauth_callback'); $this->mode = $this->arg('mode');
$this->store = new ApiStatusNetOAuthDataStore(); $this->store = new ApiStatusNetOAuthDataStore();
$this->app = $this->store->getAppByRequestToken($this->oauth_token);
try {
$this->app = $this->store->getAppByRequestToken($this->oauthTokenParam);
} catch (Exception $e) {
$this->clientError($e->getMessage());
}
return true; return true;
} }
@ -86,7 +91,6 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -97,14 +101,32 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
} else { } else {
if (empty($this->oauth_token)) { // Make sure a oauth_token parameter was provided
if (empty($this->oauthTokenParam)) {
// TRANS: Client error given when no oauth_token was passed to the OAuth API.
$this->clientError(_('No oauth_token parameter provided.')); $this->clientError(_('No oauth_token parameter provided.'));
return; } else {
// Check to make sure the token exists
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
if (empty($this->reqToken)) {
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
$this->clientError(_('Invalid request token.'));
} else {
// Check to make sure we haven't already authorized the token
if ($this->reqToken->state != 0) {
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
$this->clientError(_('Request token already authorized.'));
}
}
} }
// make sure there's an app associated with this token
if (empty($this->app)) { if (empty($this->app)) {
$this->clientError(_('Invalid token.')); // TRANS: Client error given when an invalid request token was passed to the OAuth API.
return; $this->clientError(_('Invalid request token.'));
} }
$name = $this->app->name; $name = $this->app->name;
@ -120,8 +142,9 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->showForm(_('There was a problem with your session token. '. $this->showForm(
'Try again, please.')); // TRANS: Form validation error in API OAuth authorisation because of an invalid session token.
_('There was a problem with your session token. Try again, please.'));
return; return;
} }
@ -130,8 +153,18 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
$user = null; $user = null;
if (!common_logged_in()) { if (!common_logged_in()) {
$user = common_check_user($this->nickname, $this->password);
// XXX Force credentials check?
// @fixme this should probably use a unified login form handler
$user = null;
if (Event::handle('StartOAuthLoginCheck', array($this, &$user))) {
$user = common_check_user($this->nickname, $this->password);
}
Event::handle('EndOAuthLoginCheck', array($this, &$user));
if (empty($user)) { if (empty($user)) {
// TRANS: Form validation error given when an invalid username and/or password was passed to the OAuth API.
$this->showForm(_("Invalid nickname / password!")); $this->showForm(_("Invalid nickname / password!"));
return; return;
} }
@ -139,101 +172,196 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
$user = common_current_user(); $user = common_current_user();
} }
// fetch the token
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
assert(!empty($this->reqToken));
if ($this->arg('allow')) { if ($this->arg('allow')) {
// mark the req token as authorized // mark the req token as authorized
try {
$this->store->authorize_token($this->oauth_token); $this->store->authorize_token($this->oauthTokenParam);
} catch (Exception $e) {
// Check to see if there was a previous token associated $this->serverError($e->getMessage());
// with this user/app and kill it. If the user is doing this she
// probably doesn't want any old tokens anyway.
$appUser = Oauth_application_user::getByKeys($user, $this->app);
if (!empty($appUser)) {
$result = $appUser->delete();
if (!$result) {
common_log_db_error($appUser, 'DELETE', __FILE__);
throw new ServerException(_('Database error deleting OAuth application user.'));
return;
}
} }
// associated the authorized req token with the user and the app common_log(
LOG_INFO,
sprintf(
"API OAuth - User %d (%s) has authorized request token %s for OAuth application %d (%s).",
$user->id,
$user->nickname,
$this->reqToken->tok,
$this->app->id,
$this->app->name
)
);
$appUser = new Oauth_application_user(); // XXX: Make sure we have a oauth_token_association table. The table
// is now in the main schema, but because it is being added with
// a point release, it's unlikely to be there. This code can be
// removed as of 1.0.
$this->ensureOauthTokenAssociationTable();
$appUser->profile_id = $user->id; $tokenAssoc = new Oauth_token_association();
$appUser->application_id = $this->app->id;
// Note: do not copy the access type from the application. $tokenAssoc->profile_id = $user->id;
// The access type should always be 0 when the OAuth app $tokenAssoc->application_id = $this->app->id;
// user record has a request token associated with it. $tokenAssoc->token = $this->oauthTokenParam;
// Access type gets assigned once an access token has been $tokenAssoc->created = common_sql_now();
// granted. The OAuth app user record then gets updated
// with the new access token and access type.
$appUser->token = $this->oauth_token; $result = $tokenAssoc->insert();
$appUser->created = common_sql_now();
$result = $appUser->insert();
if (!$result) { if (!$result) {
common_log_db_error($appUser, 'INSERT', __FILE__); common_log_db_error($tokenAssoc, 'INSERT', __FILE__);
throw new ServerException(_('Database error inserting OAuth application user.')); // TRANS: Server error displayed when a database action fails.
return; $this->serverError(_('Database error inserting oauth_token_association.'));
} }
// if we have a callback redirect and provide the token $callback = $this->getCallback();
// A callback specified in the app setup overrides whatever if (!empty($callback) && $this->reqToken->verified_callback != 'oob') {
// is passed in with the request. $targetUrl = $this->buildCallbackUrl(
$callback,
array(
'oauth_token' => $this->oauthTokenParam,
'oauth_verifier' => $this->reqToken->verifier // 1.0a
)
);
if (!empty($this->app->callback_url)) { common_log(LOG_INFO, "Redirecting to callback: $targetUrl");
$this->callback = $this->app->callback_url;
// Redirect the user to the provided OAuth callback
common_redirect($targetUrl, 303);
} elseif ($this->app->type == 2) {
// Strangely, a web application seems to want to do the OOB
// workflow. Because no callback was specified anywhere.
common_log(
LOG_WARNING,
sprintf(
"API OAuth - No callback provided for OAuth web client ID %s (%s) "
. "during authorization step. Falling back to OOB workflow.",
$this->app->id,
$this->app->name
)
);
} }
if (!empty($this->callback)) { // Otherwise, inform the user that the rt was authorized
$this->showAuthorized();
} else if ($this->arg('cancel')) {
common_log(
LOG_INFO,
sprintf(
"API OAuth - User %d (%s) refused to authorize request token %s for OAuth application %d (%s).",
$user->id,
$user->nickname,
$this->reqToken->tok,
$this->app->id,
$this->app->name
)
);
$target_url = $this->getCallback($this->callback, try {
array('oauth_token' => $this->oauth_token)); $this->store->revoke_token($this->oauthTokenParam, 0);
} catch (Exception $e) {
common_redirect($target_url, 303); $this->ServerError($e->getMessage());
} else {
common_debug("callback was empty!");
} }
// otherwise inform the user that the rt was authorized $callback = $this->getCallback();
$this->elementStart('p'); // If there's a callback available, inform the consumer the user
// has refused authorization
if (!empty($callback) && $this->reqToken->verified_callback != 'oob') {
$targetUrl = $this->buildCallbackUrl(
$callback,
array(
'oauth_problem' => 'user_refused',
)
);
// XXX: Do OAuth 1.0a verifier code common_log(LOG_INFO, "Redirecting to callback: $targetUrl");
$this->raw(sprintf(_("The request token %s has been authorized. " . // Redirect the user to the provided OAuth callback
'Please exchange it for an access token.'), common_redirect($targetUrl, 303);
$this->oauth_token)); }
$this->elementEnd('p'); // otherwise inform the user that authorization for the rt was declined
$this->showCanceled();
} else if ($this->arg('deny')) {
$datastore = new ApiStatusNetOAuthDataStore();
$datastore->revoke_token($this->oauth_token, 0);
$this->elementStart('p');
$this->raw(sprintf(_("The request token %s has been denied and revoked."),
$this->oauth_token));
$this->elementEnd('p');
} else { } else {
// TRANS: Client error given on when invalid data was passed through a form in the OAuth API.
$this->clientError(_('Unexpected form submission.')); $this->clientError(_('Unexpected form submission.'));
return;
} }
} }
// XXX Remove this function when we hit 1.0
function ensureOauthTokenAssociationTable()
{
$schema = Schema::get();
$reqTokenCols = array(
new ColumnDef('profile_id', 'integer', null, true, 'PRI'),
new ColumnDef('application_id', 'integer', null, true, 'PRI'),
new ColumnDef('token', 'varchar', 255, true, 'PRI'),
new ColumnDef('created', 'datetime', null, false),
new ColumnDef(
'modified',
'timestamp',
null,
false,
null,
'CURRENT_TIMESTAMP',
'on update CURRENT_TIMESTAMP'
)
);
$schema->ensureTable('oauth_token_association', $reqTokenCols);
}
/**
* Show body - override to add a special CSS class for the authorize
* page's "desktop mode" (minimal display)
*
* Calls template methods
*
* @return nothing
*/
function showBody()
{
$bodyClasses = array();
if ($this->desktopMode()) {
$bodyClasses[] = 'oauth-desktop-mode';
}
if (common_current_user()) {
$bodyClasses[] = 'user_in';
}
$attrs = array('id' => strtolower($this->trimmed('action')));
if (!empty($bodyClasses)) {
$attrs['class'] = implode(' ', $bodyClasses);
}
$this->elementStart('body', $attrs);
$this->elementStart('div', array('id' => 'wrap'));
if (Event::handle('StartShowHeader', array($this))) {
$this->showHeader();
Event::handle('EndShowHeader', array($this));
}
$this->showCore();
if (Event::handle('StartShowFooter', array($this))) {
$this->showFooter();
Event::handle('EndShowFooter', array($this));
}
$this->elementEnd('div');
$this->showScripts();
$this->elementEnd('body');
}
function showForm($error=null) function showForm($error=null)
{ {
$this->error = $error; $this->error = $error;
@ -253,9 +381,9 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
* *
* @return string title of the page * @return string title of the page
*/ */
function title() function title()
{ {
// TRANS: Title for a page where a user can confirm/deny account access by an external application.
return _('An application would like to connect to your account'); return _('An application would like to connect to your account');
} }
@ -264,36 +392,50 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
* *
* @return void * @return void
*/ */
function showContent() function showContent()
{ {
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
'id' => 'form_apioauthauthorize', 'id' => 'form_apioauthauthorize',
'class' => 'form_settings', 'class' => 'form_settings',
'action' => common_local_url('apioauthauthorize'))); 'action' => common_local_url('ApiOauthAuthorize')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
$this->element('legend', array('id' => 'apioauthauthorize_allowdeny'), $this->element('legend', array('id' => 'apioauthauthorize_allowdeny'),
// TRANS: Fieldset legend.
_('Allow or deny access')); _('Allow or deny access'));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->hidden('oauth_token', $this->oauth_token); $this->hidden('mode', $this->mode);
$this->hidden('oauth_token', $this->oauthTokenParam);
$this->hidden('oauth_callback', $this->callback); $this->hidden('oauth_callback', $this->callback);
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
$this->elementStart('p'); $this->elementStart('p');
if (!empty($this->app->icon)) { if (!empty($this->app->icon) && $this->app->name != 'anonymous') {
$this->element('img', array('src' => $this->app->icon)); $this->element('img', array('src' => $this->app->icon));
} }
$access = ($this->app->access_type & Oauth_application::$writeAccess) ? $access = ($this->app->access_type & Oauth_application::$writeAccess) ?
'access and update' : 'access'; 'access and update' : 'access';
$msg = _('The application <strong>%1$s</strong> by ' . if ($this->app->name == 'anonymous') {
'<strong>%2$s</strong> would like the ability ' . // Special message for the anonymous app and consumer.
// TRANS: User notification of external application requesting account access.
// TRANS: %3$s is the access type requested (read-write or read-only), %4$s is the StatusNet sitename.
$msg = _('An application would like the ability ' .
'to <strong>%3$s</strong> your %4$s account data. ' . 'to <strong>%3$s</strong> your %4$s account data. ' .
'You should only give access to your %4$s account ' . 'You should only give access to your %4$s account ' .
'to third parties you trust.'); 'to third parties you trust.');
} else {
// TRANS: User notification of external application requesting account access.
// TRANS: %1$s is the application name requesting access, %2$s is the organisation behind the application,
// TRANS: %3$s is the access type requested, %4$s is the StatusNet sitename.
$msg = _('The application <strong>%1$s</strong> by ' .
'<strong>%2$s</strong> would like the ability ' .
'to <strong>%3$s</strong> your %4$s account data. ' .
'You should only give access to your %4$s account ' .
'to third parties you trust.');
}
$this->raw(sprintf($msg, $this->raw(sprintf($msg,
$this->app->name, $this->app->name,
@ -304,34 +446,43 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
// quickie hack
$button = false;
if (!common_logged_in()) { if (!common_logged_in()) {
if (Event::handle('StartOAuthLoginForm', array($this, &$button))) {
$this->elementStart('fieldset');
// TRANS: Fieldset legend.
$this->element('legend', null, _m('LEGEND','Account'));
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
// TRANS: Field label on OAuth API authorisation form.
$this->input('nickname', _('Nickname'));
$this->elementEnd('li');
$this->elementStart('li');
// TRANS: Field label on OAuth API authorisation form.
$this->password('password', _('Password'));
$this->elementEnd('li');
$this->elementEnd('ul');
$this->elementStart('fieldset'); $this->elementEnd('fieldset');
$this->element('legend', null, _('Account')); }
$this->elementStart('ul', 'form_data'); Event::handle('EndOAuthLoginForm', array($this, &$button));
$this->elementStart('li');
$this->input('nickname', _('Nickname'));
$this->elementEnd('li');
$this->elementStart('li');
$this->password('password', _('Password'));
$this->elementEnd('li');
$this->elementEnd('ul');
$this->elementEnd('fieldset');
} }
$this->element('input', array('id' => 'deny_submit', $this->element('input', array('id' => 'cancel_submit',
'class' => 'submit submit form_action-primary', 'class' => 'submit submit form_action-primary',
'name' => 'deny', 'name' => 'cancel',
'type' => 'submit', 'type' => 'submit',
'value' => _('Deny'))); // TRANS: Button text that when clicked will cancel the process of allowing access to an account
// TRANS: by an external application.
'value' => _m('BUTTON','Cancel')));
$this->element('input', array('id' => 'allow_submit', $this->element('input', array('id' => 'allow_submit',
'class' => 'submit submit form_action-secondary', 'class' => 'submit submit form_action-secondary',
'name' => 'allow', 'name' => 'allow',
'type' => 'submit', 'type' => 'submit',
'value' => _('Allow'))); // TRANS: Button text that when clicked will allow access to an account by an external application.
'value' => $button ? $button : _m('BUTTON','Allow')));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
@ -345,10 +496,10 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
* *
* @return void * @return void
*/ */
function getInstructions() function getInstructions()
{ {
return _('Allow or deny access to your account information.'); // TRANS: Form instructions.
return _('Authorize access to your account information.');
} }
/** /**
@ -358,18 +509,61 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
* *
* @return void * @return void
*/ */
function showLocalNav() function showLocalNav()
{ {
// NOP // NOP
} }
/*
* Checks to see if a the "mode" parameter is present in the request
* and set to "desktop". If it is, the page is meant to be displayed in
* a small frame of another application, and we should suppress the
* header, aside, and footer.
*/
function desktopMode()
{
if (isset($this->mode) && $this->mode == 'desktop') {
return true;
} else {
return false;
}
}
/*
* Override - suppress output in "desktop" mode
*/
function showHeader()
{
if ($this->desktopMode() == false) {
parent::showHeader();
}
}
/*
* Override - suppress output in "desktop" mode
*/
function showAside()
{
if ($this->desktopMode() == false) {
parent::showAside();
}
}
/*
* Override - suppress output in "desktop" mode
*/
function showFooter()
{
if ($this->desktopMode() == false) {
parent::showFooter();
}
}
/** /**
* Show site notice. * Show site notice.
* *
* @return nothing * @return nothing
*/ */
function showSiteNotice() function showSiteNotice()
{ {
// NOP // NOP
@ -382,10 +576,165 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
* *
* @return nothing * @return nothing
*/ */
function showNoticeForm() function showNoticeForm()
{ {
// NOP // NOP
} }
/*
* Show a nice message confirming the authorization
* operation was canceled.
*
* @return nothing
*/
function showCanceled()
{
$info = new InfoAction(
// TRANS: Header for user notification after revoking OAuth access to an application.
_('Authorization canceled.'),
sprintf(
// TRANS: User notification after revoking OAuth access to an application.
// TRANS: %s is an OAuth token.
_('The request token %s has been revoked.'),
$this->oauthTokenParam
)
);
$info->showPage();
}
/*
* Show a nice message that the authorization was successful.
* If the operation is out-of-band, show a pin.
*
* @return nothing
*/
function showAuthorized()
{
$title = null;
$msg = null;
if ($this->app->name == 'anonymous') {
$title =
// TRANS: Title of the page notifying the user that an anonymous client application was successfully authorized to access the user's account with OAuth.
_('You have successfully authorized the application');
$msg =
// TRANS: Message notifying the user that an anonymous client application was successfully authorized to access the user's account with OAuth.
_('Please return to the application and enter the following security code to complete the process.');
} else {
$title = sprintf(
// TRANS: Title of the page notifying the user that the client application was successfully authorized to access the user's account with OAuth.
// TRANS: %s is the authorised application name.
_('You have successfully authorized %s'),
$this->app->name
);
$msg = sprintf(
// TRANS: Message notifying the user that the client application was successfully authorized to access the user's account with OAuth.
// TRANS: %s is the authorised application name.
_('Please return to %s and enter the following security code to complete the process.'),
$this->app->name
);
}
if ($this->reqToken->verified_callback == 'oob') {
$pin = new ApiOauthPinAction(
$title,
$msg,
$this->reqToken->verifier,
$this->desktopMode()
);
$pin->showPage();
} else {
// NOTE: This would only happen if an application registered as
// a web application but sent in 'oob' for the oauth_callback
// parameter. Usually web apps will send in a callback and
// not use the pin-based workflow.
$info = new InfoAction(
$title,
$msg,
$this->oauthTokenParam,
$this->reqToken->verifier
);
$info->showPage();
}
}
/*
* Figure out what the callback should be
*/
function getCallback()
{
$callback = null;
// Return the verified callback if we have one
if ($this->reqToken->verified_callback != 'oob') {
$callback = $this->reqToken->verified_callback;
// Otherwise return the callback that was provided when
// registering the app
if (empty($callback)) {
common_debug(
"No verified callback found for request token, using application callback: "
. $this->app->callback_url,
__FILE__
);
$callback = $this->app->callback_url;
}
}
return $callback;
}
/*
* Properly format the callback URL and parameters so it's
* suitable for a redirect in the OAuth dance
*
* @param string $url the URL
* @param array $params an array of parameters
*
* @return string $url a URL to use for redirecting to
*/
function buildCallbackUrl($url, $params)
{
foreach ($params as $k => $v) {
$url = $this->appendQueryVar(
$url,
OAuthUtil::urlencode_rfc3986($k),
OAuthUtil::urlencode_rfc3986($v)
);
}
return $url;
}
/*
* Append a new query parameter after any existing query
* parameters.
*
* @param string $url the URL
* @prarm string $k the parameter name
* @param string $v value of the paramter
*
* @return string $url the new URL with added parameter
*/
function appendQueryVar($url, $k, $v) {
$url = preg_replace('/(.*)(\?|&)' . $k . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
$url = substr($url, 0, -1);
if (strpos($url, '?') === false) {
return ($url . '?' . $k . '=' . $v);
} else {
return ($url . '&' . $k . '=' . $v);
}
}
} }

172
actions/apioauthpin.php Normal file
View File

@ -0,0 +1,172 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Action for displaying an OAuth verifier pin
*
* 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 Zach Copley <zach@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
/**
* Class for displaying an OAuth verifier pin
*
* XXX: I'm pretty sure we don't need to check the logged in state here. -- Zach
*
* @category Action
* @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 ApiOauthPinAction extends InfoAction
{
function __construct($title, $message, $verifier, $desktopMode = false)
{
$this->verifier = $verifier;
$this->title = $title;
$this->desktopMode = $desktopMode;
parent::__construct($title, $message);
}
/**
* Show body - override to add a special CSS class for the pin pages's
* "desktop mode" (minimal display)
*
* Calls template methods
*
* @return nothing
*/
function showBody()
{
$bodyClasses = array();
if ($this->desktopMode) {
$bodyClasses[] = 'oauth-desktop-mode';
}
if (common_current_user()) {
$bodyClasses[] = 'user_in';
}
$attrs = array('id' => strtolower($this->trimmed('action')));
if (!empty($bodyClasses)) {
$attrs['class'] = implode(' ', $bodyClasses);
}
$this->elementStart('body', $attrs);
$this->elementStart('div', array('id' => 'wrap'));
if (Event::handle('StartShowHeader', array($this))) {
$this->showHeader();
Event::handle('EndShowHeader', array($this));
}
$this->showCore();
if (Event::handle('StartShowFooter', array($this))) {
$this->showFooter();
Event::handle('EndShowFooter', array($this));
}
$this->elementEnd('div');
$this->showScripts();
$this->elementEnd('body');
}
/**
* A local menu
*
* Shows different login/register actions.
*
* @return void
*/
function showLocalNav()
{
// NOP
}
/*
* Override - suppress output in "desktop" mode
*/
function showHeader()
{
if ($this->desktopMode == false) {
parent::showHeader();
}
}
/*
* Override - suppress output in "desktop" mode
*/
function showAside()
{
if ($this->desktopMode == false) {
parent::showAside();
}
}
/*
* Override - suppress output in "desktop" mode
*/
function showFooter()
{
if ($this->desktopMode == false) {
parent::showFooter();
}
}
/**
* Show site notice.
*
* @return nothing
*/
function showSiteNotice()
{
// NOP
}
/**
* Show notice form.
*
* Show the form for posting a new notice
*
* @return nothing
*/
function showNoticeForm()
{
// NOP
}
/**
* Display content.
*
* @return nothing
*/
function showContent()
{
$this->element('div', array('class' => 'info'), $this->message);
$this->element('div', array('id' => 'oauth_pin'), $this->verifier);
}
}

View File

@ -2,7 +2,7 @@
/** /**
* StatusNet, the distributed open-source microblogging tool * StatusNet, the distributed open-source microblogging tool
* *
* Get an OAuth request token * Issue temporary OAuth credentials (a request token)
* *
* PHP version 5 * PHP version 5
* *
@ -34,7 +34,7 @@ if (!defined('STATUSNET')) {
require_once INSTALLDIR . '/lib/apioauth.php'; require_once INSTALLDIR . '/lib/apioauth.php';
/** /**
* Get an OAuth request token * Issue temporary OAuth credentials (a request token)
* *
* @category API * @category API
* @package StatusNet * @package StatusNet
@ -42,7 +42,6 @@ require_once INSTALLDIR . '/lib/apioauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiOauthRequestTokenAction extends ApiOauthAction class ApiOauthRequestTokenAction extends ApiOauthAction
{ {
/** /**
@ -51,24 +50,22 @@ class ApiOauthRequestTokenAction extends ApiOauthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
$this->callback = $this->arg('oauth_callback'); // XXX: support "force_login" parameter like Twitter? (Forces the user to enter
// their credentials to ensure the correct users account is authorized.)
if (!empty($this->callback)) {
common_debug("callback: $this->callback");
}
return true; return true;
} }
/** /**
* Class handler. * Handle a request for temporary OAuth credentials
*
* Make sure the request is kosher, then emit a set of temporary
* credentials -- AKA an unauthorized request token.
* *
* @param array $args array of arguments * @param array $args array of arguments
* *
@ -85,15 +82,73 @@ class ApiOauthRequestTokenAction extends ApiOauthAction
$server->add_signature_method($hmac_method); $server->add_signature_method($hmac_method);
try { try {
$req = OAuthRequest::from_request();
$req = OAuthRequest::from_request();
// verify callback
if (!$this->verifyCallback($req->get_parameter('oauth_callback'))) {
throw new OAuthException(
"You must provide a valid URL or 'oob' in oauth_callback.",
400
);
}
// check signature and issue a new request token
$token = $server->fetch_request_token($req); $token = $server->fetch_request_token($req);
print $token;
common_log(
LOG_INFO,
sprintf(
"API OAuth - Issued request token %s for consumer %s with oauth_callback %s",
$token->key,
$req->get_parameter('oauth_consumer_key'),
"'" . $req->get_parameter('oauth_callback') ."'"
)
);
// return token to the client
$this->showRequestToken($token);
} catch (OAuthException $e) { } catch (OAuthException $e) {
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage()); common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
header('HTTP/1.1 401 Unauthorized');
header('Content-Type: text/html; charset=utf-8'); // Return 401 for for bad credentials or signature problems,
print $e->getMessage() . "\n"; // and 400 for missing or unsupported parameters
$code = $e->getCode();
$this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
} }
} }
/*
* Display temporary OAuth credentials
*/
function showRequestToken($token)
{
header('Content-Type: application/x-www-form-urlencoded');
print $token;
print '&oauth_callback_confirmed=true';
}
/* Make sure the callback parameter contains either a real URL
* or the string 'oob'.
*
* @todo Check for evil/banned URLs here
*
* @return boolean true or false
*/
function verifyCallback($callback)
{
if ($callback == "oob") {
common_debug("OAuth request token requested for out of band client.");
// XXX: Should we throw an error if a client is registered as a
// web application but requests the pin based workflow? For now I'm
// allowing the workflow to proceed and issuing a pin. --Zach
return true;
} else {
return Validate::uri($callback);
}
}
} }

View File

@ -48,10 +48,8 @@ require_once INSTALLDIR.'/lib/apiprivateauth.php';
* *
* @see ApiPrivateAuthAction * @see ApiPrivateAuthAction
*/ */
class ApiSearchAtomAction extends ApiPrivateAuthAction class ApiSearchAtomAction extends ApiPrivateAuthAction
{ {
var $cnt; var $cnt;
var $query; var $query;
var $lang; var $lang;
@ -70,7 +68,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @see Action::__construct * @see Action::__construct
*/ */
function __construct($output='php://output', $indent=null) function __construct($output='php://output', $indent=null)
{ {
parent::__construct($output, $indent); parent::__construct($output, $indent);
@ -81,7 +78,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadonly() function isReadonly()
{ {
return true; return true;
@ -93,16 +89,13 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* @param array $args Arguments from $_REQUEST * @param array $args Arguments from $_REQUEST
* *
* @return boolean success * @return boolean success
*
*/ */
function prepare($args) function prepare($args)
{ {
common_debug("in apisearchatom prepare()"); common_debug("in apisearchatom prepare()");
parent::prepare($args); parent::prepare($args);
$this->query = $this->trimmed('q'); $this->query = $this->trimmed('q');
$this->lang = $this->trimmed('lang'); $this->lang = $this->trimmed('lang');
$this->rpp = $this->trimmed('rpp'); $this->rpp = $this->trimmed('rpp');
@ -121,7 +114,7 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
$this->page = 1; $this->page = 1;
} }
// TODO: Suppport since_id -- we need to tweak the backend // TODO: Suppport max_id -- we need to tweak the backend
// Search classes to support it. // Search classes to support it.
$this->since_id = $this->trimmed('since_id'); $this->since_id = $this->trimmed('since_id');
@ -139,7 +132,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -154,7 +146,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @return array an array of Notice objects sorted in reverse chron * @return array an array of Notice objects sorted in reverse chron
*/ */
function getNotices() function getNotices()
{ {
// TODO: Support search operators like from: and to:, boolean, etc. // TODO: Support search operators like from: and to:, boolean, etc.
@ -180,13 +171,16 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
if ($this->cnt > 0) { if ($this->cnt > 0) {
while ($notice->fetch()) { while ($notice->fetch()) {
++$cnt; ++$cnt;
if (!$this->max_id) { if (!$this->max_id) {
$this->max_id = $notice->id; $this->max_id = $notice->id;
} }
if ($this->since_id && $notice->id <= $this->since_id) {
break;
}
if ($cnt > $this->rpp) { if ($cnt > $this->rpp) {
break; break;
} }
@ -203,7 +197,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function showAtom() function showAtom()
{ {
$notices = $this->getNotices(); $notices = $this->getNotices();
@ -212,7 +205,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
$this->showFeed(); $this->showFeed();
foreach ($notices as $n) { foreach ($notices as $n) {
$profile = $n->getProfile(); $profile = $n->getProfile();
// Don't show notices from deleted users // Don't show notices from deleted users
@ -230,7 +222,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function showFeed() function showFeed()
{ {
// TODO: A9 OpenSearch stuff like search.twitter.com? // TODO: A9 OpenSearch stuff like search.twitter.com?
@ -278,6 +269,7 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
'rel' => 'self', 'rel' => 'self',
'href' => $self_uri)); 'href' => $self_uri));
// @todo Needs i18n?
$this->element('title', null, "$this->query - $sitename Search"); $this->element('title', null, "$this->query - $sitename Search");
$this->element('updated', null, common_date_iso8601('now')); $this->element('updated', null, common_date_iso8601('now'));
@ -313,7 +305,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
'rel' => 'previous', 'rel' => 'previous',
'href' => $previous_uri)); 'href' => $previous_uri));
} }
} }
/** /**
@ -324,7 +315,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function showEntry($notice) function showEntry($notice)
{ {
$server = common_config('site', 'server'); $server = common_config('site', 'server');
@ -356,10 +346,10 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
if ($ns) { if ($ns) {
if (!empty($ns->name) && !empty($ns->url)) { if (!empty($ns->name) && !empty($ns->url)) {
$source = '<a href="' $source = '<a href="'
. htmlspecialchars($ns->url) . htmlspecialchars($ns->url)
. '" rel="nofollow">' . '" rel="nofollow">'
. htmlspecialchars($ns->name) . htmlspecialchars($ns->name)
. '</a>'; . '</a>';
} else { } else {
$source = $ns->code; $source = $ns->code;
} }
@ -372,6 +362,7 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
$name = $profile->nickname; $name = $profile->nickname;
if ($profile->fullname) { if ($profile->fullname) {
// @todo Needs proper i18n?
$name .= ' (' . $profile->fullname . ')'; $name .= ' (' . $profile->fullname . ')';
} }
@ -387,7 +378,6 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function initAtom() function initAtom()
{ {
header('Content-Type: application/atom+xml; charset=utf-8'); header('Content-Type: application/atom+xml; charset=utf-8');
@ -399,10 +389,8 @@ class ApiSearchAtomAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function endAtom() function endAtom()
{ {
$this->elementEnd('feed'); $this->elementEnd('feed');
} }
} }

View File

@ -44,7 +44,6 @@ require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
* @link http://status.net/ * @link http://status.net/
* @see ApiAction * @see ApiAction
*/ */
class ApiSearchJSONAction extends ApiPrivateAuthAction class ApiSearchJSONAction extends ApiPrivateAuthAction
{ {
var $query; var $query;
@ -62,7 +61,6 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
* *
* @return boolean true if nothing goes wrong * @return boolean true if nothing goes wrong
*/ */
function prepare($args) function prepare($args)
{ {
common_debug("apisearchjson prepare()"); common_debug("apisearchjson prepare()");
@ -87,6 +85,9 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
$this->page = 1; $this->page = 1;
} }
// TODO: Suppport max_id -- we need to tweak the backend
// Search classes to support it.
$this->since_id = $this->trimmed('since_id'); $this->since_id = $this->trimmed('since_id');
$this->geocode = $this->trimmed('geocode'); $this->geocode = $this->trimmed('geocode');
@ -100,7 +101,6 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -112,10 +112,8 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function showResults() function showResults()
{ {
// TODO: Support search operators like from: and to:, boolean, etc. // TODO: Support search operators like from: and to:, boolean, etc.
$notice = new Notice(); $notice = new Notice();
@ -132,9 +130,9 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
$cnt = $notice->find(); $cnt = $notice->find();
} }
// TODO: since_id, lang, geocode // TODO: max_id, lang, geocode
$results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page); $results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page, $this->since_id);
$this->initDocument('json'); $this->initDocument('json');
$results->show(); $results->show();
@ -146,7 +144,6 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;

View File

@ -55,7 +55,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiStatusesDestroyAction extends ApiAuthAction class ApiStatusesDestroyAction extends ApiAuthAction
{ {
var $status = null; var $status = null;
@ -66,9 +65,7 @@ class ApiStatusesDestroyAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -94,13 +91,13 @@ class ApiStatusesDestroyAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to execute an unknown API method deleting a status.
_('API method not found.'), _('API method not found.'),
404 404
); );
@ -109,6 +106,8 @@ class ApiStatusesDestroyAction extends ApiAuthAction
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to delete a status not using POST or DELETE.
// TRANS: POST and DELETE should not be translated.
_('This method requires a POST or DELETE.'), _('This method requires a POST or DELETE.'),
400, 400,
$this->format $this->format
@ -118,6 +117,7 @@ class ApiStatusesDestroyAction extends ApiAuthAction
if (empty($this->notice)) { if (empty($this->notice)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to delete a status with an invalid ID.
_('No status found with that ID.'), _('No status found with that ID.'),
404, $this->format 404, $this->format
); );
@ -125,13 +125,14 @@ class ApiStatusesDestroyAction extends ApiAuthAction
} }
if ($this->user->id == $this->notice->profile_id) { if ($this->user->id == $this->notice->profile_id) {
$replies = new Reply; if (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) {
$replies->get('notice_id', $this->notice_id); $this->notice->delete();
$replies->delete(); Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
$this->notice->delete(); }
$this->showNotice(); $this->showNotice();
} else { } else {
$this->clientError( $this->clientError(
// TRANS: Client error displayed trying to delete a status of another user.
_('You may not delete another user\'s status.'), _('You may not delete another user\'s status.'),
403, 403,
$this->format $this->format
@ -144,7 +145,6 @@ class ApiStatusesDestroyAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showNotice() function showNotice()
{ {
if (!empty($this->notice)) { if (!empty($this->notice)) {
@ -155,5 +155,4 @@ class ApiStatusesDestroyAction extends ApiAuthAction
} }
} }
} }
} }

View File

@ -43,7 +43,6 @@ require_once INSTALLDIR . '/lib/mediafile.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiStatusesRetweetAction extends ApiAuthAction class ApiStatusesRetweetAction extends ApiAuthAction
{ {
var $original = null; var $original = null;
@ -54,14 +53,13 @@ class ApiStatusesRetweetAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
// TRANS: Client error. POST is a HTTP command. It should not be translated.
$this->clientError(_('This method requires a POST.'), $this->clientError(_('This method requires a POST.'),
400, $this->format); 400, $this->format);
return false; return false;
@ -72,6 +70,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction
$this->original = Notice::staticGet('id', $id); $this->original = Notice::staticGet('id', $id);
if (empty($this->original)) { if (empty($this->original)) {
// TRANS: Client error displayed trying to repeat a non-existing notice through the API.
$this->clientError(_('No such notice.'), $this->clientError(_('No such notice.'),
400, $this->format); 400, $this->format);
return false; return false;
@ -80,6 +79,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction
$this->user = $this->auth_user; $this->user = $this->auth_user;
if ($this->user->id == $this->original->profile_id) { if ($this->user->id == $this->original->profile_id) {
// TRANS: Client error displayed trying to repeat an own notice through the API.
$this->clientError(_('Cannot repeat your own notice.'), $this->clientError(_('Cannot repeat your own notice.'),
400, $this->format); 400, $this->format);
return false; return false;
@ -88,6 +88,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
if ($profile->hasRepeated($id)) { if ($profile->hasRepeated($id)) {
// TRANS: Client error displayed trying to re-repeat a notice through the API.
$this->clientError(_('Already repeated that notice.'), $this->clientError(_('Already repeated that notice.'),
400, $this->format); 400, $this->format);
return false; return false;
@ -105,15 +106,12 @@ class ApiStatusesRetweetAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
$repeat = $this->original->repeat($this->user->id, $this->source); $repeat = $this->original->repeat($this->user->id, $this->source);
$this->showNotice($repeat); $this->showNotice($repeat);
} }
@ -122,7 +120,6 @@ class ApiStatusesRetweetAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showNotice($notice) function showNotice($notice)
{ {
if (!empty($notice)) { if (!empty($notice)) {

View File

@ -43,7 +43,6 @@ require_once INSTALLDIR . '/lib/mediafile.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiStatusesRetweetsAction extends ApiAuthAction class ApiStatusesRetweetsAction extends ApiAuthAction
{ {
const MAXCOUNT = 100; const MAXCOUNT = 100;
@ -57,9 +56,7 @@ class ApiStatusesRetweetsAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -69,6 +66,7 @@ class ApiStatusesRetweetsAction extends ApiAuthAction
$this->original = Notice::staticGet('id', $id); $this->original = Notice::staticGet('id', $id);
if (empty($this->original)) { if (empty($this->original)) {
// TRANS: Client error displayed trying to display redents of a non-exiting notice.
$this->clientError(_('No such notice.'), $this->clientError(_('No such notice.'),
400, $this->format); 400, $this->format);
return false; return false;
@ -94,7 +92,6 @@ class ApiStatusesRetweetsAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -109,6 +106,7 @@ class ApiStatusesRetweetsAction extends ApiAuthAction
$this->showJsonTimeline($strm); $this->showJsonTimeline($strm);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }

View File

@ -55,10 +55,8 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiStatusesShowAction extends ApiPrivateAuthAction class ApiStatusesShowAction extends ApiPrivateAuthAction
{ {
var $notice_id = null; var $notice_id = null;
var $notice = null; var $notice = null;
@ -68,9 +66,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -100,17 +96,27 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json', 'atom'))) {
$this->clientError(_('API method not found.'), $code = 404); // TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), 404);
return; return;
} }
$this->showNotice(); switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
$this->showNotice();
break;
case 'DELETE':
$this->deleteNotice();
break;
default:
$this->clientError(_('HTTP method not supported.'), 405);
return;
}
} }
/** /**
@ -118,17 +124,23 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function showNotice() function showNotice()
{ {
if (!empty($this->notice)) { if (!empty($this->notice)) {
if ($this->format == 'xml') { switch ($this->format) {
case 'xml':
$this->showSingleXmlStatus($this->notice); $this->showSingleXmlStatus($this->notice);
} elseif ($this->format == 'json') { break;
case 'json':
$this->show_single_json_status($this->notice); $this->show_single_json_status($this->notice);
break;
case 'atom':
$this->showSingleAtomStatus($this->notice);
break;
default:
throw new Exception(sprintf(_("Unsupported format: %s"), $this->format));
} }
} else { } else {
// XXX: Twitter just sets a 404 header and doens't bother // XXX: Twitter just sets a 404 header and doens't bother
// to return an err msg // to return an err msg
@ -136,12 +148,14 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
if (!empty($deleted)) { if (!empty($deleted)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed requesting a deleted status.
_('Status deleted.'), _('Status deleted.'),
410, 410,
$this->format $this->format
); );
} else { } else {
$this->clientError( $this->clientError(
// TRANS: Client error displayed requesting a status with an invalid ID.
_('No status with that ID found.'), _('No status with that ID found.'),
404, 404,
$this->format $this->format
@ -151,7 +165,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
} }
/** /**
* Is this action read only? * We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
* *
* @param array $args other arguments * @param array $args other arguments
* *
@ -160,7 +174,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
} }
/** /**
@ -168,7 +182,6 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notice)) { if (!empty($this->notice)) {
@ -186,7 +199,6 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notice)) { if (!empty($this->notice)) {
@ -194,6 +206,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->notice->id, $this->notice->id,
strtotime($this->notice->created)) strtotime($this->notice->created))
@ -204,4 +217,30 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
return null; return null;
} }
function deleteNotice()
{
if ($this->format != 'atom') {
$this->clientError(_("Can only delete using the Atom format."));
return;
}
if (empty($this->auth_user) ||
($this->notice->profile_id != $this->auth_user->id &&
!$this->auth_user->hasRight(Right::DELETEOTHERSNOTICE))) {
$this->clientError(_('Can\'t delete this notice.'), 403);
return;
}
if (Event::handle('StartDeleteOwnNotice', array($this->auth_user, $this->notice))) {
$this->notice->delete();
Event::handle('EndDeleteOwnNotice', array($this->auth_user, $this->notice));
}
// @fixme is there better output we could do here?
header('HTTP/1.1 200 OK');
header('Content-Type: text/plain');
print(sprintf(_('Deleted notice %d'), $this->notice->id));
print("\n");
}
} }

View File

@ -55,7 +55,7 @@
Yes Yes
@param status (Required) The URL-encoded text of the status update. @param status (Required) The URL-encoded text of the status update.
@param source (Optional) The source of the status. @param source (Optional) The source application name, if using HTTP authentication or an anonymous OAuth consumer.
@param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to. @param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to.
@param lat (Optional) The latitude the status refers to. @param lat (Optional) The latitude the status refers to.
@param long (Optional) The longitude the status refers to. @param long (Optional) The longitude the status refers to.
@ -67,7 +67,7 @@
@subsection usagenotes Usage notes @subsection usagenotes Usage notes
@li The URL pattern is relative to the @ref apiroot. @li The URL pattern is relative to the @ref apiroot.
@li If the @e source parameter is not supplied the source of the status will default to 'api'. @li If the @e source parameter is not supplied the source of the status will default to 'api'. When authenticated via a registered OAuth application, the application's registered name and URL will always override the source parameter.
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a> @li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
to encode the latitude and longitude (see example response below <georss:point>). to encode the latitude and longitude (see example response below <georss:point>).
@li Data uploaded via the @e media parameter should be multipart/form-data encoded. @li Data uploaded via the @e media parameter should be multipart/form-data encoded.
@ -147,10 +147,8 @@ require_once INSTALLDIR . '/lib/mediafile.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiStatusesUpdateAction extends ApiAuthAction class ApiStatusesUpdateAction extends ApiAuthAction
{ {
var $source = null;
var $status = null; var $status = null;
var $in_reply_to_status_id = null; var $in_reply_to_status_id = null;
var $lat = null; var $lat = null;
@ -162,9 +160,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -188,13 +184,13 @@ class ApiStatusesUpdateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') { if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError( $this->clientError(
// TRANS: Client error. POST is a HTTP command. It should not be translated.
_('This method requires a POST.'), _('This method requires a POST.'),
400, 400,
$this->format $this->format
@ -209,8 +205,11 @@ class ApiStatusesUpdateAction extends ApiAuthAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
@ -218,6 +217,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
if (empty($this->status)) { if (empty($this->status)) {
$this->clientError( $this->clientError(
// TRANS: Client error displayed when the parameter "status" is missing.
_('Client must provide a \'status\' parameter with a value.'), _('Client must provide a \'status\' parameter with a value.'),
400, 400,
$this->format $this->format
@ -226,20 +226,24 @@ class ApiStatusesUpdateAction extends ApiAuthAction
} }
if (empty($this->auth_user)) { if (empty($this->auth_user)) {
// TRANS: Client error displayed when updating a status for a non-existing user.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
$status_shortened = common_shorten_links($this->status); $status_shortened = $this->auth_user->shortenlinks($this->status);
if (Notice::contentTooLong($status_shortened)) { if (Notice::contentTooLong($status_shortened)) {
// Note: Twitter truncates anything over 140, flags the status // Note: Twitter truncates anything over 140, flags the status
// as "truncated." // as "truncated."
$this->clientError( $this->clientError(
sprintf( sprintf(
_('That\'s too long. Max notice size is %d chars.'), // TRANS: Client error displayed when the parameter "status" is missing.
// TRANS: %d is the maximum number of character for a notice.
_m('That\'s too long. Maximum notice size is %d character.',
'That\'s too long. Maximum notice size is %d characters.',
Notice::maxContent()),
Notice::maxContent() Notice::maxContent()
), ),
406, 406,
@ -255,7 +259,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$cmd = $inter->handle_command($this->auth_user, $status_shortened); $cmd = $inter->handle_command($this->auth_user, $status_shortened);
if ($cmd) { if ($cmd) {
if ($this->supported($cmd)) { if ($this->supported($cmd)) {
$cmd->execute(new Channel()); $cmd->execute(new Channel());
} }
@ -265,13 +268,10 @@ class ApiStatusesUpdateAction extends ApiAuthAction
// or not! // or not!
$this->notice = $this->auth_user->getCurrentNotice(); $this->notice = $this->auth_user->getCurrentNotice();
} else { } else {
$reply_to = null; $reply_to = null;
if (!empty($this->in_reply_to_status_id)) { if (!empty($this->in_reply_to_status_id)) {
// Check whether notice actually exists // Check whether notice actually exists
$reply = Notice::staticGet($this->in_reply_to_status_id); $reply = Notice::staticGet($this->in_reply_to_status_id);
@ -280,7 +280,8 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$reply_to = $this->in_reply_to_status_id; $reply_to = $this->in_reply_to_status_id;
} else { } else {
$this->clientError( $this->clientError(
_('Not found.'), // TRANS: Client error displayed when replying to a non-existing notice.
_('Parent notice not found.'),
$code = 404, $code = 404,
$this->format $this->format
); );
@ -302,10 +303,11 @@ class ApiStatusesUpdateAction extends ApiAuthAction
if (Notice::contentTooLong($status_shortened)) { if (Notice::contentTooLong($status_shortened)) {
$upload->delete(); $upload->delete();
$msg = _( // TRANS: Client error displayed exceeding the maximum notice length.
'Max notice size is %d chars, ' . // TRANS: %d is the maximum lenth for a notice.
'including attachment URL.' $msg = _m('Maximum notice size is %d character, including attachment URL.',
); 'Maximum notice size is %d characters, including attachment URL.',
Notice::maxContent());
$this->clientError( $this->clientError(
sprintf($msg, Notice::maxContent()), sprintf($msg, Notice::maxContent()),
400, 400,
@ -344,7 +346,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
if (isset($upload)) { if (isset($upload)) {
$upload->attachToNotice($this->notice); $upload->attachToNotice($this->notice);
} }
} }
$this->showNotice(); $this->showNotice();
@ -355,7 +356,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function showNotice() function showNotice()
{ {
if (!empty($this->notice)) { if (!empty($this->notice)) {
@ -374,7 +374,6 @@ class ApiStatusesUpdateAction extends ApiAuthAction
* *
* @return boolean true or false * @return boolean true or false
*/ */
function supported($cmd) function supported($cmd)
{ {
static $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand', static $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand',
@ -386,5 +385,4 @@ class ApiStatusesUpdateAction extends ApiAuthAction
return false; return false;
} }
} }

View File

@ -46,7 +46,6 @@ if (!defined('STATUSNET')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiStatusnetConfigAction extends ApiAction class ApiStatusnetConfigAction extends ApiAction
{ {
var $keys = array( var $keys = array(
@ -69,9 +68,7 @@ class ApiStatusnetConfigAction extends ApiAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -85,7 +82,6 @@ class ApiStatusnetConfigAction extends ApiAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -138,6 +134,7 @@ class ApiStatusnetConfigAction extends ApiAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -155,11 +152,8 @@ class ApiStatusnetConfigAction extends ApiAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

View File

@ -47,7 +47,6 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiStatusnetVersionAction extends ApiPrivateAuthAction class ApiStatusnetVersionAction extends ApiPrivateAuthAction
{ {
/** /**
@ -58,7 +57,6 @@ class ApiStatusnetVersionAction extends ApiPrivateAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -72,7 +70,6 @@ class ApiStatusnetVersionAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -90,6 +87,7 @@ class ApiStatusnetVersionAction extends ApiPrivateAuthAction
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -107,11 +105,8 @@ class ApiStatusnetVersionAction extends ApiPrivateAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiSubscriptionsAction extends ApiBareAuthAction class ApiSubscriptionsAction extends ApiBareAuthAction
{ {
var $profiles = null; var $profiles = null;
@ -62,9 +61,7 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -84,6 +81,7 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
$this->user = $this->getTargetUser($this->arg('id')); $this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when requesting a list of followers for a non-existing user.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return false; return false;
} }
@ -102,12 +100,12 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
return; return;
} }
@ -128,7 +126,6 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
* *
* @return array Profiles * @return array Profiles
*/ */
function getProfiles() function getProfiles()
{ {
} }
@ -140,7 +137,6 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -151,7 +147,6 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
* *
* @return string datestamp of the latest profile in the stream * @return string datestamp of the latest profile in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->profiles) && (count($this->profiles) > 0)) { if (!empty($this->profiles) && (count($this->profiles) > 0)) {
@ -171,7 +166,6 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->profiles) && (count($this->profiles) > 0)) { if (!empty($this->profiles) && (count($this->profiles) > 0)) {
@ -181,8 +175,10 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->user->id, $this->user->id,
// Caching tags.
isset($this->ids_only) ? 'IDs' : 'Profiles', isset($this->ids_only) ? 'IDs' : 'Profiles',
strtotime($this->profiles[0]->created), strtotime($this->profiles[0]->created),
strtotime($this->profiles[$last]->created)) strtotime($this->profiles[$last]->created))
@ -201,7 +197,6 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function showProfiles($include_statuses = true) function showProfiles($include_statuses = true)
{ {
switch ($this->format) { switch ($this->format) {
@ -229,6 +224,7 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
print json_encode($arrays); print json_encode($arrays);
break; break;
default: default:
// TRANS: Client error displayed when requesting profiles of followers in an unsupported format.
$this->clientError(_('Unsupported format.')); $this->clientError(_('Unsupported format.'));
break; break;
} }
@ -240,7 +236,6 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function showIds() function showIds()
{ {
switch ($this->format) { switch ($this->format) {
@ -259,9 +254,9 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
print json_encode($ids); print json_encode($ids);
break; break;
default: default:
// TRANS: Client error displayed when requesting IDs of followers in an unsupported format.
$this->clientError(_('Unsupported format.')); $this->clientError(_('Unsupported format.'));
break; break;
} }
} }
} }

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR.'/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineFavoritesAction extends ApiBareAuthAction class ApiTimelineFavoritesAction extends ApiBareAuthAction
{ {
var $notices = null; var $notices = null;
@ -59,9 +58,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -69,6 +66,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
$this->user = $this->getTargetUser($this->arg('id')); $this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when requesting most recent favourite notices by a user for a non-existing user.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -87,7 +85,6 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -99,7 +96,6 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function showTimeline() function showTimeline()
{ {
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
@ -107,6 +103,8 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
$sitename = common_config('site', 'name'); $sitename = common_config('site', 'name');
$title = sprintf( $title = sprintf(
// TRANS: Title for timeline of most recent favourite notices by a user.
// TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
_('%1$s / Favorites from %2$s'), _('%1$s / Favorites from %2$s'),
$sitename, $sitename,
$this->user->nickname $this->user->nickname
@ -116,7 +114,10 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
$id = "tag:$taguribase:Favorites:" . $this->user->id; $id = "tag:$taguribase:Favorites:" . $this->user->id;
$subtitle = sprintf( $subtitle = sprintf(
_('%1$s updates favorited by %2$s / %2$s.'), // TRANS: Subtitle for timeline of most recent favourite notices by a user.
// TRANS: %1$s is the StatusNet sitename, %2$s is a user's full name,
// TRANS: %3$s is a user nickname.
_('%1$s updates favorited by %2$s / %3$s.'),
$sitename, $sitename,
$profile->getBestName(), $profile->getBestName(),
$this->user->nickname $this->user->nickname
@ -148,7 +149,6 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
); );
break; break;
case 'atom': case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8'); header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed($this->auth_user); $atom = new AtomNoticeFeed($this->auth_user);
@ -165,12 +165,12 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
$atom->addEntryFromNotices($this->notices); $atom->addEntryFromNotices($this->notices);
$this->raw($atom->getString()); $this->raw($atom->getString());
break; break;
case 'json': case 'json':
$this->showJsonTimeline($this->notices); $this->showJsonTimeline($this->notices);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -181,7 +181,6 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
* *
* @return array notices * @return array notices
*/ */
function getNotices() function getNotices()
{ {
$notices = array(); $notices = array();
@ -220,7 +219,6 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -231,7 +229,6 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -249,7 +246,6 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -259,6 +255,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->user->id, $this->user->id,
strtotime($this->notices[0]->created), strtotime($this->notices[0]->created),
@ -269,5 +266,4 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
return null; return null;
} }
} }

View File

@ -151,7 +151,6 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineFriendsAction extends ApiBareAuthAction class ApiTimelineFriendsAction extends ApiBareAuthAction
{ {
var $notices = null; var $notices = null;
@ -164,13 +163,13 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
$this->user = $this->getTargetUser($this->arg('id')); $this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -189,7 +188,6 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -201,7 +199,6 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function showTimeline() function showTimeline()
{ {
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
@ -246,7 +243,6 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
); );
break; break;
case 'atom': case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8'); header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed($this->auth_user); $atom = new AtomNoticeFeed($this->auth_user);
@ -268,6 +264,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
$this->showJsonTimeline($this->notices); $this->showJsonTimeline($this->notices);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -278,7 +275,6 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
* *
* @return array notices * @return array notices
*/ */
function getNotices() function getNotices()
{ {
$notices = array(); $notices = array();
@ -307,7 +303,6 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -318,7 +313,6 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -336,16 +330,15 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1; $last = count($this->notices) - 1;
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->user->id, $this->user->id,
strtotime($this->notices[0]->created), strtotime($this->notices[0]->created),
@ -356,5 +349,4 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
return null; return null;
} }
} }

View File

@ -49,10 +49,8 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineGroupAction extends ApiPrivateAuthAction class ApiTimelineGroupAction extends ApiPrivateAuthAction
{ {
var $group = null; var $group = null;
var $notices = null; var $notices = null;
@ -64,7 +62,6 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -83,12 +80,12 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (empty($this->group)) { if (empty($this->group)) {
// TRANS: Client error displayed requesting most recent notices to a group for a non-existing group.
$this->clientError(_('Group not found.'), 404, $this->format); $this->clientError(_('Group not found.'), 404, $this->format);
return false; return false;
} }
@ -102,7 +99,6 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function showTimeline() function showTimeline()
{ {
// We'll pull common formatting out of this for other formats // We'll pull common formatting out of this for other formats
@ -126,7 +122,6 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
); );
break; break;
case 'atom': case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8'); header('Content-Type: application/atom+xml; charset=utf-8');
try { try {
@ -138,19 +133,21 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
$this->raw($atom->getString()); $this->raw($atom->getString());
} catch (Atom10FeedException $e) { } catch (Atom10FeedException $e) {
$this->serverError( $this->serverError(
'Could not generate feed for group - ' . $e->getMessage(), // TRANS: Server error displayed when generating an Atom feed fails.
// TRANS: %s is the error.
sprintf(_('Could not generate feed for group - %s'),$e->getMessage()),
400, 400,
$this->format $this->format
); );
return; return;
} }
break; break;
case 'json': case 'json':
$this->showJsonTimeline($this->notices); $this->showJsonTimeline($this->notices);
break; break;
default: default:
$this->clientError( $this->clientError(
// TRANS: Client error displayed when trying to handle an unknown API method.
_('API method not found.'), _('API method not found.'),
404, 404,
$this->format $this->format
@ -164,7 +161,6 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
* *
* @return array notices * @return array notices
*/ */
function getNotices() function getNotices()
{ {
$notices = array(); $notices = array();
@ -190,7 +186,6 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -201,7 +196,6 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -219,7 +213,6 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -229,6 +222,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->group->id, $this->group->id,
strtotime($this->notices[0]->created), strtotime($this->notices[0]->created),
@ -239,5 +233,4 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
return null; return null;
} }
} }

View File

@ -56,7 +56,6 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineHomeAction extends ApiBareAuthAction class ApiTimelineHomeAction extends ApiBareAuthAction
{ {
var $notices = null; var $notices = null;
@ -67,9 +66,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -77,6 +74,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
$this->user = $this->getTargetUser($this->arg('id')); $this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when requesting most recent dents by user and friends for a non-existing user.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -95,7 +93,6 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -107,12 +104,12 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function showTimeline() function showTimeline()
{ {
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE); $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
$sitename = common_config('site', 'name'); $sitename = common_config('site', 'name');
// TRANS: Timeline title for user and friends. %s is a user nickname.
$title = sprintf(_("%s and friends"), $this->user->nickname); $title = sprintf(_("%s and friends"), $this->user->nickname);
$taguribase = TagURI::base(); $taguribase = TagURI::base();
$id = "tag:$taguribase:HomeTimeline:" . $this->user->id; $id = "tag:$taguribase:HomeTimeline:" . $this->user->id;
@ -172,6 +169,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
$this->showJsonTimeline($this->notices); $this->showJsonTimeline($this->notices);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -182,7 +180,6 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
* *
* @return array notices * @return array notices
*/ */
function getNotices() function getNotices()
{ {
$notices = array(); $notices = array();
@ -215,7 +212,6 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -226,7 +222,6 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -244,7 +239,6 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -254,6 +248,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->user->id, $this->user->id,
strtotime($this->notices[0]->created), strtotime($this->notices[0]->created),
@ -264,5 +259,4 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
return null; return null;
} }
} }

View File

@ -55,10 +55,8 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineMentionsAction extends ApiBareAuthAction class ApiTimelineMentionsAction extends ApiBareAuthAction
{ {
var $notices = null; var $notices = null;
/** /**
@ -67,9 +65,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -77,6 +73,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
$this->user = $this->getTargetUser($this->arg('id')); $this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed when requesting most recent mentions for a non-existing user.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -95,7 +92,6 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -107,7 +103,6 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function showTimeline() function showTimeline()
{ {
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
@ -115,6 +110,8 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
$sitename = common_config('site', 'name'); $sitename = common_config('site', 'name');
$title = sprintf( $title = sprintf(
// TRANS: Title for timeline of most recent mentions of a user.
// TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
_('%1$s / Updates mentioning %2$s'), _('%1$s / Updates mentioning %2$s'),
$sitename, $this->user->nickname $sitename, $this->user->nickname
); );
@ -128,6 +125,9 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
$self = $this->getSelfUri(); $self = $this->getSelfUri();
$subtitle = sprintf( $subtitle = sprintf(
// TRANS: Subtitle for timeline of most recent mentions of a user.
// TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname,
// TRANS: %3$s is a user's full name.
_('%1$s updates that reply to updates from %2$s / %3$s.'), _('%1$s updates that reply to updates from %2$s / %3$s.'),
$sitename, $this->user->nickname, $profile->getBestName() $sitename, $this->user->nickname, $profile->getBestName()
); );
@ -149,7 +149,6 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
); );
break; break;
case 'atom': case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8'); header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed($this->auth_user); $atom = new AtomNoticeFeed($this->auth_user);
@ -171,6 +170,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
$this->showJsonTimeline($this->notices); $this->showJsonTimeline($this->notices);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -181,7 +181,6 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
* *
* @return array notices * @return array notices
*/ */
function getNotices() function getNotices()
{ {
$notices = array(); $notices = array();
@ -205,7 +204,6 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -216,7 +214,6 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -234,7 +231,6 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -244,6 +240,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->user->id, $this->user->id,
strtotime($this->notices[0]->created), strtotime($this->notices[0]->created),
@ -254,5 +251,4 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
return null; return null;
} }
} }

View File

@ -144,10 +144,8 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
</statuses> </statuses>
@endverbatim @endverbatim
*/ */
class ApiTimelinePublicAction extends ApiPrivateAuthAction class ApiTimelinePublicAction extends ApiPrivateAuthAction
{ {
var $notices = null; var $notices = null;
/** /**
@ -158,7 +156,6 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -177,7 +174,6 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -189,16 +185,17 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function showTimeline() function showTimeline()
{ {
$sitename = common_config('site', 'name'); $sitename = common_config('site', 'name');
$sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'); $sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
// TRANS: Title for site timeline. %s is the StatusNet sitename.
$title = sprintf(_("%s public timeline"), $sitename); $title = sprintf(_("%s public timeline"), $sitename);
$taguribase = TagURI::base(); $taguribase = TagURI::base();
$id = "tag:$taguribase:PublicTimeline"; $id = "tag:$taguribase:PublicTimeline";
$link = common_local_url('public'); $link = common_local_url('public');
$self = $this->getSelfUri(); $self = $this->getSelfUri();
// TRANS: Subtitle for site timeline. %s is the StatusNet sitename.
$subtitle = sprintf(_("%s updates from everyone!"), $sitename); $subtitle = sprintf(_("%s updates from everyone!"), $sitename);
switch($this->format) { switch($this->format) {
@ -238,6 +235,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
$this->showJsonTimeline($this->notices); $this->showJsonTimeline($this->notices);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -248,7 +246,6 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
* *
* @return array notices * @return array notices
*/ */
function getNotices() function getNotices()
{ {
$notices = array(); $notices = array();
@ -272,7 +269,6 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -283,7 +279,6 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -301,7 +296,6 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -311,6 +305,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
strtotime($this->notices[0]->created), strtotime($this->notices[0]->created),
strtotime($this->notices[$last]->created)) strtotime($this->notices[$last]->created))
@ -320,5 +315,4 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
return null; return null;
} }
} }

View File

@ -43,7 +43,6 @@ require_once INSTALLDIR . '/lib/mediafile.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineRetweetedByMeAction extends ApiAuthAction class ApiTimelineRetweetedByMeAction extends ApiAuthAction
{ {
const DEFAULTCOUNT = 20; const DEFAULTCOUNT = 20;
@ -64,12 +63,12 @@ class ApiTimelineRetweetedByMeAction extends ApiAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
$this->serverError('Unimplemented.', 503); // TRANS: Server error displayed calling unimplemented API method for 'retweeted by me'.
$this->serverError(_('Unimplemented.'), 503);
return false; return false;
} }
@ -81,7 +80,6 @@ class ApiTimelineRetweetedByMeAction extends ApiAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;

View File

@ -42,7 +42,6 @@ require_once INSTALLDIR . '/lib/apiauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineRetweetedToMeAction extends ApiAuthAction class ApiTimelineRetweetedToMeAction extends ApiAuthAction
{ {
const DEFAULTCOUNT = 20; const DEFAULTCOUNT = 20;
@ -61,9 +60,7 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -88,7 +85,6 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -108,6 +104,7 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
case 'atom': case 'atom':
$profile = $this->auth_user->getProfile(); $profile = $this->auth_user->getProfile();
// TRANS: Title for Atom feed "repeated to me". %s is the user nickname.
$title = sprintf(_("Repeated to %s"), $this->auth_user->nickname); $title = sprintf(_("Repeated to %s"), $this->auth_user->nickname);
$taguribase = TagURI::base(); $taguribase = TagURI::base();
$id = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id; $id = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id;
@ -116,8 +113,8 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
$this->showAtomTimeline($strm, $title, $id, $link); $this->showAtomTimeline($strm, $title, $id, $link);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -132,7 +129,6 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;

View File

@ -43,7 +43,6 @@ require_once INSTALLDIR . '/lib/mediafile.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineRetweetsOfMeAction extends ApiAuthAction class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
{ {
const DEFAULTCOUNT = 20; const DEFAULTCOUNT = 20;
@ -62,9 +61,7 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -89,7 +86,6 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -111,6 +107,8 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
case 'atom': case 'atom':
$profile = $this->auth_user->getProfile(); $profile = $this->auth_user->getProfile();
// TRANS: Title of list of repeated notices of the logged in user.
// TRANS: %s is the nickname of the logged in user.
$title = sprintf(_("Repeats of %s"), $this->auth_user->nickname); $title = sprintf(_("Repeats of %s"), $this->auth_user->nickname);
$taguribase = TagURI::base(); $taguribase = TagURI::base();
$id = "tag:$taguribase:RepeatsOfMe:" . $this->auth_user->id; $id = "tag:$taguribase:RepeatsOfMe:" . $this->auth_user->id;
@ -147,8 +145,8 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
$this->raw($atom->getString()); $this->raw($atom->getString());
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -163,7 +161,6 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;

View File

@ -49,10 +49,8 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineTagAction extends ApiPrivateAuthAction class ApiTimelineTagAction extends ApiPrivateAuthAction
{ {
var $notices = null; var $notices = null;
/** /**
@ -61,9 +59,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -85,7 +81,6 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -97,13 +92,16 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function showTimeline() function showTimeline()
{ {
$sitename = common_config('site', 'name'); $sitename = common_config('site', 'name');
$sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png'); $sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
// TRANS: Title for timeline with lastest notices with a given tag.
// TRANS: %s is the tag.
$title = sprintf(_("Notices tagged with %s"), $this->tag); $title = sprintf(_("Notices tagged with %s"), $this->tag);
$subtitle = sprintf( $subtitle = sprintf(
// TRANS: Subtitle for timeline with lastest notices with a given tag.
// TRANS: %1$s is the tag, $2$s is the StatusNet sitename.
_('Updates tagged with %1$s on %2$s!'), _('Updates tagged with %1$s on %2$s!'),
$this->tag, $this->tag,
$sitename $sitename
@ -136,7 +134,6 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
); );
break; break;
case 'atom': case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8'); header('Content-Type: application/atom+xml; charset=utf-8');
$atom = new AtomNoticeFeed($this->auth_user); $atom = new AtomNoticeFeed($this->auth_user);
@ -158,6 +155,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
$this->showJsonTimeline($this->notices); $this->showJsonTimeline($this->notices);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
@ -168,7 +166,6 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
* *
* @return array notices * @return array notices
*/ */
function getNotices() function getNotices()
{ {
$notices = array(); $notices = array();
@ -193,7 +190,6 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -204,7 +200,6 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -222,7 +217,6 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -232,6 +226,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_user_cache_hash($this->auth_user),
common_language(), common_language(),
$this->tag, $this->tag,
strtotime($this->notices[0]->created), strtotime($this->notices[0]->created),
@ -242,5 +237,4 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
return null; return null;
} }
} }

View File

@ -57,10 +57,8 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiTimelineUserAction extends ApiBareAuthAction class ApiTimelineUserAction extends ApiBareAuthAction
{ {
var $notices = null; var $notices = null;
/** /**
@ -69,9 +67,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
* @param array $args $_REQUEST args * @param array $args $_REQUEST args
* *
* @return boolean success flag * @return boolean success flag
*
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -79,6 +75,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
$this->user = $this->getTargetUser($this->arg('id')); $this->user = $this->getTargetUser($this->arg('id'));
if (empty($this->user)) { if (empty($this->user)) {
// TRANS: Client error displayed requesting most recent notices for a non-existing user.
$this->clientError(_('No such user.'), 404, $this->format); $this->clientError(_('No such user.'), 404, $this->format);
return; return;
} }
@ -97,11 +94,15 @@ class ApiTimelineUserAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
$this->showTimeline();
if ($this->isPost()) {
$this->handlePost();
} else {
$this->showTimeline();
}
} }
/** /**
@ -109,7 +110,6 @@ class ApiTimelineUserAction extends ApiBareAuthAction
* *
* @return void * @return void
*/ */
function showTimeline() function showTimeline()
{ {
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
@ -119,9 +119,9 @@ class ApiTimelineUserAction extends ApiBareAuthAction
$atom = new AtomUserNoticeFeed($this->user, $this->auth_user); $atom = new AtomUserNoticeFeed($this->user, $this->auth_user);
$link = common_local_url( $link = common_local_url(
'showstream', 'showstream',
array('nickname' => $this->user->nickname) array('nickname' => $this->user->nickname)
); );
$self = $this->getSelfUri(); $self = $this->getSelfUri();
@ -137,21 +137,63 @@ class ApiTimelineUserAction extends ApiBareAuthAction
break; break;
case 'rss': case 'rss':
$this->showRssTimeline( $this->showRssTimeline(
$this->notices, $this->notices,
$atom->title, $atom->title,
$link, $link,
$atom->subtitle, $atom->subtitle,
$suplink, $suplink,
$atom->logo, $atom->logo,
$self $self
); );
break; break;
case 'atom': case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8'); header('Content-Type: application/atom+xml; charset=utf-8');
$atom->setId($self); $atom->setId($self);
$atom->setSelfLink($self); $atom->setSelfLink($self);
// Add navigation links: next, prev, first
// Note: we use IDs rather than pages for navigation; page boundaries
// change too quickly!
if (!empty($this->next_id)) {
$nextUrl = common_local_url('ApiTimelineUser',
array('format' => 'atom',
'id' => $this->user->id),
array('max_id' => $this->next_id));
$atom->addLink($nextUrl,
array('rel' => 'next',
'type' => 'application/atom+xml'));
}
if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
$lastNotice = $this->notices[0];
$lastId = $lastNotice->id;
$prevUrl = common_local_url('ApiTimelineUser',
array('format' => 'atom',
'id' => $this->user->id),
array('since_id' => $lastId));
$atom->addLink($prevUrl,
array('rel' => 'prev',
'type' => 'application/atom+xml'));
}
if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
$firstUrl = common_local_url('ApiTimelineUser',
array('format' => 'atom',
'id' => $this->user->id));
$atom->addLink($firstUrl,
array('rel' => 'first',
'type' => 'application/atom+xml'));
}
$atom->addEntryFromNotices($this->notices); $atom->addEntryFromNotices($this->notices);
$this->raw($atom->getString()); $this->raw($atom->getString());
@ -160,10 +202,10 @@ class ApiTimelineUserAction extends ApiBareAuthAction
$this->showJsonTimeline($this->notices); $this->showJsonTimeline($this->notices);
break; break;
default: default:
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
break; break;
} }
} }
/** /**
@ -171,25 +213,29 @@ class ApiTimelineUserAction extends ApiBareAuthAction
* *
* @return array notices * @return array notices
*/ */
function getNotices() function getNotices()
{ {
$notices = array(); $notices = array();
$notice = $this->user->getNotices( $notice = $this->user->getNotices(($this->page-1) * $this->count,
($this->page-1) * $this->count, $this->count, $this->count + 1,
$this->since_id, $this->max_id $this->since_id,
); $this->max_id);
while ($notice->fetch()) { while ($notice->fetch()) {
$notices[] = clone($notice); if (count($notices) < $this->count) {
$notices[] = clone($notice);
} else {
$this->next_id = $notice->id;
break;
}
} }
return $notices; return $notices;
} }
/** /**
* Is this action read only? * We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
* *
* @param array $args other arguments * @param array $args other arguments
* *
@ -198,7 +244,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
} }
/** /**
@ -206,7 +252,6 @@ class ApiTimelineUserAction extends ApiBareAuthAction
* *
* @return string datestamp of the latest notice in the stream * @return string datestamp of the latest notice in the stream
*/ */
function lastModified() function lastModified()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
@ -224,25 +269,228 @@ class ApiTimelineUserAction extends ApiBareAuthAction
* *
* @return string etag * @return string etag
*/ */
function etag() function etag()
{ {
if (!empty($this->notices) && (count($this->notices) > 0)) { if (!empty($this->notices) && (count($this->notices) > 0)) {
$last = count($this->notices) - 1; $last = count($this->notices) - 1;
return '"' . implode( return '"' . implode(
':', ':',
array($this->arg('action'), array($this->arg('action'),
common_language(), common_user_cache_hash($this->auth_user),
$this->user->id, common_language(),
strtotime($this->notices[0]->created), $this->user->id,
strtotime($this->notices[$last]->created)) strtotime($this->notices[0]->created),
) strtotime($this->notices[$last]->created))
. '"'; )
. '"';
} }
return null; return null;
} }
function handlePost()
{
if (empty($this->auth_user) ||
$this->auth_user->id != $this->user->id) {
// TRANS: Client error displayed trying to add a notice to another user's timeline.
$this->clientError(_('Only the user can add to their own timeline.'));
return;
}
// Only handle posts for Atom
if ($this->format != 'atom') {
// TRANS: Client error displayed when using another format than AtomPub.
$this->clientError(_('Only accept AtomPub for Atom feeds.'));
return;
}
$xml = trim(file_get_contents('php://input'));
if (empty($xml)) {
$this->clientError(_('Atom post must not be empty.'));
}
$dom = DOMDocument::loadXML($xml);
if (!$dom) {
$this->clientError(_('Atom post must be well-formed XML.'));
}
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
$dom->documentElement->localName != 'entry') {
// TRANS: Client error displayed when not using an Atom entry.
$this->clientError(_('Atom post must be an Atom entry.'));
return;
}
$activity = new Activity($dom->documentElement);
if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
if ($activity->verb != ActivityVerb::POST) {
// TRANS: Client error displayed when not using the POST verb.
// TRANS: Do not translate POST.
$this->clientError(_('Can only handle POST activities.'));
return;
}
$note = $activity->objects[0];
if (!in_array($note->type, array(ActivityObject::NOTE,
ActivityObject::BLOGENTRY,
ActivityObject::STATUS))) {
// TRANS: Client error displayed when using an unsupported activity object type.
// TRANS: %s is the unsupported activity object type.
$this->clientError(sprintf(_('Cannot handle activity object type "%s".'),
$note->type));
return;
}
$saved = $this->postNote($activity);
Event::handle('EndAtomPubNewActivity', array($activity, $saved));
}
if (!empty($saved)) {
header('HTTP/1.1 201 Created');
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $saved->id,
'format' => 'atom')));
$this->showSingleAtomStatus($saved);
}
}
function postNote($activity)
{
$note = $activity->objects[0];
// Use summary as fallback for content
if (!empty($note->content)) {
$sourceContent = $note->content;
} else if (!empty($note->summary)) {
$sourceContent = $note->summary;
} else if (!empty($note->title)) {
$sourceContent = $note->title;
} else {
// @fixme fetch from $sourceUrl?
// TRANS: Client error displayed when posting a notice without content through the API.
$this->clientError(sprintf(_('No content for notice %d.'),
$note->id));
return;
}
// Get (safe!) HTML and text versions of the content
$rendered = $this->purify($sourceContent);
$content = html_entity_decode(strip_tags($rendered), ENT_QUOTES, 'UTF-8');
$shortened = $this->auth_user->shortenLinks($content);
$options = array('is_local' => Notice::LOCAL_PUBLIC,
'rendered' => $rendered,
'replies' => array(),
'groups' => array(),
'tags' => array(),
'urls' => array());
// accept remote URI (not necessarily a good idea)
common_debug("Note ID is {$note->id}");
if (!empty($note->id)) {
$notice = Notice::staticGet('uri', trim($note->id));
if (!empty($notice)) {
// TRANS: Client error displayed when using another format than AtomPub.
$this->clientError(sprintf(_('Notice with URI "%s" already exists.'),
$note->id));
return;
}
common_log(LOG_NOTICE, "Saving client-supplied notice URI '$note->id'");
$options['uri'] = $note->id;
}
// accept remote create time (also maybe not such a good idea)
if (!empty($activity->time)) {
common_log(LOG_NOTICE, "Saving client-supplied create time {$activity->time}");
$options['created'] = common_sql_date($activity->time);
}
// Check for optional attributes...
if (!empty($activity->context)) {
foreach ($activity->context->attention as $uri) {
$profile = Profile::fromURI($uri);
if (!empty($profile)) {
$options['replies'] = $uri;
} else {
$group = User_group::staticGet('uri', $uri);
if (!empty($group)) {
$options['groups'] = $uri;
} else {
// @fixme: hook for discovery here
common_log(LOG_WARNING, sprintf(_('AtomPub post with unknown attention URI %s'), $uri));
}
}
}
// Maintain direct reply associations
// @fixme what about conversation ID?
if (!empty($activity->context->replyToID)) {
$orig = Notice::staticGet('uri',
$activity->context->replyToID);
if (!empty($orig)) {
$options['reply_to'] = $orig->id;
}
}
$location = $activity->context->location;
if ($location) {
$options['lat'] = $location->lat;
$options['lon'] = $location->lon;
if ($location->location_id) {
$options['location_ns'] = $location->location_ns;
$options['location_id'] = $location->location_id;
}
}
}
// Atom categories <-> hashtags
foreach ($activity->categories as $cat) {
if ($cat->term) {
$term = common_canonical_tag($cat->term);
if ($term) {
$options['tags'][] = $term;
}
}
}
// Atom enclosures -> attachment URLs
foreach ($activity->enclosures as $href) {
// @fixme save these locally or....?
$options['urls'][] = $href;
}
$saved = Notice::saveNew($this->user->id,
$content,
'atompub', // TODO: deal with this
$options);
return $saved;
}
function purify($content)
{
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
$config = array('safe' => 1,
'deny_attribute' => 'id,style,on*');
return htmLawed($content, $config);
}
} }

View File

@ -44,10 +44,8 @@ require_once INSTALLDIR.'/lib/apiprivateauth.php';
* *
* @see ApiAction * @see ApiAction
*/ */
class ApiTrendsAction extends ApiPrivateAuthAction class ApiTrendsAction extends ApiPrivateAuthAction
{ {
var $callback; var $callback;
/** /**
@ -70,7 +68,6 @@ class ApiTrendsAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -84,7 +81,7 @@ class ApiTrendsAction extends ApiPrivateAuthAction
*/ */
function showTrends() function showTrends()
{ {
// TRANS: Server error for unfinished API method showTrends.
$this->serverError(_('API method under construction.'), 501); $this->serverError(_('API method under construction.'), 501);
} }
} }

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiUserFollowersAction extends ApiSubscriptionsAction class ApiUserFollowersAction extends ApiSubscriptionsAction
{ {
/** /**
@ -56,7 +55,6 @@ class ApiUserFollowersAction extends ApiSubscriptionsAction
* *
* @return array Profiles * @return array Profiles
*/ */
function getProfiles() function getProfiles()
{ {
$offset = ($this->page - 1) * $this->count; $offset = ($this->page - 1) * $this->count;
@ -85,5 +83,4 @@ class ApiUserFollowersAction extends ApiSubscriptionsAction
return $profiles; return $profiles;
} }
} }

View File

@ -48,7 +48,6 @@ require_once INSTALLDIR . '/lib/apibareauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiUserFriendsAction extends ApiSubscriptionsAction class ApiUserFriendsAction extends ApiSubscriptionsAction
{ {
/** /**
@ -56,7 +55,6 @@ class ApiUserFriendsAction extends ApiSubscriptionsAction
* *
* @return array Profiles * @return array Profiles
*/ */
function getProfiles() function getProfiles()
{ {
$offset = ($this->page - 1) * $this->count; $offset = ($this->page - 1) * $this->count;
@ -85,5 +83,4 @@ class ApiUserFriendsAction extends ApiSubscriptionsAction
return $profiles; return $profiles;
} }
} }

View File

@ -0,0 +1,135 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Return a user's avatar 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 Brion Vibber <brion@status.net>
* @copyright 2010 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 avatar URL for a user, specified by screen name.
* Unlike most API endpoints, this returns an HTTP redirect rather than direct data.
*
* @category API
* @package StatusNet
* @author Brion Vibber <brion@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 ApiUserProfileImageAction extends ApiPrivateAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = User::staticGet('nickname', $this->arg('screen_name'));
$this->size = $this->arg('size');
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)) {
// TRANS: Client error displayed when requesting user information for a non-existing user.
$this->clientError(_('User not found.'), 404, $this->format);
return;
}
$profile = $this->user->getProfile();
if (empty($profile)) {
// TRANS: Client error displayed when requesting user information for a user without a profile.
$this->clientError(_('User has no profile.'));
return;
}
$size = $this->avatarSize();
$avatar = $profile->getAvatar($size);
if ($avatar) {
$url = $avatar->displayUrl();
} else {
$url = Avatar::defaultImage($size);
}
// We don't actually output JSON or XML data -- redirect!
common_redirect($url, 302);
}
/**
* Get the appropriate pixel size for an avatar based on the request...
*
* @return int
*/
private function avatarSize()
{
switch ($this->size) {
case 'mini':
return AVATAR_MINI_SIZE; // 24x24
case 'bigger':
return AVATAR_PROFILE_SIZE; // Twitter does 73x73, but we do 96x96
case 'normal': // fall through
default:
return AVATAR_STREAM_SIZE; // 48x48
}
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return true;
}
}

View File

@ -49,7 +49,6 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ApiUserShowAction extends ApiPrivateAuthAction class ApiUserShowAction extends ApiPrivateAuthAction
{ {
/** /**
@ -60,7 +59,6 @@ class ApiUserShowAction extends ApiPrivateAuthAction
* @return boolean success flag * @return boolean success flag
* *
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -87,17 +85,18 @@ class ApiUserShowAction extends ApiPrivateAuthAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (empty($this->user)) { if (empty($this->user)) {
$this->clientError(_('Not found.'), 404, $this->format); // TRANS: Client error displayed when requesting user information for a non-existing user.
$this->clientError(_('User not found.'), 404, $this->format);
return; return;
} }
if (!in_array($this->format, array('xml', 'json'))) { if (!in_array($this->format, array('xml', 'json'))) {
// TRANS: Client error displayed when trying to handle an unknown API method.
$this->clientError(_('API method not found.'), $code = 404); $this->clientError(_('API method not found.'), $code = 404);
return; return;
} }
@ -105,6 +104,7 @@ class ApiUserShowAction extends ApiPrivateAuthAction
$profile = $this->user->getProfile(); $profile = $this->user->getProfile();
if (empty($profile)) { if (empty($profile)) {
// TRANS: Client error displayed when requesting user information for a user without a profile.
$this->clientError(_('User has no profile.')); $this->clientError(_('User has no profile.'));
return; return;
} }
@ -120,7 +120,6 @@ class ApiUserShowAction extends ApiPrivateAuthAction
$this->showJsonObjects($twitter_user); $this->showJsonObjects($twitter_user);
$this->endDocument('json'); $this->endDocument('json');
} }
} }
/** /**
@ -132,10 +131,8 @@ class ApiUserShowAction extends ApiPrivateAuthAction
* *
* @return boolean is read only action? * @return boolean is read only action?
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
} }
} }

View File

@ -0,0 +1,374 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* Feed of ActivityStreams 'favorite' actions
*
* PHP version 5
*
* 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 AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
// This check helps protect against security problems;
// your code file can't be executed directly from the web.
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Feed of ActivityStreams 'favorite' actions
*
* @category AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
class AtompubfavoritefeedAction extends ApiAuthAction
{
private $_profile = null;
private $_faves = null;
/**
* For initializing members of the class.
*
* @param array $argarray misc. arguments
*
* @return boolean true
*/
function prepare($argarray)
{
parent::prepare($argarray);
$this->_profile = Profile::staticGet('id', $this->trimmed('profile'));
if (empty($this->_profile)) {
throw new ClientException(_('No such profile'), 404);
}
$offset = ($this->page-1) * $this->count;
$limit = $this->count + 1;
$this->_faves = Fave::byProfile($this->_profile->id,
$offset,
$limit);
return true;
}
/**
* Handler method
*
* @param array $argarray is ignored since it's now passed in in prepare()
*
* @return void
*/
function handle($argarray=null)
{
parent::handle($argarray);
switch ($_SERVER['REQUEST_METHOD']) {
case 'HEAD':
case 'GET':
$this->showFeed();
break;
case 'POST':
$this->addFavorite();
break;
default:
throw new ClientException(_('HTTP method not supported.'), 405);
return;
}
return;
}
/**
* Show a feed of favorite activity streams objects
*
* @return void
*/
function showFeed()
{
header('Content-Type: application/atom+xml; charset=utf-8');
$url = common_local_url('AtomPubFavoriteFeed',
array('profile' => $this->_profile->id));
$feed = new Atom10Feed(true);
$feed->addNamespace('activity',
'http://activitystrea.ms/spec/1.0/');
$feed->addNamespace('poco',
'http://portablecontacts.net/spec/1.0');
$feed->addNamespace('media',
'http://purl.org/syndication/atommedia');
$feed->id = $url;
$feed->setUpdated('now');
$feed->addAuthor($this->_profile->getBestName(),
$this->_profile->getURI());
$feed->setTitle(sprintf(_("%s favorites"),
$this->_profile->getBestName()));
$feed->setSubtitle(sprintf(_("Notices %s has favorited to on %s"),
$this->_profile->getBestName(),
common_config('site', 'name')));
$feed->addLink(common_local_url('showfavorites',
array('nickname' =>
$this->_profile->nickname)));
$feed->addLink($url,
array('rel' => 'self',
'type' => 'application/atom+xml'));
// If there's more...
if ($this->page > 1) {
$feed->addLink($url,
array('rel' => 'first',
'type' => 'application/atom+xml'));
$feed->addLink(common_local_url('AtomPubFavoriteFeed',
array('profile' =>
$this->_profile->id),
array('page' =>
$this->page - 1)),
array('rel' => 'prev',
'type' => 'application/atom+xml'));
}
if ($this->_faves->N > $this->count) {
$feed->addLink(common_local_url('AtomPubFavoriteFeed',
array('profile' =>
$this->_profile->id),
array('page' =>
$this->page + 1)),
array('rel' => 'next',
'type' => 'application/atom+xml'));
}
$i = 0;
while ($this->_faves->fetch()) {
// We get one more than needed; skip that one
$i++;
if ($i > $this->count) {
break;
}
$act = $this->_faves->asActivity();
$feed->addEntryRaw($act->asString(false, false, false));
}
$this->raw($feed->getString());
}
/**
* add a new favorite
*
* @return void
*/
function addFavorite()
{
// XXX: Refactor this; all the same for atompub
if (empty($this->auth_user) ||
$this->auth_user->id != $this->_profile->id) {
throw new ClientException(_("Can't add someone else's".
" subscription"), 403);
}
$xml = file_get_contents('php://input');
$dom = DOMDocument::loadXML($xml);
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
$dom->documentElement->localName != 'entry') {
// TRANS: Client error displayed when not using an Atom entry.
throw new ClientException(_('Atom post must be an Atom entry.'));
return;
}
$activity = new Activity($dom->documentElement);
$fave = null;
if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
if ($activity->verb != ActivityVerb::FAVORITE) {
// TRANS: Client error displayed when not using the POST verb.
// TRANS: Do not translate POST.
throw new ClientException(_('Can only handle Favorite activities.'));
return;
}
$note = $activity->objects[0];
if (!in_array($note->type, array(ActivityObject::NOTE,
ActivityObject::BLOGENTRY,
ActivityObject::STATUS))) {
throw new ClientException(_('Can only fave notices.'));
return;
}
$notice = Notice::staticGet('uri', $note->id);
if (empty($notice)) {
// XXX: import from listed URL or something
throw new ClientException(_('Unknown note.'));
}
$old = Fave::pkeyGet(array('user_id' => $this->auth_user->id,
'notice_id' => $notice->id));
if (!empty($old)) {
throw new ClientException(_('Already a favorite.'));
}
$profile = $this->auth_user->getProfile();
$fave = Fave::addNew($profile, $notice);
if (!empty($fave)) {
$this->_profile->blowFavesCache();
$this->notify($fave, $notice, $this->auth_user);
}
Event::handle('EndAtomPubNewActivity', array($activity, $fave));
}
if (!empty($fave)) {
$act = $fave->asActivity();
header('Content-Type: application/atom+xml; charset=utf-8');
header('Content-Location: ' . $act->selfLink);
$this->startXML();
$this->raw($act->asString(true, true, true));
$this->endXML();
}
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
return true;
} else {
return false;
}
}
/**
* Return last modified, if applicable.
*
* MAY override
*
* @return string last modified http header
*/
function lastModified()
{
// For comparison with If-Last-Modified
// If not applicable, return null
return null;
}
/**
* Return etag, if applicable.
*
* MAY override
*
* @return string etag http header
*/
function etag()
{
return null;
}
/**
* Does this require authentication?
*
* @return boolean true if delete, else false
*/
function requiresAuth()
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
return false;
} else {
return true;
}
}
/**
* 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,355 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* Feed of group memberships for a user, in ActivityStreams format
*
* PHP version 5
*
* 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 AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
// This check helps protect against security problems;
// your code file can't be executed directly from the web.
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Feed of group memberships for a user, in ActivityStreams format
*
* @category Action
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
class AtompubmembershipfeedAction extends ApiAuthAction
{
private $_profile = null;
private $_memberships = null;
/**
* For initializing members of the class.
*
* @param array $argarray misc. arguments
*
* @return boolean true
*/
function prepare($argarray)
{
parent::prepare($argarray);
$profileId = $this->trimmed('profile');
$this->_profile = Profile::staticGet('id', $profileId);
if (empty($this->_profile)) {
throw new ClientException(_('No such profile.'), 404);
}
$offset = ($this->page-1) * $this->count;
$limit = $this->count + 1;
$this->_memberships = Group_member::byMember($this->_profile->id,
$offset,
$limit);
return true;
}
/**
* Handler method
*
* @param array $argarray is ignored since it's now passed in in prepare()
*
* @return void
*/
function handle($argarray=null)
{
parent::handle($argarray);
switch ($_SERVER['REQUEST_METHOD']) {
case 'HEAD':
case 'GET':
$this->showFeed();
break;
case 'POST':
$this->addMembership();
break;
default:
throw new ClientException(_('HTTP method not supported.'), 405);
return;
}
return;
}
/**
* Show a feed of favorite activity streams objects
*
* @return void
*/
function showFeed()
{
header('Content-Type: application/atom+xml; charset=utf-8');
$url = common_local_url('AtomPubMembershipFeed',
array('profile' => $this->_profile->id));
$feed = new Atom10Feed(true);
$feed->addNamespace('activity',
'http://activitystrea.ms/spec/1.0/');
$feed->addNamespace('poco',
'http://portablecontacts.net/spec/1.0');
$feed->addNamespace('media',
'http://purl.org/syndication/atommedia');
$feed->id = $url;
$feed->setUpdated('now');
$feed->addAuthor($this->_profile->getBestName(),
$this->_profile->getURI());
$feed->setTitle(sprintf(_("%s group memberships"),
$this->_profile->getBestName()));
$feed->setSubtitle(sprintf(_("Groups %s is a member of on %s"),
$this->_profile->getBestName(),
common_config('site', 'name')));
$feed->addLink(common_local_url('usergroups',
array('nickname' =>
$this->_profile->nickname)));
$feed->addLink($url,
array('rel' => 'self',
'type' => 'application/atom+xml'));
// If there's more...
if ($this->page > 1) {
$feed->addLink($url,
array('rel' => 'first',
'type' => 'application/atom+xml'));
$feed->addLink(common_local_url('AtomPubMembershipFeed',
array('profile' =>
$this->_profile->id),
array('page' =>
$this->page - 1)),
array('rel' => 'prev',
'type' => 'application/atom+xml'));
}
if ($this->_memberships->N > $this->count) {
$feed->addLink(common_local_url('AtomPubMembershipFeed',
array('profile' =>
$this->_profile->id),
array('page' =>
$this->page + 1)),
array('rel' => 'next',
'type' => 'application/atom+xml'));
}
$i = 0;
while ($this->_memberships->fetch()) {
// We get one more than needed; skip that one
$i++;
if ($i > $this->count) {
break;
}
$act = $this->_memberships->asActivity();
$feed->addEntryRaw($act->asString(false, false, false));
}
$this->raw($feed->getString());
}
/**
* add a new favorite
*
* @return void
*/
function addMembership()
{
// XXX: Refactor this; all the same for atompub
if (empty($this->auth_user) ||
$this->auth_user->id != $this->_profile->id) {
throw new ClientException(_("Can't add someone else's".
" membership"), 403);
}
$xml = file_get_contents('php://input');
$dom = DOMDocument::loadXML($xml);
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
$dom->documentElement->localName != 'entry') {
// TRANS: Client error displayed when not using an Atom entry.
throw new ClientException(_('Atom post must be an Atom entry.'));
return;
}
$activity = new Activity($dom->documentElement);
$membership = null;
if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
if ($activity->verb != ActivityVerb::JOIN) {
// TRANS: Client error displayed when not using the POST verb.
// TRANS: Do not translate POST.
throw new ClientException(_('Can only handle Join activities.'));
return;
}
$groupObj = $activity->objects[0];
if ($groupObj->type != ActivityObject::GROUP) {
throw new ClientException(_('Can only fave notices.'));
return;
}
$group = User_group::staticGet('uri', $groupObj->id);
if (empty($group)) {
// XXX: import from listed URL or something
throw new ClientException(_('Unknown group.'));
}
$old = Group_member::pkeyGet(array('profile_id' => $this->auth_user->id,
'group_id' => $group->id));
if (!empty($old)) {
throw new ClientException(_('Already a member.'));
}
$profile = $this->auth_user->getProfile();
if (Group_block::isBlocked($group, $profile)) {
// XXX: import from listed URL or something
throw new ClientException(_('Blocked by admin.'));
}
if (Event::handle('StartJoinGroup', array($group, $this->auth_user))) {
$membership = Group_member::join($group->id, $this->auth_user->id);
Event::handle('EndJoinGroup', array($group, $this->auth_user));
}
Event::handle('EndAtomPubNewActivity', array($activity, $membership));
}
if (!empty($membership)) {
$act = $membership->asActivity();
header('Content-Type: application/atom+xml; charset=utf-8');
header('Content-Location: ' . $act->selfLink);
$this->startXML();
$this->raw($act->asString(true, true, true));
$this->endXML();
}
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
return true;
} else {
return false;
}
}
/**
* Return last modified, if applicable.
*
* MAY override
*
* @return string last modified http header
*/
function lastModified()
{
// For comparison with If-Last-Modified
// If not applicable, return null
return null;
}
/**
* Return etag, if applicable.
*
* MAY override
*
* @return string etag http header
*/
function etag()
{
return null;
}
/**
* Does this require authentication?
*
* @return boolean true if delete, else false
*/
function requiresAuth()
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
return false;
} else {
return true;
}
}
}

View File

@ -0,0 +1,228 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* Show a single favorite in Atom Activity Streams format
*
* PHP version 5
*
* 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 AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
// This check helps protect against security problems;
// your code file can't be executed directly from the web.
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Show a single favorite in Atom Activity Streams format.
*
* Can also be used to delete a favorite.
*
* @category Action
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
class AtompubshowfavoriteAction extends ApiAuthAction
{
private $_profile = null;
private $_notice = null;
private $_fave = null;
/**
* For initializing members of the class.
*
* @param array $argarray misc. arguments
*
* @return boolean true
*/
function prepare($argarray)
{
parent::prepare($argarray);
$profileId = $this->trimmed('profile');
$noticeId = $this->trimmed('notice');
$this->_profile = Profile::staticGet('id', $profileId);
if (empty($this->_profile)) {
throw new ClientException(_('No such profile.'), 404);
}
$this->_notice = Notice::staticGet('id', $noticeId);
if (empty($this->_notice)) {
throw new ClientException(_('No such notice.'), 404);
}
$this->_fave = Fave::pkeyGet(array('user_id' => $profileId,
'notice_id' => $noticeId));
if (empty($this->_fave)) {
throw new ClientException(_('No such favorite.'), 404);
}
return true;
}
/**
* Handler method
*
* @param array $argarray is ignored since it's now passed in in prepare()
*
* @return void
*/
function handle($argarray=null)
{
parent::handle($argarray);
switch ($_SERVER['REQUEST_METHOD']) {
case GET:
case HEAD:
$this->showFave();
break;
case DELETE:
$this->deleteFave();
break;
default:
throw new ClientException(_('HTTP method not supported.'),
405);
}
return true;
}
/**
* Show a single favorite, in ActivityStreams format
*
* @return void
*/
function showFave()
{
$activity = $this->_fave->asActivity();
header('Content-Type: application/atom+xml; charset=utf-8');
$this->startXML();
$this->raw($activity->asString(true, true, true));
$this->endXML();
return;
}
/**
* Delete the favorite
*
* @return void
*/
function deleteFave()
{
if (empty($this->auth_user) ||
$this->auth_user->id != $this->_profile->id) {
throw new ClientException(_("Can't delete someone else's".
" favorite"), 403);
}
$this->_fave->delete();
return;
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
return true;
} else {
return false;
}
}
/**
* Return last modified, if applicable.
*
* MAY override
*
* @return string last modified http header
*/
function lastModified()
{
return max(strtotime($this->_profile->modified),
strtotime($this->_notice->modified),
strtotime($this->_fave->modified));
}
/**
* Return etag, if applicable.
*
* MAY override
*
* @return string etag http header
*/
function etag()
{
$mtime = strtotime($this->_fave->modified);
return 'W/"' . implode(':', array('AtomPubShowFavorite',
$this->_profile->id,
$this->_notice->id,
$mtime)) . '"';
}
/**
* Does this require authentication?
*
* @return boolean true if delete, else false
*/
function requiresAuth()
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
return false;
} else {
return true;
}
}
}

View File

@ -0,0 +1,235 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* Show a single membership as an Activity Streams entry
*
* PHP version 5
*
* 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 AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
// This check helps protect against security problems;
// your code file can't be executed directly from the web.
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Show (or delete) a single membership event as an ActivityStreams entry
*
* @category AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
class AtompubshowmembershipAction extends ApiAuthAction
{
private $_profile = null;
private $_group = null;
private $_membership = null;
/**
* For initializing members of the class.
*
* @param array $argarray misc. arguments
*
* @return boolean true
*/
function prepare($argarray)
{
parent::prepare($argarray);
$profileId = $this->trimmed('profile');
$this->_profile = Profile::staticGet('id', $profileId);
if (empty($this->_profile)) {
throw new ClientException(_('No such profile.'), 404);
}
$groupId = $this->trimmed('group');
$this->_group = User_group::staticGet('id', $groupId);
if (empty($this->_group)) {
throw new ClientException(_('No such group'), 404);
}
$kv = array('group_id' => $groupId,
'profile_id' => $profileId);
$this->_membership = Group_member::pkeyGet($kv);
if (empty($this->_membership)) {
throw new ClientException(_('Not a member'), 404);
}
return true;
}
/**
* Handler method
*
* @param array $argarray is ignored since it's now passed in in prepare()
*
* @return void
*/
function handle($argarray=null)
{
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
case 'HEAD':
$this->showMembership();
break;
case 'DELETE':
$this->deleteMembership();
break;
default:
throw new ClientException(_('Method not supported'), 405);
break;
}
return;
}
/**
* show a single membership
*
* @return void
*/
function showMembership()
{
$activity = $this->_membership->asActivity();
header('Content-Type: application/atom+xml; charset=utf-8');
$this->startXML();
$this->raw($activity->asString(true, true, true));
$this->endXML();
return;
}
/**
* Delete the membership (leave the group)
*
* @return void
*/
function deleteMembership()
{
if (empty($this->auth_user) ||
$this->auth_user->id != $this->_profile->id) {
throw new ClientException(_("Can't delete someone else's".
" membership"), 403);
}
if (Event::handle('StartLeaveGroup', array($this->_group, $this->auth_user))) {
Group_member::leave($this->_group->id, $this->auth_user->id);
Event::handle('EndLeaveGroup', array($this->_group, $this->auth_user));
}
return;
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
return true;
} else {
return false;
}
}
/**
* Return last modified, if applicable.
*
* Because the representation depends on the profile and group,
* our last modified value is the maximum of their mod time
* with the actual membership's mod time.
*
* @return string last modified http header
*/
function lastModified()
{
return max(strtotime($this->_profile->modified),
strtotime($this->_group->modified),
strtotime($this->_membership->modified));
}
/**
* Return etag, if applicable.
*
* A "weak" Etag including the profile and group id as well as
* the admin flag and ctime of the membership.
*
* @return string etag http header
*/
function etag()
{
$ctime = strtotime($this->_membership->created);
$adminflag = ($this->_membership->is_admin) ? 't' : 'f';
return 'W/"' . implode(':', array('AtomPubShowMembership',
$this->_profile->id,
$this->_group->id,
$adminflag,
$ctime)) . '"';
}
/**
* Does this require authentication?
*
* @return boolean true if delete, else false
*/
function requiresAuth()
{
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
return false;
} else {
return true;
}
}
}

View File

@ -0,0 +1,224 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* Single subscription
*
* PHP version 5
*
* 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 AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
// This check helps protect against security problems;
// your code file can't be executed directly from the web.
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Show a single subscription
*
* @category AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
class AtompubshowsubscriptionAction extends ApiAuthAction
{
private $_subscriber = null;
private $_subscribed = null;
private $_subscription = null;
/**
* For initializing members of the class.
*
* @param array $argarray misc. arguments
*
* @return boolean true
*/
function prepare($argarray)
{
parent::prepare($argarray);
$subscriberId = $this->trimmed('subscriber');
$this->_subscriber = Profile::staticGet('id', $subscriberId);
if (empty($this->_subscriber)) {
throw new ClientException(sprintf(_('No such profile id: %d'),
$subscriberId), 404);
}
$subscribedId = $this->trimmed('subscribed');
$this->_subscribed = Profile::staticGet('id', $subscribedId);
if (empty($this->_subscribed)) {
throw new ClientException(sprintf(_('No such profile id: %d'),
$subscribedId), 404);
}
$this->_subscription =
Subscription::pkeyGet(array('subscriber' => $subscriberId,
'subscribed' => $subscribedId));
if (empty($this->_subscription)) {
$msg = sprintf(_('Profile %d not subscribed to profile %d'),
$subscriberId, $subscribedId);
throw new ClientException($msg, 404);
}
return true;
}
/**
* Handler method
*
* @param array $argarray is ignored since it's now passed in in prepare()
*
* @return void
*/
function handle($argarray=null)
{
parent::handle($argarray);
switch ($_SERVER['REQUEST_METHOD']) {
case 'HEAD':
case 'GET':
$this->showSubscription();
break;
case 'DELETE':
$this->deleteSubscription();
break;
default:
$this->clientError(_('HTTP method not supported.'), 405);
return;
}
return;
}
/**
* Show the subscription in ActivityStreams Atom format.
*
* @return void
*/
function showSubscription()
{
$activity = $this->_subscription->asActivity();
header('Content-Type: application/atom+xml; charset=utf-8');
$this->startXML();
$this->raw($activity->asString(true, true, true));
$this->endXML();
return;
}
/**
* Delete the subscription
*
* @return void
*/
function deleteSubscription()
{
if (empty($this->auth_user) ||
$this->auth_user->id != $this->_subscriber->id) {
throw new ClientException(_("Can't delete someone else's".
" subscription"), 403);
}
Subscription::cancel($this->_subscriber,
$this->_subscribed);
return;
}
/**
* Is this action read only?
*
* @param array $args other arguments
*
* @return boolean true
*/
function isReadOnly($args)
{
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
return false;
} else {
return true;
}
}
/**
* Return last modified, if applicable.
*
* @return string last modified http header
*/
function lastModified()
{
return max(strtotime($this->_subscriber->modified),
strtotime($this->_subscribed->modified),
strtotime($this->_subscription->modified));
}
/**
* Etag for this object
*
* @return string etag http header
*/
function etag()
{
$mtime = strtotime($this->_subscription->modified);
return 'W/"' . implode(':', array('AtomPubShowSubscription',
$this->_subscriber->id,
$this->_subscribed->id,
$mtime)) . '"';
}
/**
* Does this require authentication?
*
* @return boolean true if delete, else false
*/
function requiresAuth()
{
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
return true;
} else {
return false;
}
}
}

View File

@ -0,0 +1,335 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* AtomPub subscription feed
*
* PHP version 5
*
* 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 Cache
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
// This check helps protect against security problems;
// your code file can't be executed directly from the web.
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
/**
* Subscription feed class for AtomPub
*
* Generates a list of the user's subscriptions
*
* @category AtomPub
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
class AtompubsubscriptionfeedAction extends ApiAuthAction
{
private $_profile = null;
private $_subscriptions = null;
/**
* For initializing members of the class.
*
* @param array $argarray misc. arguments
*
* @return boolean true
*/
function prepare($argarray)
{
parent::prepare($argarray);
$subscriber = $this->trimmed('subscriber');
$this->_profile = Profile::staticGet('id', $subscriber);
if (empty($this->_profile)) {
throw new ClientException(sprintf(_('No such profile id: %d'),
$subscriber), 404);
}
// page and count from ApiAction
$offset = ($this->page-1) * $this->count;
$this->_subscriptions = Subscription::bySubscriber($subscriber,
$offset,
$this->count + 1);
return true;
}
/**
* Handler method
*
* @param array $argarray is ignored since it's now passed in in prepare()
*
* @return void
*/
function handle($argarray=null)
{
parent::handle($argarray);
switch ($_SERVER['REQUEST_METHOD']) {
case 'HEAD':
case 'GET':
$this->showFeed();
break;
case 'POST':
$this->addSubscription();
break;
default:
$this->clientError(_('HTTP method not supported.'), 405);
return;
}
return;
}
/**
* Show the feed of subscriptions
*
* @return void
*/
function showFeed()
{
header('Content-Type: application/atom+xml; charset=utf-8');
$url = common_local_url('AtomPubSubscriptionFeed',
array('subscriber' => $this->_profile->id));
$feed = new Atom10Feed(true);
$feed->addNamespace('activity',
'http://activitystrea.ms/spec/1.0/');
$feed->addNamespace('poco',
'http://portablecontacts.net/spec/1.0');
$feed->addNamespace('media',
'http://purl.org/syndication/atommedia');
$feed->id = $url;
$feed->setUpdated('now');
$feed->addAuthor($this->_profile->getBestName(),
$this->_profile->getURI());
$feed->setTitle(sprintf(_("%s subscriptions"),
$this->_profile->getBestName()));
$feed->setSubtitle(sprintf(_("People %s has subscribed to on %s"),
$this->_profile->getBestName(),
common_config('site', 'name')));
$feed->addLink(common_local_url('subscriptions',
array('nickname' =>
$this->_profile->nickname)));
$feed->addLink($url,
array('rel' => 'self',
'type' => 'application/atom+xml'));
// If there's more...
if ($this->page > 1) {
$feed->addLink($url,
array('rel' => 'first',
'type' => 'application/atom+xml'));
$feed->addLink(common_local_url('AtomPubSubscriptionFeed',
array('subscriber' =>
$this->_profile->id),
array('page' =>
$this->page - 1)),
array('rel' => 'prev',
'type' => 'application/atom+xml'));
}
if ($this->_subscriptions->N > $this->count) {
$feed->addLink(common_local_url('AtomPubSubscriptionFeed',
array('subscriber' =>
$this->_profile->id),
array('page' =>
$this->page + 1)),
array('rel' => 'next',
'type' => 'application/atom+xml'));
}
$i = 0;
// XXX: This is kind of inefficient
while ($this->_subscriptions->fetch()) {
// We get one more than needed; skip that one
$i++;
if ($i > $this->count) {
break;
}
$act = $this->_subscriptions->asActivity();
$feed->addEntryRaw($act->asString(false, false, false));
}
$this->raw($feed->getString());
}
/**
* Add a new subscription
*
* Handling the POST method for AtomPub
*
* @return void
*/
function addSubscription()
{
if (empty($this->auth_user) ||
$this->auth_user->id != $this->_profile->id) {
throw new ClientException(_("Can't add someone else's".
" subscription"), 403);
}
$xml = file_get_contents('php://input');
$dom = DOMDocument::loadXML($xml);
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
$dom->documentElement->localName != 'entry') {
// TRANS: Client error displayed when not using an Atom entry.
$this->clientError(_('Atom post must be an Atom entry.'));
return;
}
$activity = new Activity($dom->documentElement);
$sub = null;
if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
if ($activity->verb != ActivityVerb::FOLLOW) {
// TRANS: Client error displayed when not using the POST verb.
// TRANS: Do not translate POST.
$this->clientError(_('Can only handle Follow activities.'));
return;
}
$person = $activity->objects[0];
if ($person->type != ActivityObject::PERSON) {
$this->clientError(_('Can only follow people.'));
return;
}
// XXX: OStatus discovery (maybe)
$profile = Profile::fromURI($person->id);
if (empty($profile)) {
$this->clientError(sprintf(_('Unknown profile %s'), $person->id));
return;
}
if (Subscription::start($this->_profile, $profile)) {
$sub = Subscription::pkeyGet(array('subscriber' => $this->_profile->id,
'subscribed' => $profile->id));
}
Event::handle('EndAtomPubNewActivity', array($activity, $sub));
}
if (!empty($sub)) {
$act = $sub->asActivity();
header('Content-Type: application/atom+xml; charset=utf-8');
header('Content-Location: ' . $act->selfLink);
$this->startXML();
$this->raw($act->asString(true, true, true));
$this->endXML();
}
}
/**
* Return true if read only.
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return $_SERVER['REQUEST_METHOD'] != 'POST';
}
/**
* Return last modified, if applicable.
*
* @return string last modified http header
*/
function lastModified()
{
return null;
}
/**
* Return etag, if applicable.
*
* @return string etag http header
*/
function etag()
{
return null;
}
/**
* Does this require authentication?
*
* @return boolean true if delete, else false
*/
function requiresAuth()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
return true;
} else {
return false;
}
}
}

View File

@ -42,7 +42,6 @@ require_once INSTALLDIR.'/lib/attachmentlist.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class AttachmentAction extends Action class AttachmentAction extends Action
{ {
/** /**
@ -70,6 +69,7 @@ class AttachmentAction extends Action
} }
if (empty($this->attachment)) { if (empty($this->attachment)) {
// TRANS: Client error displayed trying to get a non-existing attachment.
$this->clientError(_('No such attachment.'), 404); $this->clientError(_('No such attachment.'), 404);
return false; return false;
} }
@ -81,7 +81,6 @@ class AttachmentAction extends Action
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly($args) function isReadOnly($args)
{ {
return true; return true;
@ -129,7 +128,6 @@ class AttachmentAction extends Action
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -150,7 +148,6 @@ class AttachmentAction extends Action
* *
* @return void * @return void
*/ */
function showLocalNavBlock() function showLocalNavBlock()
{ {
} }
@ -162,7 +159,6 @@ class AttachmentAction extends Action
* *
* @return void * @return void
*/ */
function showContent() function showContent()
{ {
$ali = new Attachment($this->attachment, $this); $ali = new Attachment($this->attachment, $this);
@ -174,7 +170,6 @@ class AttachmentAction extends Action
* *
* @return void * @return void
*/ */
function showPageNoticeBlock() function showPageNoticeBlock()
{ {
} }
@ -191,4 +186,3 @@ class AttachmentAction extends Action
$atcs->show(); $atcs->show();
} }
} }

View File

@ -42,7 +42,6 @@ require_once INSTALLDIR.'/actions/attachment.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class Attachment_ajaxAction extends AttachmentAction class Attachment_ajaxAction extends AttachmentAction
{ {
/** /**
@ -80,4 +79,3 @@ class Attachment_ajaxAction extends AttachmentAction
$this->elementEnd('div'); $this->elementEnd('div');
} }
} }

View File

@ -42,10 +42,8 @@ require_once INSTALLDIR.'/actions/attachment.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class Attachment_thumbnailAction extends AttachmentAction class Attachment_thumbnailAction extends AttachmentAction
{ {
function handle($args) function handle($args)
{ {
$this->showPage(); $this->showPage();
@ -79,6 +77,4 @@ class Attachment_thumbnailAction extends AttachmentAction
} }
$this->element('img', array('src' => $file_thumbnail->url, 'alt' => 'Thumbnail')); $this->element('img', array('src' => $file_thumbnail->url, 'alt' => 'Thumbnail'));
} }
} }

View File

@ -56,27 +56,32 @@ class AvatarbynicknameAction extends Action
parent::handle($args); parent::handle($args);
$nickname = $this->trimmed('nickname'); $nickname = $this->trimmed('nickname');
if (!$nickname) { if (!$nickname) {
// TRANS: Client error displayed trying to get an avatar without providing a nickname.
$this->clientError(_('No nickname.')); $this->clientError(_('No nickname.'));
return; return;
} }
$size = $this->trimmed('size'); $size = $this->trimmed('size');
if (!$size) { if (!$size) {
// TRANS: Client error displayed trying to get an avatar without providing an avatar size.
$this->clientError(_('No size.')); $this->clientError(_('No size.'));
return; return;
} }
$size = strtolower($size); $size = strtolower($size);
if (!in_array($size, array('original', '96', '48', '24'))) { if (!in_array($size, array('original', '96', '48', '24'))) {
// TRANS: Client error displayed trying to get an avatar providing an invalid avatar size.
$this->clientError(_('Invalid size.')); $this->clientError(_('Invalid size.'));
return; return;
} }
$user = User::staticGet('nickname', $nickname); $user = User::staticGet('nickname', $nickname);
if (!$user) { if (!$user) {
// TRANS: Client error displayed trying to get an avatar for a non-existing user.
$this->clientError(_('No such user.')); $this->clientError(_('No such user.'));
return; return;
} }
$profile = $user->getProfile(); $profile = $user->getProfile();
if (!$profile) { if (!$profile) {
// TRANS: Client error displayed trying to get an avatar for a user without a profile.
$this->clientError(_('User has no profile.')); $this->clientError(_('User has no profile.'));
return; return;
} }
@ -103,4 +108,3 @@ class AvatarbynicknameAction extends Action
return true; return true;
} }
} }

View File

@ -49,7 +49,6 @@ define('MAX_ORIGINAL', 480);
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class AvatarsettingsAction extends AccountSettingsAction class AvatarsettingsAction extends AccountSettingsAction
{ {
var $mode = null; var $mode = null;
@ -61,9 +60,9 @@ class AvatarsettingsAction extends AccountSettingsAction
* *
* @return string Title of the page * @return string Title of the page
*/ */
function title() function title()
{ {
// TRANS: Title for avatar upload page.
return _('Avatar'); return _('Avatar');
} }
@ -72,10 +71,12 @@ class AvatarsettingsAction extends AccountSettingsAction
* *
* @return instructions for use * @return instructions for use
*/ */
function getInstructions() function getInstructions()
{ {
return sprintf(_('You can upload your personal avatar. The maximum file size is %s.'), ImageFile::maxFileSize()); // TRANS: Instruction for avatar upload page.
// TRANS: %s is the maximum file size, for example "500b", "10kB" or "2MB".
return sprintf(_('You can upload your personal avatar. The maximum file size is %s.'),
ImageFile::maxFileSize());
} }
/** /**
@ -103,6 +104,7 @@ class AvatarsettingsAction extends AccountSettingsAction
if (!$profile) { if (!$profile) {
common_log_db_error($user, 'SELECT', __FILE__); common_log_db_error($user, 'SELECT', __FILE__);
// TRANS: Server error displayed in avatar upload page when no matching profile can be found for a user.
$this->serverError(_('User without matching profile.')); $this->serverError(_('User without matching profile.'));
return; return;
} }
@ -116,6 +118,7 @@ class AvatarsettingsAction extends AccountSettingsAction
'action' => 'action' =>
common_local_url('avatarsettings'))); common_local_url('avatarsettings')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
// TRANS: Avatar upload page form legend.
$this->element('legend', null, _('Avatar settings')); $this->element('legend', null, _('Avatar settings'));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
@ -124,6 +127,7 @@ class AvatarsettingsAction extends AccountSettingsAction
if ($original) { if ($original) {
$this->elementStart('li', array('id' => 'avatar_original', $this->elementStart('li', array('id' => 'avatar_original',
'class' => 'avatar_view')); 'class' => 'avatar_view'));
// TRANS: Header on avatar upload page for thumbnail of originally uploaded avatar (h2).
$this->element('h2', null, _("Original")); $this->element('h2', null, _("Original"));
$this->elementStart('div', array('id'=>'avatar_original_view')); $this->elementStart('div', array('id'=>'avatar_original_view'));
$this->element('img', array('src' => $original->url, $this->element('img', array('src' => $original->url,
@ -139,6 +143,7 @@ class AvatarsettingsAction extends AccountSettingsAction
if ($avatar) { if ($avatar) {
$this->elementStart('li', array('id' => 'avatar_preview', $this->elementStart('li', array('id' => 'avatar_preview',
'class' => 'avatar_view')); 'class' => 'avatar_view'));
// TRANS: Header on avatar upload page for thumbnail of to be used rendition of uploaded avatar (h2).
$this->element('h2', null, _("Preview")); $this->element('h2', null, _("Preview"));
$this->elementStart('div', array('id'=>'avatar_preview_view')); $this->elementStart('div', array('id'=>'avatar_preview_view'));
$this->element('img', array('src' => $original->url, $this->element('img', array('src' => $original->url,
@ -146,7 +151,8 @@ class AvatarsettingsAction extends AccountSettingsAction
'height' => AVATAR_PROFILE_SIZE, 'height' => AVATAR_PROFILE_SIZE,
'alt' => $user->nickname)); 'alt' => $user->nickname));
$this->elementEnd('div'); $this->elementEnd('div');
$this->submit('delete', _('Delete')); // TRANS: Button on avatar upload page to delete current avatar.
$this->submit('delete', _m('BUTTON','Delete'));
$this->elementEnd('li'); $this->elementEnd('li');
} }
@ -163,7 +169,8 @@ class AvatarsettingsAction extends AccountSettingsAction
$this->elementStart('ul', 'form_actions'); $this->elementStart('ul', 'form_actions');
$this->elementStart('li'); $this->elementStart('li');
$this->submit('upload', _('Upload')); // TRANS: Button on avatar upload page to upload an avatar.
$this->submit('upload', _m('BUTTON','Upload'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
} }
@ -171,7 +178,6 @@ class AvatarsettingsAction extends AccountSettingsAction
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
} }
function showCropForm() function showCropForm()
@ -182,6 +188,7 @@ class AvatarsettingsAction extends AccountSettingsAction
if (!$profile) { if (!$profile) {
common_log_db_error($user, 'SELECT', __FILE__); common_log_db_error($user, 'SELECT', __FILE__);
// TRANS: Server error displayed in avatar upload page when no matching profile can be found for a user.
$this->serverError(_('User without matching profile.')); $this->serverError(_('User without matching profile.'));
return; return;
} }
@ -194,6 +201,7 @@ class AvatarsettingsAction extends AccountSettingsAction
'action' => 'action' =>
common_local_url('avatarsettings'))); common_local_url('avatarsettings')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
// TRANS: Avatar upload page crop form legend.
$this->element('legend', null, _('Avatar settings')); $this->element('legend', null, _('Avatar settings'));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
@ -202,6 +210,7 @@ class AvatarsettingsAction extends AccountSettingsAction
$this->elementStart('li', $this->elementStart('li',
array('id' => 'avatar_original', array('id' => 'avatar_original',
'class' => 'avatar_view')); 'class' => 'avatar_view'));
// TRANS: Header on avatar upload crop form for thumbnail of originally uploaded avatar (h2).
$this->element('h2', null, _("Original")); $this->element('h2', null, _("Original"));
$this->elementStart('div', array('id'=>'avatar_original_view')); $this->elementStart('div', array('id'=>'avatar_original_view'));
$this->element('img', array('src' => Avatar::url($this->filedata['filename']), $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
@ -214,6 +223,7 @@ class AvatarsettingsAction extends AccountSettingsAction
$this->elementStart('li', $this->elementStart('li',
array('id' => 'avatar_preview', array('id' => 'avatar_preview',
'class' => 'avatar_view')); 'class' => 'avatar_view'));
// TRANS: Header on avatar upload crop form for thumbnail of to be used rendition of uploaded avatar (h2).
$this->element('h2', null, _("Preview")); $this->element('h2', null, _("Preview"));
$this->elementStart('div', array('id'=>'avatar_preview_view')); $this->elementStart('div', array('id'=>'avatar_preview_view'));
$this->element('img', array('src' => Avatar::url($this->filedata['filename']), $this->element('img', array('src' => Avatar::url($this->filedata['filename']),
@ -228,13 +238,14 @@ class AvatarsettingsAction extends AccountSettingsAction
'type' => 'hidden', 'type' => 'hidden',
'id' => $crop_info)); 'id' => $crop_info));
} }
$this->submit('crop', _('Crop'));
// TRANS: Button on avatar upload crop form to confirm a selected crop as avatar.
$this->submit('crop', _m('BUTTON','Crop'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
} }
/** /**
@ -244,7 +255,6 @@ class AvatarsettingsAction extends AccountSettingsAction
* *
* @return void * @return void
*/ */
function handlePost() function handlePost()
{ {
// Workaround for PHP returning empty $_POST and $_FILES when POST // Workaround for PHP returning empty $_POST and $_FILES when POST
@ -254,9 +264,11 @@ class AvatarsettingsAction extends AccountSettingsAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
@ -278,6 +290,7 @@ class AvatarsettingsAction extends AccountSettingsAction
} else if ($this->arg('delete')) { } else if ($this->arg('delete')) {
$this->deleteAvatar(); $this->deleteAvatar();
} else { } else {
// TRANS: Unexpected validation error on avatar upload form.
$this->showForm(_('Unexpected form submission.')); $this->showForm(_('Unexpected form submission.'));
} }
Event::handle('EndAvatarSaveForm', array($this)); Event::handle('EndAvatarSaveForm', array($this));
@ -292,7 +305,6 @@ class AvatarsettingsAction extends AccountSettingsAction
* *
* @return void * @return void
*/ */
function uploadAvatar() function uploadAvatar()
{ {
try { try {
@ -302,6 +314,7 @@ class AvatarsettingsAction extends AccountSettingsAction
return; return;
} }
if ($imagefile === null) { if ($imagefile === null) {
// TRANS: Validation error on avatar upload form when no file was uploaded.
$this->showForm(_('No file uploaded.')); $this->showForm(_('No file uploaded.'));
return; return;
} }
@ -329,6 +342,7 @@ class AvatarsettingsAction extends AccountSettingsAction
$this->mode = 'crop'; $this->mode = 'crop';
// TRANS: Avatar upload form unstruction after uploading a file.
$this->showForm(_('Pick a square area of the image to be your avatar'), $this->showForm(_('Pick a square area of the image to be your avatar'),
true); true);
} }
@ -338,12 +352,12 @@ class AvatarsettingsAction extends AccountSettingsAction
* *
* @return void * @return void
*/ */
function cropAvatar() function cropAvatar()
{ {
$filedata = $_SESSION['FILEDATA']; $filedata = $_SESSION['FILEDATA'];
if (!$filedata) { if (!$filedata) {
// TRANS: Server error displayed if an avatar upload went wrong somehow server side.
$this->serverError(_('Lost our file data.')); $this->serverError(_('Lost our file data.'));
return; return;
} }
@ -367,9 +381,11 @@ class AvatarsettingsAction extends AccountSettingsAction
@unlink($filedata['filepath']); @unlink($filedata['filepath']);
unset($_SESSION['FILEDATA']); unset($_SESSION['FILEDATA']);
$this->mode = 'upload'; $this->mode = 'upload';
// TRANS: Success message for having updated a user avatar.
$this->showForm(_('Avatar updated.'), true); $this->showForm(_('Avatar updated.'), true);
common_broadcast_profile($profile); common_broadcast_profile($profile);
} else { } else {
// TRANS: Error displayed on the avatar upload page if the avatar could not be updated for an unknown reason.
$this->showForm(_('Failed updating avatar.')); $this->showForm(_('Failed updating avatar.'));
} }
} }
@ -379,7 +395,6 @@ class AvatarsettingsAction extends AccountSettingsAction
* *
* @return void * @return void
*/ */
function deleteAvatar() function deleteAvatar()
{ {
$user = common_current_user(); $user = common_current_user();
@ -394,6 +409,7 @@ class AvatarsettingsAction extends AccountSettingsAction
$avatar = $profile->getAvatar(AVATAR_MINI_SIZE); $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
if($avatar) $avatar->delete(); if($avatar) $avatar->delete();
// TRANS: Success message for deleting a user avatar.
$this->showForm(_('Avatar deleted.'), true); $this->showForm(_('Avatar deleted.'), true);
} }
@ -414,7 +430,6 @@ class AvatarsettingsAction extends AccountSettingsAction
* *
* @return void * @return void
*/ */
function showScripts() function showScripts()
{ {
parent::showScripts(); parent::showScripts();

View File

@ -42,7 +42,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/ * @link http://status.net/
*/ */
class BlockAction extends ProfileFormAction class BlockAction extends ProfileFormAction
{ {
var $profile = null; var $profile = null;
@ -54,7 +53,6 @@ class BlockAction extends ProfileFormAction
* *
* @return boolean success flag * @return boolean success flag
*/ */
function prepare($args) function prepare($args)
{ {
if (!parent::prepare($args)) { if (!parent::prepare($args)) {
@ -66,6 +64,7 @@ class BlockAction extends ProfileFormAction
assert(!empty($cur)); // checked by parent assert(!empty($cur)); // checked by parent
if ($cur->hasBlocked($this->profile)) { if ($cur->hasBlocked($this->profile)) {
// TRANS: Client error displayed when blocking a user that has already been blocked.
$this->clientError(_('You already blocked that user.')); $this->clientError(_('You already blocked that user.'));
return false; return false;
} }
@ -82,7 +81,6 @@ class BlockAction extends ProfileFormAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
@ -104,6 +102,7 @@ class BlockAction extends ProfileFormAction
} }
function title() { function title() {
// TRANS: Title for block user page.
return _('Block user'); return _('Block user');
} }
@ -133,8 +132,10 @@ class BlockAction extends ProfileFormAction
'action' => common_local_url('block'))); 'action' => common_local_url('block')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
// TRANS: Legend for block user form.
$this->element('legend', _('Block user')); $this->element('legend', _('Block user'));
$this->element('p', null, $this->element('p', null,
// TRANS: Explanation of consequences when blocking a user on the block user page.
_('Are you sure you want to block this user? '. _('Are you sure you want to block this user? '.
'Afterwards, they will be unsubscribed from you, '. 'Afterwards, they will be unsubscribed from you, '.
'unable to subscribe to you in the future, and '. 'unable to subscribe to you in the future, and '.
@ -184,6 +185,7 @@ class BlockAction extends ProfileFormAction
} }
if (!$result) { if (!$result) {
// TRANS: Server error displayed when blocking a user fails.
$this->serverError(_('Failed to save block information.')); $this->serverError(_('Failed to save block information.'));
return; return;
} }

View File

@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class BlockedfromgroupAction extends GroupDesignAction class BlockedfromgroupAction extends GroupDesignAction
{ {
var $page = null; var $page = null;
@ -70,6 +69,7 @@ class BlockedfromgroupAction extends GroupDesignAction
} }
if (!$nickname) { if (!$nickname) {
// TRANS: Client error displayed when requesting a list of blocked users for a group without providing a group nickname.
$this->clientError(_('No nickname.'), 404); $this->clientError(_('No nickname.'), 404);
return false; return false;
} }
@ -77,6 +77,7 @@ class BlockedfromgroupAction extends GroupDesignAction
$local = Local_group::staticGet('nickname', $nickname); $local = Local_group::staticGet('nickname', $nickname);
if (!$local) { if (!$local) {
// TRANS: Client error displayed when requesting a list of blocked users for a non-local group.
$this->clientError(_('No such group.'), 404); $this->clientError(_('No such group.'), 404);
return false; return false;
} }
@ -84,6 +85,7 @@ class BlockedfromgroupAction extends GroupDesignAction
$this->group = User_group::staticGet('id', $local->group_id); $this->group = User_group::staticGet('id', $local->group_id);
if (!$this->group) { if (!$this->group) {
// TRANS: Client error displayed when requesting a list of blocked users for a non-existing group.
$this->clientError(_('No such group.'), 404); $this->clientError(_('No such group.'), 404);
return false; return false;
} }
@ -94,9 +96,13 @@ class BlockedfromgroupAction extends GroupDesignAction
function title() function title()
{ {
if ($this->page == 1) { if ($this->page == 1) {
// TRANS: Title for first page with list of users blocked from a group.
// TRANS: %s is a group nickname.
return sprintf(_('%s blocked profiles'), return sprintf(_('%s blocked profiles'),
$this->group->nickname); $this->group->nickname);
} else { } else {
// TRANS: Title for any but the first page with list of users blocked from a group.
// TRANS: %1$s is a group nickname, %2$d is a page number.
return sprintf(_('%1$s blocked profiles, page %2$d'), return sprintf(_('%1$s blocked profiles, page %2$d'),
$this->group->nickname, $this->group->nickname,
$this->page); $this->page);
@ -112,6 +118,7 @@ class BlockedfromgroupAction extends GroupDesignAction
function showPageNotice() function showPageNotice()
{ {
$this->element('p', 'instructions', $this->element('p', 'instructions',
// TRANS: Instructions for list of users blocked from a group.
_('A list of the users blocked from joining this group.')); _('A list of the users blocked from joining this group.'));
} }
@ -205,7 +212,6 @@ class GroupBlockListItem extends ProfileListItem
* *
* @see UnblockForm * @see UnblockForm
*/ */
class GroupUnblockForm extends Form class GroupUnblockForm extends Form
{ {
/** /**
@ -234,7 +240,6 @@ class GroupUnblockForm extends Form
* @param User_group $group group to block user from * @param User_group $group group to block user from
* @param array $args return-to args * @param array $args return-to args
*/ */
function __construct($out=null, $profile=null, $group=null, $args=null) function __construct($out=null, $profile=null, $group=null, $args=null)
{ {
parent::__construct($out); parent::__construct($out);
@ -249,7 +254,6 @@ class GroupUnblockForm extends Form
* *
* @return int ID of the form * @return int ID of the form
*/ */
function id() function id()
{ {
// This should be unique for the page. // This should be unique for the page.
@ -261,7 +265,6 @@ class GroupUnblockForm extends Form
* *
* @return string class of the form * @return string class of the form
*/ */
function formClass() function formClass()
{ {
return 'form_group_unblock'; return 'form_group_unblock';
@ -272,7 +275,6 @@ class GroupUnblockForm extends Form
* *
* @return string URL of the action * @return string URL of the action
*/ */
function action() function action()
{ {
return common_local_url('groupunblock'); return common_local_url('groupunblock');
@ -285,6 +287,7 @@ class GroupUnblockForm extends Form
*/ */
function formLegend() function formLegend()
{ {
// TRANS: Form legend for unblocking a user from a group.
$this->out->element('legend', null, _('Unblock user from group')); $this->out->element('legend', null, _('Unblock user from group'));
} }
@ -293,7 +296,6 @@ class GroupUnblockForm extends Form
* *
* @return void * @return void
*/ */
function formData() function formData()
{ {
$this->out->hidden('unblockto-' . $this->profile->id, $this->out->hidden('unblockto-' . $this->profile->id,
@ -314,9 +316,14 @@ class GroupUnblockForm extends Form
* *
* @return void * @return void
*/ */
function formActions() function formActions()
{ {
$this->out->submit('submit', _('Unblock'), 'submit', null, _('Unblock this user')); $this->out->submit('submit',
// TRANS: Button text for unblocking a user from a group.
_m('BUTTON','Unblock'),
'submit',
null,
// TRANS: Tooltip for button for unblocking a user from a group.
_('Unblock this user'));
} }
} }

View File

@ -42,12 +42,12 @@ require_once INSTALLDIR . '/actions/newnotice.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class BookmarkletAction extends NewnoticeAction class BookmarkletAction extends NewnoticeAction
{ {
function showTitle() function showTitle()
{ {
// TRANS: Title for mini-posting window loaded from bookmarklet. // TRANS: Title for mini-posting window loaded from bookmarklet.
// TRANS: %s is the StatusNet site name.
$this->element('title', null, sprintf(_('Post to %s'), common_config('site', 'name'))); $this->element('title', null, sprintf(_('Post to %s'), common_config('site', 'name')));
} }
@ -73,4 +73,3 @@ class BookmarkletAction extends NewnoticeAction
{ {
} }
} }

View File

@ -44,7 +44,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class ConfirmaddressAction extends Action class ConfirmaddressAction extends Action
{ {
/** type of confirmation. */ /** type of confirmation. */
@ -61,7 +60,6 @@ class ConfirmaddressAction extends Action
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -72,16 +70,19 @@ class ConfirmaddressAction extends Action
} }
$code = $this->trimmed('code'); $code = $this->trimmed('code');
if (!$code) { if (!$code) {
// TRANS: Client error displayed when not providing a confirmation code in the contact address confirmation action.
$this->clientError(_('No confirmation code.')); $this->clientError(_('No confirmation code.'));
return; return;
} }
$confirm = Confirm_address::staticGet('code', $code); $confirm = Confirm_address::staticGet('code', $code);
if (!$confirm) { if (!$confirm) {
// TRANS: Client error displayed when providing a non-existing confirmation code in the contact address confirmation action.
$this->clientError(_('Confirmation code not found.')); $this->clientError(_('Confirmation code not found.'));
return; return;
} }
$cur = common_current_user(); $cur = common_current_user();
if ($cur->id != $confirm->user_id) { if ($cur->id != $confirm->user_id) {
// TRANS: Client error displayed when not providing a confirmation code for another user in the contact address confirmation action.
$this->clientError(_('That confirmation code is not for you!')); $this->clientError(_('That confirmation code is not for you!'));
return; return;
} }
@ -98,6 +99,7 @@ class ConfirmaddressAction extends Action
if (in_array($type, array('email', 'sms'))) if (in_array($type, array('email', 'sms')))
{ {
if ($cur->$type == $confirm->address) { if ($cur->$type == $confirm->address) {
// TRANS: Client error for an already confirmed email/jabber/sms address.
$this->clientError(_('That address has already been confirmed.')); $this->clientError(_('That address has already been confirmed.'));
return; return;
} }
@ -162,7 +164,9 @@ class ConfirmaddressAction extends Action
if (!$result) { if (!$result) {
common_log_db_error($confirm, 'DELETE', __FILE__); common_log_db_error($confirm, 'DELETE', __FILE__);
$this->serverError(_('Couldn\'t delete email confirmation.')); // TRANS: Server error displayed when an address confirmation code deletion from the
// TRANS: database fails in the contact address confirmation action.
$this->serverError(_('Could not delete address confirmation.'));
return; return;
} }
@ -175,9 +179,9 @@ class ConfirmaddressAction extends Action
* *
* @return string title * @return string title
*/ */
function title() function title()
{ {
// TRANS: Title for the contact address confirmation action.
return _('Confirm address'); return _('Confirm address');
} }
@ -186,12 +190,13 @@ class ConfirmaddressAction extends Action
* *
* @return void * @return void
*/ */
function showContent() function showContent()
{ {
$cur = common_current_user(); $cur = common_current_user();
$this->element('p', null, $this->element('p', null,
// TRANS: Success message for the contact address confirmation action.
// TRANS: %s can be 'email', 'jabber', or 'sms'.
sprintf(_('The address "%s" has been '. sprintf(_('The address "%s" has been '.
'confirmed for your account.'), 'confirmed for your account.'),
$this->address)); $this->address));

View File

@ -45,7 +45,6 @@ require_once INSTALLDIR.'/lib/noticelist.php';
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/ * @link http://status.net/
*/ */
class ConversationAction extends Action class ConversationAction extends Action
{ {
var $id = null; var $id = null;
@ -58,7 +57,6 @@ class ConversationAction extends Action
* *
* @return boolean false if id not passed in * @return boolean false if id not passed in
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
@ -81,7 +79,6 @@ class ConversationAction extends Action
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -93,10 +90,10 @@ class ConversationAction extends Action
* *
* @return string page title * @return string page title
*/ */
function title() function title()
{ {
return _("Conversation"); // TRANS: Title for page with a conversion (multiple notices in context).
return _('Conversation');
} }
/** /**
@ -107,7 +104,6 @@ class ConversationAction extends Action
* *
* @return void * @return void
*/ */
function showContent() function showContent()
{ {
$notices = Notice::conversationStream($this->id, null, null); $notices = Notice::conversationStream($this->id, null, null);
@ -134,7 +130,6 @@ class ConversationAction extends Action
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/ * @link http://status.net/
*/ */
class ConversationTree extends NoticeList class ConversationTree extends NoticeList
{ {
var $tree = null; var $tree = null;
@ -145,12 +140,12 @@ class ConversationTree extends NoticeList
* *
* @return void * @return void
*/ */
function show() function show()
{ {
$cnt = $this->_buildTree(); $cnt = $this->_buildTree();
$this->out->elementStart('div', array('id' =>'notices_primary')); $this->out->elementStart('div', array('id' =>'notices_primary'));
// TRANS: Header on conversation page. Hidden by default (h2).
$this->out->element('h2', null, _('Notices')); $this->out->element('h2', null, _('Notices'));
$this->out->elementStart('ol', array('class' => 'notices xoxo')); $this->out->elementStart('ol', array('class' => 'notices xoxo'));
@ -200,7 +195,6 @@ class ConversationTree extends NoticeList
* *
* @return void * @return void
*/ */
function showNoticePlus($id) function showNoticePlus($id)
{ {
$notice = $this->table[$id]; $notice = $this->table[$id];
@ -237,7 +231,6 @@ class ConversationTree extends NoticeList
* *
* @return NoticeListItem a list item to show * @return NoticeListItem a list item to show
*/ */
function newListItem($notice) function newListItem($notice)
{ {
return new ConversationTreeItem($notice, $this->out); return new ConversationTreeItem($notice, $this->out);
@ -255,7 +248,6 @@ class ConversationTree extends NoticeList
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/ * @link http://status.net/
*/ */
class ConversationTreeItem extends NoticeListItem class ConversationTreeItem extends NoticeListItem
{ {
/** /**
@ -266,7 +258,6 @@ class ConversationTreeItem extends NoticeListItem
* *
* @return void * @return void
*/ */
function showStart() function showStart()
{ {
return; return;
@ -280,7 +271,6 @@ class ConversationTreeItem extends NoticeListItem
* *
* @return void * @return void
*/ */
function showEnd() function showEnd()
{ {
return; return;
@ -293,7 +283,6 @@ class ConversationTreeItem extends NoticeListItem
* *
* @return void * @return void
*/ */
function showContext() function showContext()
{ {
return; return;

View File

@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/ * @link http://status.net/
*/ */
class DeleteapplicationAction extends Action class DeleteapplicationAction extends Action
{ {
var $app = null; var $app = null;
@ -52,7 +51,6 @@ class DeleteapplicationAction extends Action
* *
* @return boolean success flag * @return boolean success flag
*/ */
function prepare($args) function prepare($args)
{ {
if (!parent::prepare($args)) { if (!parent::prepare($args)) {
@ -60,6 +58,7 @@ class DeleteapplicationAction extends Action
} }
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Client error displayed trying to delete an application while not logged in.
$this->clientError(_('You must be logged in to delete an application.')); $this->clientError(_('You must be logged in to delete an application.'));
return false; return false;
} }
@ -68,6 +67,7 @@ class DeleteapplicationAction extends Action
$this->app = Oauth_application::staticGet('id', $id); $this->app = Oauth_application::staticGet('id', $id);
if (empty($this->app)) { if (empty($this->app)) {
// TRANS: Client error displayed trying to delete an application that does not exist.
$this->clientError(_('Application not found.')); $this->clientError(_('Application not found.'));
return false; return false;
} }
@ -75,6 +75,7 @@ class DeleteapplicationAction extends Action
$cur = common_current_user(); $cur = common_current_user();
if ($cur->id != $this->app->owner) { if ($cur->id != $this->app->owner) {
// TRANS: Client error displayed trying to delete an application the current user does not own.
$this->clientError(_('You are not the owner of this application.'), 401); $this->clientError(_('You are not the owner of this application.'), 401);
return false; return false;
} }
@ -91,7 +92,6 @@ class DeleteapplicationAction extends Action
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
@ -120,6 +120,7 @@ class DeleteapplicationAction extends Action
} }
function title() { function title() {
// TRANS: Title for delete application page.
return _('Delete application'); return _('Delete application');
} }
@ -144,8 +145,10 @@ class DeleteapplicationAction extends Action
array('id' => $this->app->id)))); array('id' => $this->app->id))));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
// TRANS: Fieldset legend on delete application page.
$this->element('legend', _('Delete application')); $this->element('legend', _('Delete application'));
$this->element('p', null, $this->element('p', null,
// TRANS: Confirmation text on delete application page.
_('Are you sure you want to delete this application? '. _('Are you sure you want to delete this application? '.
'This will clear all data about the application from the '. 'This will clear all data about the application from the '.
'database, including all existing user connections.')); 'database, including all existing user connections.'));
@ -171,10 +174,8 @@ class DeleteapplicationAction extends Action
* *
* @return void * @return void
*/ */
function handlePost() function handlePost()
{ {
$this->app->delete(); $this->app->delete();
} }
} }

235
actions/deletegroup.php Normal file
View File

@ -0,0 +1,235 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Delete 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 Group
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Brion Vibber <brion@status.net>
* @copyright 2008-2010 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 group
*
* This is the action for deleting a group.
*
* @category Group
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Brion Vibber <brion@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/
* @fixme merge more of this code with related variants
*/
class DeletegroupAction extends RedirectingAction
{
var $group = null;
/**
* Prepare to run
*
* @fixme merge common setup code with other group actions
* @fixme allow group admins to delete their own groups
*/
function prepare($args)
{
parent::prepare($args);
if (!common_logged_in()) {
// TRANS: Client error when trying to delete group while not logged in.
$this->clientError(_('You must be logged in to delete a group.'));
return false;
}
$nickname_arg = $this->trimmed('nickname');
$id = intval($this->arg('id'));
if ($id) {
$this->group = User_group::staticGet('id', $id);
} else if ($nickname_arg) {
$nickname = common_canonical_nickname($nickname_arg);
// Permanent redirect on non-canonical nickname
if ($nickname_arg != $nickname) {
$args = array('nickname' => $nickname);
common_redirect(common_local_url('leavegroup', $args), 301);
return false;
}
$local = Local_group::staticGet('nickname', $nickname);
if (!$local) {
// TRANS: Client error when trying to delete a non-local group.
$this->clientError(_('No such group.'), 404);
return false;
}
$this->group = User_group::staticGet('id', $local->group_id);
} else {
// TRANS: Client error when trying to delete a group without providing a nickname or ID for the group.
$this->clientError(_('No nickname or ID.'), 404);
return false;
}
if (!$this->group) {
// TRANS: Client error when trying to delete a non-existing group.
$this->clientError(_('No such group.'), 404);
return false;
}
$cur = common_current_user();
if (!$cur->hasRight(Right::DELETEGROUP)) {
// TRANS: Client error when trying to delete a group without having the rights to delete it.
$this->clientError(_('You are not allowed to delete this group.'), 403);
return false;
}
return true;
}
/**
* Handle the request
*
* On POST, delete the group.
*
* @param array $args unused
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($this->arg('no')) {
$this->returnToPrevious();
return;
} elseif ($this->arg('yes')) {
$this->handlePost();
return;
}
}
$this->showPage();
}
function handlePost()
{
$cur = common_current_user();
try {
if (Event::handle('StartDeleteGroup', array($this->group))) {
$this->group->delete();
Event::handle('EndDeleteGroup', array($this->group));
}
} catch (Exception $e) {
// TRANS: Server error displayed if a group could not be deleted.
// TRANS: %s is the name of the group that could not be deleted.
$this->serverError(sprintf(_('Could not delete group %s.'),
$this->group->nickname));
}
if ($this->boolean('ajax')) {
$this->startHTML('text/xml;charset=utf-8');
$this->elementStart('head');
// TRANS: Message given after deleting a group.
// TRANS: %s is the deleted group's name.
$this->element('title', null, sprintf(_('Deleted group %s'),
$this->group->nickname));
$this->elementEnd('head');
$this->elementStart('body');
// @fixme add a sensible AJAX response form!
$this->elementEnd('body');
$this->elementEnd('html');
} else {
// @fixme if we could direct to the page on which this group
// would have shown... that would be awesome
common_redirect(common_local_url('groups'),
303);
}
}
function title() {
// TRANS: Title of delete group page.
return _('Delete group');
}
function showContent() {
$this->areYouSureForm();
}
/**
* Confirm with user.
* Ripped from DeleteuserAction
*
* Shows a confirmation form.
*
* @fixme refactor common code for things like this
* @return void
*/
function areYouSureForm()
{
$id = $this->group->id;
$this->elementStart('form', array('id' => 'deletegroup-' . $id,
'method' => 'post',
'class' => 'form_settings form_entity_block',
'action' => common_local_url('deletegroup', array('id' => $this->group->id))));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
// TRANS: Form legend for deleting a group.
$this->element('legend', _('Delete group'));
if (Event::handle('StartDeleteGroupForm', array($this, $this->group))) {
$this->element('p', null,
// TRANS: Warning in form for deleleting a group.
_('Are you sure you want to delete this group? '.
'This will clear all data about the group from the '.
'database, without a backup. ' .
'Public posts to this group will still appear in ' .
'individual timelines.'));
foreach ($this->args as $k => $v) {
if (substr($k, 0, 9) == 'returnto-') {
$this->hidden($k, $v);
}
}
Event::handle('EndDeleteGroupForm', array($this, $this->group));
}
$this->submit('form_action-no',
// TRANS: Button label on the delete group form.
_m('BUTTON','No'),
'submit form_action-primary',
'no',
// TRANS: Submit button title for 'No' when deleting a group.
_('Do not delete this group'));
$this->submit('form_action-yes',
// TRANS: Button label on the delete group form.
_m('BUTTON','Yes'),
'submit form_action-secondary',
'yes',
// TRANS: Submit button title for 'Yes' when deleting a group.
_('Delete this group'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}
}

View File

@ -32,6 +32,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1); exit(1);
} }
// @todo FIXME: documentation needed.
class DeletenoticeAction extends Action class DeletenoticeAction extends Action
{ {
var $error = null; var $error = null;
@ -45,10 +46,18 @@ class DeletenoticeAction extends Action
parent::prepare($args); parent::prepare($args);
$this->user = common_current_user(); $this->user = common_current_user();
if (!$this->user) {
// TRANS: Error message displayed trying to delete a notice while not logged in.
common_user_error(_('Not logged in.'));
exit;
}
$notice_id = $this->trimmed('notice'); $notice_id = $this->trimmed('notice');
$this->notice = Notice::staticGet($notice_id); $this->notice = Notice::staticGet($notice_id);
if (!$this->notice) { if (!$this->notice) {
// TRANS: Error message displayed trying to delete a non-existing notice.
common_user_error(_('No such notice.')); common_user_error(_('No such notice.'));
exit; exit;
} }
@ -63,11 +72,9 @@ class DeletenoticeAction extends Action
{ {
parent::handle($args); parent::handle($args);
if (!common_logged_in()) { if ($this->notice->profile_id != $this->user_profile->id &&
common_user_error(_('Not logged in.'));
exit;
} else if ($this->notice->profile_id != $this->user_profile->id &&
!$this->user->hasRight(Right::DELETEOTHERSNOTICE)) { !$this->user->hasRight(Right::DELETEOTHERSNOTICE)) {
// TRANS: Error message displayed trying to delete a notice that was not made by the current user.
common_user_error(_('Can\'t delete this notice.')); common_user_error(_('Can\'t delete this notice.'));
exit; exit;
} }
@ -87,7 +94,6 @@ class DeletenoticeAction extends Action
* *
* @return void * @return void
*/ */
function showPageNotice() function showPageNotice()
{ {
$instr = $this->getInstructions(); $instr = $this->getInstructions();
@ -100,12 +106,14 @@ class DeletenoticeAction extends Action
function getInstructions() function getInstructions()
{ {
// TRANS: Instructions for deleting a notice.
return _('You are about to permanently delete a notice. ' . return _('You are about to permanently delete a notice. ' .
'Once this is done, it cannot be undone.'); 'Once this is done, it cannot be undone.');
} }
function title() function title()
{ {
// TRANS: Page title when deleting a notice.
return _('Delete notice'); return _('Delete notice');
} }
@ -118,7 +126,6 @@ class DeletenoticeAction extends Action
* *
* @return void * @return void
*/ */
function showForm($error = null) function showForm($error = null)
{ {
$this->error = $error; $this->error = $error;
@ -130,7 +137,6 @@ class DeletenoticeAction extends Action
* *
* @return void * @return void
*/ */
function showContent() function showContent()
{ {
$this->elementStart('form', array('id' => 'form_notice_delete', $this->elementStart('form', array('id' => 'form_notice_delete',
@ -138,9 +144,11 @@ class DeletenoticeAction extends Action
'method' => 'post', 'method' => 'post',
'action' => common_local_url('deletenotice'))); 'action' => common_local_url('deletenotice')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
// TRANS: Fieldset legend for the delete notice form.
$this->element('legend', null, _('Delete notice')); $this->element('legend', null, _('Delete notice'));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->hidden('notice', $this->trimmed('notice')); $this->hidden('notice', $this->trimmed('notice'));
// TRANS: Message for the delete notice form.
$this->element('p', null, _('Are you sure you want to delete this notice?')); $this->element('p', null, _('Are you sure you want to delete this notice?'));
$this->submit('form_action-no', $this->submit('form_action-no',
// TRANS: Button label on the delete notice form. // TRANS: Button label on the delete notice form.
@ -172,7 +180,10 @@ class DeletenoticeAction extends Action
} }
if ($this->arg('yes')) { if ($this->arg('yes')) {
$this->notice->delete(); if (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) {
$this->notice->delete();
Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
}
} }
$url = common_get_returnto(); $url = common_get_returnto();

View File

@ -71,7 +71,7 @@ class DesignadminpanelAction extends AdminPanelAction
function getInstructions() function getInstructions()
{ {
return _('Design settings for this StatusNet site.'); return _('Design settings for this StatusNet site');
} }
/** /**
@ -120,8 +120,11 @@ class DesignadminpanelAction extends AdminPanelAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
@ -140,7 +143,7 @@ class DesignadminpanelAction extends AdminPanelAction
$themeChanged = ($this->trimmed('theme') != $oldtheme); $themeChanged = ($this->trimmed('theme') != $oldtheme);
} }
static $settings = array('theme', 'logo'); static $settings = array('theme', 'logo', 'ssllogo');
$values = array(); $values = array();
@ -154,9 +157,22 @@ class DesignadminpanelAction extends AdminPanelAction
$config->query('BEGIN'); $config->query('BEGIN');
// Only update colors if the theme has not changed. if ($themeChanged) {
// If the theme has changed, reset custom colors and let them pick
// up the new theme's defaults.
$colors = array('background', 'content', 'sidebar', 'text', 'link');
foreach ($colors as $colorKey) {
// Clear from global config so we see defaults on this page...
$GLOBALS['config']['design'][$colorKey . 'color'] = false;
if (!$themeChanged) { // And remove old settings from DB...
$this->deleteSetting('design', $colorKey . 'color');
}
} else {
// Only save colors from the form if the theme has not changed.
//
// @fixme a future more ajaxy form should allow theme switch
// and color customization in one step.
$bgcolor = new WebColor($this->trimmed('design_background')); $bgcolor = new WebColor($this->trimmed('design_background'));
$ccolor = new WebColor($this->trimmed('design_content')); $ccolor = new WebColor($this->trimmed('design_content'));
@ -217,6 +233,7 @@ class DesignadminpanelAction extends AdminPanelAction
function restoreDefaults() function restoreDefaults()
{ {
$this->deleteSetting('site', 'logo'); $this->deleteSetting('site', 'logo');
$this->deleteSetting('site', 'ssllogo');
$this->deleteSetting('site', 'theme'); $this->deleteSetting('site', 'theme');
$settings = array( $settings = array(
@ -244,8 +261,8 @@ class DesignadminpanelAction extends AdminPanelAction
function saveBackgroundImage() function saveBackgroundImage()
{ {
$filename = null; $filename = null;
if (isset($_FILES['design_background-image_file']['error']) &&
if ($_FILES['design_background-image_file']['error'] == $_FILES['design_background-image_file']['error'] ==
UPLOAD_ERR_OK) { UPLOAD_ERR_OK) {
$filepath = null; $filepath = null;
@ -318,6 +335,11 @@ class DesignadminpanelAction extends AdminPanelAction
$this->clientError(_('Invalid logo URL.')); $this->clientError(_('Invalid logo URL.'));
} }
if (!empty($values['ssllogo']) &&
!Validate::uri($values['ssllogo'], array('allowed_schemes' => array('https')))) {
$this->clientError(_('Invalid SSL logo URL.'));
}
if (!in_array($values['theme'], Theme::listAvailable())) { if (!in_array($values['theme'], Theme::listAvailable())) {
$this->clientError(sprintf(_("Theme not available: %s."), $values['theme'])); $this->clientError(sprintf(_("Theme not available: %s."), $values['theme']));
} }
@ -431,6 +453,10 @@ class DesignAdminPanelForm extends AdminForm
$this->input('logo', _('Site logo'), 'Logo for the site (full URL)'); $this->input('logo', _('Site logo'), 'Logo for the site (full URL)');
$this->unli(); $this->unli();
$this->li();
$this->input('ssllogo', _('SSL logo'), 'Logo to show on SSL pages');
$this->unli();
$this->out->elementEnd('ul'); $this->out->elementEnd('ul');
$this->out->elementEnd('fieldset'); $this->out->elementEnd('fieldset');

View File

@ -42,7 +42,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class EditApplicationAction extends OwnerDesignAction class EditApplicationAction extends OwnerDesignAction
{ {
var $msg = null; var $msg = null;
@ -51,18 +50,19 @@ class EditApplicationAction extends OwnerDesignAction
function title() function title()
{ {
return _('Edit Application'); // TRANS: Title for "Edit application" form.
return _('Edit application');
} }
/** /**
* Prepare to run * Prepare to run
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Client error displayed trying to edit an application while not logged in.
$this->clientError(_('You must be logged in to edit an application.')); $this->clientError(_('You must be logged in to edit an application.'));
return false; return false;
} }
@ -74,10 +74,12 @@ class EditApplicationAction extends OwnerDesignAction
$cur = common_current_user(); $cur = common_current_user();
if ($cur->id != $this->owner->id) { if ($cur->id != $this->owner->id) {
// TRANS: Client error displayed trying to edit an application while not being its owner.
$this->clientError(_('You are not the owner of this application.'), 401); $this->clientError(_('You are not the owner of this application.'), 401);
} }
if (!$this->app) { if (!$this->app) {
// TRANS: Client error displayed trying to edit an application that does not exist.
$this->clientError(_('No such application.')); $this->clientError(_('No such application.'));
return false; return false;
} }
@ -94,7 +96,6 @@ class EditApplicationAction extends OwnerDesignAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -115,8 +116,11 @@ class EditApplicationAction extends OwnerDesignAction
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
@ -136,6 +140,7 @@ class EditApplicationAction extends OwnerDesignAction
} elseif ($this->arg('save')) { } elseif ($this->arg('save')) {
$this->trySave(); $this->trySave();
} else { } else {
// TRANS: Client error displayed submitting invalid form data for edit application.
$this->clientError(_('Unexpected form submission.')); $this->clientError(_('Unexpected form submission.'));
} }
} }
@ -158,6 +163,7 @@ class EditApplicationAction extends OwnerDesignAction
$this->element('p', 'error', $this->msg); $this->element('p', 'error', $this->msg);
} else { } else {
$this->element('p', 'instructions', $this->element('p', 'instructions',
// TRANS: Instructions for "Edit application" form.
_('Use this form to edit your application.')); _('Use this form to edit your application.'));
} }
} }
@ -174,36 +180,47 @@ class EditApplicationAction extends OwnerDesignAction
$access_type = $this->arg('default_access_type'); $access_type = $this->arg('default_access_type');
if (empty($name)) { if (empty($name)) {
// TRANS: Validation error shown when not providing a name in the "Edit application" form.
$this->showForm(_('Name is required.')); $this->showForm(_('Name is required.'));
return; return;
} elseif (mb_strlen($name) > 255) { } elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).')); // TRANS: Validation error shown when providing too long a name in the "Edit application" form.
$this->showForm(_('Name is too long (maximum 255 characters).'));
return; return;
} else if ($this->nameExists($name)) { } else if ($this->nameExists($name)) {
// TRANS: Validation error shown when providing a name for an application that already exists in the "Edit application" form.
$this->showForm(_('Name already in use. Try another one.')); $this->showForm(_('Name already in use. Try another one.'));
return; return;
} elseif (empty($description)) { } elseif (empty($description)) {
// TRANS: Validation error shown when not providing a description in the "Edit application" form.
$this->showForm(_('Description is required.')); $this->showForm(_('Description is required.'));
return; return;
} elseif (Oauth_application::descriptionTooLong($description)) { } elseif (Oauth_application::descriptionTooLong($description)) {
$this->showForm(sprintf( $this->showForm(sprintf(
_('Description is too long (max %d chars).'), // TRANS: Validation error shown when providing too long a description in the "Edit application" form.
Oauth_application::maxDescription())); _m('Description is too long (maximum %d character).',
'Description is too long (maximum %d characters).',
Oauth_application::maxDesc()),
Oauth_application::maxDesc()));
return; return;
} elseif (mb_strlen($source_url) > 255) { } elseif (mb_strlen($source_url) > 255) {
// TRANS: Validation error shown when providing too long a source URL in the "Edit application" form.
$this->showForm(_('Source URL is too long.')); $this->showForm(_('Source URL is too long.'));
return; return;
} elseif ((mb_strlen($source_url) > 0) } elseif ((mb_strlen($source_url) > 0)
&& !Validate::uri($source_url, && !Validate::uri($source_url,
array('allowed_schemes' => array('http', 'https')))) array('allowed_schemes' => array('http', 'https'))))
{ {
// TRANS: Validation error shown when providing an invalid source URL in the "Edit application" form.
$this->showForm(_('Source URL is not valid.')); $this->showForm(_('Source URL is not valid.'));
return; return;
} elseif (empty($organization)) { } elseif (empty($organization)) {
// TRANS: Validation error shown when not providing an organisation in the "Edit application" form.
$this->showForm(_('Organization is required.')); $this->showForm(_('Organization is required.'));
return; return;
} elseif (mb_strlen($organization) > 255) { } elseif (mb_strlen($organization) > 255) {
$this->showForm(_('Organization is too long (max 255 chars).')); // TRANS: Validation error shown when providing too long an arganisation name in the "Edit application" form.
$this->showForm(_('Organization is too long (maximum 255 characters).'));
return; return;
} elseif (empty($homepage)) { } elseif (empty($homepage)) {
$this->showForm(_('Organization homepage is required.')); $this->showForm(_('Organization homepage is required.'));
@ -212,9 +229,11 @@ class EditApplicationAction extends OwnerDesignAction
&& !Validate::uri($homepage, && !Validate::uri($homepage,
array('allowed_schemes' => array('http', 'https')))) array('allowed_schemes' => array('http', 'https'))))
{ {
// TRANS: Validation error shown when providing an invalid homepage URL in the "Edit application" form.
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} elseif (mb_strlen($callback_url) > 255) { } elseif (mb_strlen($callback_url) > 255) {
// TRANS: Validation error shown when providing too long a callback URL in the "Edit application" form.
$this->showForm(_('Callback is too long.')); $this->showForm(_('Callback is too long.'));
return; return;
} elseif (mb_strlen($callback_url) > 0 } elseif (mb_strlen($callback_url) > 0
@ -222,6 +241,7 @@ class EditApplicationAction extends OwnerDesignAction
array('allowed_schemes' => array('http', 'https')) array('allowed_schemes' => array('http', 'https'))
)) ))
{ {
// TRANS: Validation error shown when providing an invalid callback URL in the "Edit application" form.
$this->showForm(_('Callback URL is not valid.')); $this->showForm(_('Callback URL is not valid.'));
return; return;
} }
@ -253,8 +273,12 @@ class EditApplicationAction extends OwnerDesignAction
$result = $this->app->update($orig); $result = $this->app->update($orig);
if (!$result) { // Note: 0 means no rows changed, which can happen if the only
// thing we changed was the icon, since it's not altered until
// the next step.
if ($result === false) {
common_log_db_error($this->app, 'UPDATE', __FILE__); common_log_db_error($this->app, 'UPDATE', __FILE__);
// TRANS: Server error occuring when an application could not be updated from the "Edit application" form.
$this->serverError(_('Could not update application.')); $this->serverError(_('Could not update application.'));
} }
@ -273,7 +297,6 @@ class EditApplicationAction extends OwnerDesignAction
* *
* @return boolean true if the name already exists * @return boolean true if the name already exists
*/ */
function nameExists($name) function nameExists($name)
{ {
$newapp = Oauth_application::staticGet('name', $name); $newapp = Oauth_application::staticGet('name', $name);
@ -283,6 +306,4 @@ class EditApplicationAction extends OwnerDesignAction
return $newapp->id != $this->app->id; return $newapp->id != $this->app->id;
} }
} }
} }

View File

@ -45,14 +45,13 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class EditgroupAction extends GroupDesignAction class EditgroupAction extends GroupDesignAction
{ {
var $msg; var $msg;
function title() function title()
{ {
// TRANS: Title for form to edit a group. %s is a group nickname.
return sprintf(_('Edit %s group'), $this->group->nickname); return sprintf(_('Edit %s group'), $this->group->nickname);
} }
@ -65,6 +64,7 @@ class EditgroupAction extends GroupDesignAction
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Client error displayed trying to edit a group while not logged in.
$this->clientError(_('You must be logged in to create a group.')); $this->clientError(_('You must be logged in to create a group.'));
return false; return false;
} }
@ -81,6 +81,7 @@ class EditgroupAction extends GroupDesignAction
} }
if (!$nickname) { if (!$nickname) {
// TRANS: Client error displayed trying to edit a group while not proving a nickname for the group to edit.
$this->clientError(_('No nickname.'), 404); $this->clientError(_('No nickname.'), 404);
return false; return false;
} }
@ -97,6 +98,7 @@ class EditgroupAction extends GroupDesignAction
} }
if (!$this->group) { if (!$this->group) {
// TRANS: Client error displayed trying to edit a non-existing group.
$this->clientError(_('No such group.'), 404); $this->clientError(_('No such group.'), 404);
return false; return false;
} }
@ -104,6 +106,7 @@ class EditgroupAction extends GroupDesignAction
$cur = common_current_user(); $cur = common_current_user();
if (!$cur->isAdmin($this->group)) { if (!$cur->isAdmin($this->group)) {
// TRANS: Client error displayed trying to edit a group while not being a group admin.
$this->clientError(_('You must be an admin to edit the group.'), 403); $this->clientError(_('You must be an admin to edit the group.'), 403);
return false; return false;
} }
@ -120,7 +123,6 @@ class EditgroupAction extends GroupDesignAction
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -155,6 +157,7 @@ class EditgroupAction extends GroupDesignAction
$this->element('p', 'error', $this->msg); $this->element('p', 'error', $this->msg);
} else { } else {
$this->element('p', 'instructions', $this->element('p', 'instructions',
// TRANS: Form instructions for group edit form.
_('Use this form to edit the group.')); _('Use this form to edit the group.'));
} }
} }
@ -169,43 +172,48 @@ class EditgroupAction extends GroupDesignAction
{ {
$cur = common_current_user(); $cur = common_current_user();
if (!$cur->isAdmin($this->group)) { if (!$cur->isAdmin($this->group)) {
// TRANS: Client error displayed trying to edit a group while not being a group admin.
$this->clientError(_('You must be an admin to edit the group.'), 403); $this->clientError(_('You must be an admin to edit the group.'), 403);
return; return;
} }
$nickname = common_canonical_nickname($this->trimmed('nickname')); $nickname = Nickname::normalize($this->trimmed('nickname'));
$fullname = $this->trimmed('fullname'); $fullname = $this->trimmed('fullname');
$homepage = $this->trimmed('homepage'); $homepage = $this->trimmed('homepage');
$description = $this->trimmed('description'); $description = $this->trimmed('description');
$location = $this->trimmed('location'); $location = $this->trimmed('location');
$aliasstring = $this->trimmed('aliases'); $aliasstring = $this->trimmed('aliases');
if (!Validate::string($nickname, array('min_length' => 1, if ($this->nicknameExists($nickname)) {
'max_length' => 64, // TRANS: Group edit form validation error.
'format' => NICKNAME_FMT))) {
$this->showForm(_('Nickname must have only lowercase letters '.
'and numbers and no spaces.'));
return;
} else if ($this->nicknameExists($nickname)) {
$this->showForm(_('Nickname already in use. Try another one.')); $this->showForm(_('Nickname already in use. Try another one.'));
return; return;
} else if (!User_group::allowedNickname($nickname)) { } else if (!User_group::allowedNickname($nickname)) {
// TRANS: Group edit form validation error.
$this->showForm(_('Not a valid nickname.')); $this->showForm(_('Not a valid nickname.'));
return; return;
} else if (!is_null($homepage) && (strlen($homepage) > 0) && } else if (!is_null($homepage) && (strlen($homepage) > 0) &&
!Validate::uri($homepage, !Validate::uri($homepage,
array('allowed_schemes' => array('allowed_schemes' =>
array('http', 'https')))) { array('http', 'https')))) {
// TRANS: Group edit form validation error.
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) { } else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).')); // TRANS: Group edit form validation error.
$this->showForm(_('Full name is too long (maximum 255 characters).'));
return; return;
} else if (User_group::descriptionTooLong($description)) { } else if (User_group::descriptionTooLong($description)) {
$this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription())); $this->showForm(sprintf(
// TRANS: Group edit form validation error.
_m('Description is too long (maximum %d character).',
'Description is too long (maximum %d characters).',
User_group::maxDescription()),
User_group::maxDescription()));
return; return;
} else if (!is_null($location) && mb_strlen($location) > 255) { } else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).')); // TRANS: Group edit form validation error.
$this->showForm(_('Location is too long (maximum 255 characters).'));
return; return;
} }
@ -216,25 +224,30 @@ class EditgroupAction extends GroupDesignAction
} }
if (count($aliases) > common_config('group', 'maxaliases')) { if (count($aliases) > common_config('group', 'maxaliases')) {
$this->showForm(sprintf(_('Too many aliases! Maximum %d.'), // TRANS: Group edit form validation error.
// TRANS: %d is the maximum number of allowed aliases.
$this->showForm(sprintf(_m('Too many aliases! Maximum %d allowed.',
'Too many aliases! Maximum %d allowed.',
common_config('group', 'maxaliases')),
common_config('group', 'maxaliases'))); common_config('group', 'maxaliases')));
return; return;
} }
foreach ($aliases as $alias) { foreach ($aliases as $alias) {
if (!Validate::string($alias, array('min_length' => 1, if (!Nickname::isValid($alias)) {
'max_length' => 64, // TRANS: Group edit form validation error.
'format' => NICKNAME_FMT))) {
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias)); $this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
return; return;
} }
if ($this->nicknameExists($alias)) { if ($this->nicknameExists($alias)) {
// TRANS: Group edit form validation error.
$this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'), $this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'),
$alias)); $alias));
return; return;
} }
// XXX assumes alphanum nicknames // XXX assumes alphanum nicknames
if (strcmp($alias, $nickname) == 0) { if (strcmp($alias, $nickname) == 0) {
// TRANS: Group edit form validation error.
$this->showForm(_('Alias can\'t be the same as nickname.')); $this->showForm(_('Alias can\'t be the same as nickname.'));
return; return;
} }
@ -255,12 +268,14 @@ class EditgroupAction extends GroupDesignAction
if (!$result) { if (!$result) {
common_log_db_error($this->group, 'UPDATE', __FILE__); common_log_db_error($this->group, 'UPDATE', __FILE__);
// TRANS: Server error displayed when editing a group fails.
$this->serverError(_('Could not update group.')); $this->serverError(_('Could not update group.'));
} }
$result = $this->group->setAliases($aliases); $result = $this->group->setAliases($aliases);
if (!$result) { if (!$result) {
// TRANS: Server error displayed when group aliases could not be added.
$this->serverError(_('Could not create aliases.')); $this->serverError(_('Could not create aliases.'));
} }
@ -277,6 +292,7 @@ class EditgroupAction extends GroupDesignAction
array('nickname' => $nickname)), array('nickname' => $nickname)),
303); 303);
} else { } else {
// TRANS: Group edit form success message.
$this->showForm(_('Options saved.')); $this->showForm(_('Options saved.'));
} }
} }
@ -300,4 +316,3 @@ class EditgroupAction extends GroupDesignAction
return false; return false;
} }
} }

View File

@ -79,6 +79,7 @@ class EmailsettingsAction extends AccountSettingsAction
function showScripts() function showScripts()
{ {
parent::showScripts(); parent::showScripts();
$this->script('emailsettings.js');
$this->autofocus('email'); $this->autofocus('email');
} }
@ -131,7 +132,11 @@ class EmailsettingsAction extends AccountSettingsAction
// TRANS: Field label for e-mail address input in e-mail settings form. // TRANS: Field label for e-mail address input in e-mail settings form.
$this->input('email', _('Email address'), $this->input('email', _('Email address'),
($this->arg('email')) ? $this->arg('email') : null, ($this->arg('email')) ? $this->arg('email') : null,
// TRANS: Instructions for e-mail address input form. // TRANS: Instructions for e-mail address input form. Do not translate
// TRANS: "example.org". It is one of the domain names reserved for
// TRANS: use in examples by http://www.rfc-editor.org/rfc/rfc2606.txt.
// TRANS: Any other domain may be owned by a legitimate person or
// TRANS: organization.
_('Email address, like "UserName@example.org"')); _('Email address, like "UserName@example.org"'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
@ -145,6 +150,26 @@ class EmailsettingsAction extends AccountSettingsAction
$this->elementStart('fieldset', array('id' => 'settings_email_incoming')); $this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
// TRANS: Form legend for incoming e-mail settings form. // TRANS: Form legend for incoming e-mail settings form.
$this->element('legend', null, _('Incoming email')); $this->element('legend', null, _('Incoming email'));
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
$this->checkbox('emailpost',
// TRANS: Checkbox label in e-mail preferences form.
_('I want to post notices by email.'),
$user->emailpost);
$this->elementEnd('li');
$this->elementEnd('ul');
// Our stylesheets make the form_data list items all floats, which
// creates lots of problems with trying to wrap divs around things.
// This should force a break before the next section, which needs
// to be separate so we can disable the things in it when the
// checkbox is off.
$this->elementStart('div', array('style' => 'clear: both'));
$this->elementEnd('div');
$this->elementStart('div', array('id' => 'emailincoming'));
if ($user->incomingemail) { if ($user->incomingemail) {
$this->elementStart('p'); $this->elementStart('p');
$this->element('span', 'address', $user->incomingemail); $this->element('span', 'address', $user->incomingemail);
@ -159,13 +184,22 @@ class EmailsettingsAction extends AccountSettingsAction
} }
$this->elementStart('p'); $this->elementStart('p');
$this->element('span', 'input_instructions', if ($user->incomingemail) {
// TRANS: Instructions for incoming e-mail address input form. // TRANS: Instructions for incoming e-mail address input form, when an address has already been assigned.
_('Make a new email address for posting to; '. $msg = _('Make a new email address for posting to; '.
'cancels the old one.')); 'cancels the old one.');
} else {
// TRANS: Instructions for incoming e-mail address input form.
$msg = _('To send notices via email, we need to create a unique email address for you on this server:');
}
$this->element('span', 'input_instructions', $msg);
$this->elementEnd('p'); $this->elementEnd('p');
// TRANS: Button label for adding an e-mail address to send notices from. // TRANS: Button label for adding an e-mail address to send notices from.
$this->submit('newincoming', _m('BUTTON','New')); $this->submit('newincoming', _m('BUTTON','New'));
$this->elementEnd('div'); // div#emailincoming
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
} }
@ -174,51 +208,47 @@ class EmailsettingsAction extends AccountSettingsAction
$this->element('legend', null, _('Email preferences')); $this->element('legend', null, _('Email preferences'));
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li');
$this->checkbox('emailnotifysub', if (Event::handle('StartEmailFormData', array($this))) {
// TRANS: Checkbox label in e-mail preferences form. $this->elementStart('li');
_('Send me notices of new subscriptions through email.'), $this->checkbox('emailnotifysub',
$user->emailnotifysub); // TRANS: Checkbox label in e-mail preferences form.
$this->elementEnd('li'); _('Send me notices of new subscriptions through email.'),
$this->elementStart('li'); $user->emailnotifysub);
$this->checkbox('emailnotifyfav', $this->elementEnd('li');
// TRANS: Checkbox label in e-mail preferences form. $this->elementStart('li');
_('Send me email when someone '. $this->checkbox('emailnotifyfav',
'adds my notice as a favorite.'), // TRANS: Checkbox label in e-mail preferences form.
$user->emailnotifyfav); _('Send me email when someone '.
$this->elementEnd('li'); 'adds my notice as a favorite.'),
$this->elementStart('li'); $user->emailnotifyfav);
$this->checkbox('emailnotifymsg', $this->elementEnd('li');
// TRANS: Checkbox label in e-mail preferences form. $this->elementStart('li');
_('Send me email when someone sends me a private message.'), $this->checkbox('emailnotifymsg',
$user->emailnotifymsg); // TRANS: Checkbox label in e-mail preferences form.
$this->elementEnd('li'); _('Send me email when someone sends me a private message.'),
$this->elementStart('li'); $user->emailnotifymsg);
$this->checkbox('emailnotifyattn', $this->elementEnd('li');
// TRANS: Checkbox label in e-mail preferences form. $this->elementStart('li');
_('Send me email when someone sends me an "@-reply".'), $this->checkbox('emailnotifyattn',
$user->emailnotifyattn); // TRANS: Checkbox label in e-mail preferences form.
$this->elementEnd('li'); _('Send me email when someone sends me an "@-reply".'),
$this->elementStart('li'); $user->emailnotifyattn);
$this->checkbox('emailnotifynudge', $this->elementEnd('li');
// TRANS: Checkbox label in e-mail preferences form. $this->elementStart('li');
_('Allow friends to nudge me and send me an email.'), $this->checkbox('emailnotifynudge',
$user->emailnotifynudge); // TRANS: Checkbox label in e-mail preferences form.
$this->elementEnd('li'); _('Allow friends to nudge me and send me an email.'),
if (common_config('emailpost', 'enabled')) { $user->emailnotifynudge);
$this->elementStart('li'); $this->elementEnd('li');
$this->checkbox('emailpost', $this->elementStart('li');
// TRANS: Checkbox label in e-mail preferences form. $this->checkbox('emailmicroid',
_('I want to post notices by email.'), // TRANS: Checkbox label in e-mail preferences form.
$user->emailpost); _('Publish a MicroID for my email address.'),
$this->elementEnd('li'); $user->emailmicroid);
} $this->elementEnd('li');
$this->elementStart('li'); Event::handle('EndEmailFormData', array($this));
$this->checkbox('emailmicroid', }
// TRANS: Checkbox label in e-mail preferences form.
_('Publish a MicroID for my email address.'),
$user->emailmicroid);
$this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Button label to save e-mail preferences. // TRANS: Button label to save e-mail preferences.
$this->submit('save', _m('BUTTON','Save')); $this->submit('save', _m('BUTTON','Save'));
@ -295,43 +325,48 @@ class EmailsettingsAction extends AccountSettingsAction
function savePreferences() function savePreferences()
{ {
$emailnotifysub = $this->boolean('emailnotifysub'); $user = common_current_user();
$emailnotifyfav = $this->boolean('emailnotifyfav');
$emailnotifymsg = $this->boolean('emailnotifymsg');
$emailnotifynudge = $this->boolean('emailnotifynudge');
$emailnotifyattn = $this->boolean('emailnotifyattn');
$emailmicroid = $this->boolean('emailmicroid');
$emailpost = $this->boolean('emailpost');
$user = common_current_user(); if (Event::handle('StartEmailSaveForm', array($this, &$user))) {
assert(!is_null($user)); // should already be checked $emailnotifysub = $this->boolean('emailnotifysub');
$emailnotifyfav = $this->boolean('emailnotifyfav');
$emailnotifymsg = $this->boolean('emailnotifymsg');
$emailnotifynudge = $this->boolean('emailnotifynudge');
$emailnotifyattn = $this->boolean('emailnotifyattn');
$emailmicroid = $this->boolean('emailmicroid');
$emailpost = $this->boolean('emailpost');
$user->query('BEGIN'); assert(!is_null($user)); // should already be checked
$original = clone($user); $user->query('BEGIN');
$user->emailnotifysub = $emailnotifysub; $original = clone($user);
$user->emailnotifyfav = $emailnotifyfav;
$user->emailnotifymsg = $emailnotifymsg;
$user->emailnotifynudge = $emailnotifynudge;
$user->emailnotifyattn = $emailnotifyattn;
$user->emailmicroid = $emailmicroid;
$user->emailpost = $emailpost;
$result = $user->update($original); $user->emailnotifysub = $emailnotifysub;
$user->emailnotifyfav = $emailnotifyfav;
$user->emailnotifymsg = $emailnotifymsg;
$user->emailnotifynudge = $emailnotifynudge;
$user->emailnotifyattn = $emailnotifyattn;
$user->emailmicroid = $emailmicroid;
$user->emailpost = $emailpost;
if ($result === false) { $result = $user->update($original);
common_log_db_error($user, 'UPDATE', __FILE__);
// TRANS: Server error thrown on database error updating e-mail preferences.
$this->serverError(_('Couldn\'t update user.'));
return;
}
$user->query('COMMIT'); if ($result === false) {
common_log_db_error($user, 'UPDATE', __FILE__);
// TRANS: Server error thrown on database error updating e-mail preferences.
$this->serverError(_('Couldn\'t update user.'));
return;
}
// TRANS: Confirmation message for successful e-mail preferences save. $user->query('COMMIT');
$this->showForm(_('Email preferences saved.'), true);
Event::handle('EndEmailSaveForm', array($this));
// TRANS: Confirmation message for successful e-mail preferences save.
$this->showForm(_('Email preferences saved.'), true);
}
} }
/** /**
@ -497,6 +532,7 @@ class EmailsettingsAction extends AccountSettingsAction
$orig = clone($user); $orig = clone($user);
$user->incomingemail = null; $user->incomingemail = null;
$user->emailpost = 0;
if (!$user->updateKeys($orig)) { if (!$user->updateKeys($orig)) {
common_log_db_error($user, 'UPDATE', __FILE__); common_log_db_error($user, 'UPDATE', __FILE__);
@ -521,6 +557,7 @@ class EmailsettingsAction extends AccountSettingsAction
$orig = clone($user); $orig = clone($user);
$user->incomingemail = mail_new_incoming_address(); $user->incomingemail = mail_new_incoming_address();
$user->emailpost = 1;
if (!$user->updateKeys($orig)) { if (!$user->updateKeys($orig)) {
common_log_db_error($user, 'UPDATE', __FILE__); common_log_db_error($user, 'UPDATE', __FILE__);

View File

@ -185,29 +185,11 @@ class FavoritedAction extends Action
function showContent() function showContent()
{ {
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff')); $pop = new Popularity();
$cutoff = sprintf("fave.modified > '%s'", $pop->offset = ($this->page - 1) * NOTICES_PER_PAGE;
common_sql_date(time() - common_config('popular', 'cutoff'))); $pop->limit = NOTICES_PER_PAGE;
$pop->expiry = 600;
$qry = 'SELECT notice.*, '. $notice = $pop->getNotices();
$weightexpr . ' as weight ' .
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
"WHERE $cutoff " .
'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
'ORDER BY weight DESC';
$offset = ($this->page - 1) * NOTICES_PER_PAGE;
$limit = NOTICES_PER_PAGE + 1;
if (common_config('db', 'type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$notice = Memcached_DataObject::cachedQuery('Notice',
$qry,
600);
$nl = new NoticeList($notice, $this); $nl = new NoticeList($notice, $this);

View File

@ -129,9 +129,9 @@ class GetfileAction extends Action
return null; return null;
} }
$cache = common_memcache(); $cache = Cache::instance();
if($cache) { if($cache) {
$key = common_cache_key('attachments:etag:' . $this->path); $key = Cache::key('attachments:etag:' . $this->path);
$etag = $cache->get($key); $etag = $cache->get($key);
if($etag === false) { if($etag === false) {
$etag = crc32(file_get_contents($this->path)); $etag = crc32(file_get_contents($this->path));

View File

@ -97,9 +97,13 @@ class GroupmembersAction extends GroupDesignAction
function title() function title()
{ {
if ($this->page == 1) { if ($this->page == 1) {
// TRANS: Title of the page showing group members.
// TRANS: %s is the name of the group.
return sprintf(_('%s group members'), return sprintf(_('%s group members'),
$this->group->nickname); $this->group->nickname);
} else { } else {
// TRANS: Title of the page showing group members.
// TRANS: %1$s is the name of the group, %2$d is the page number of the members list.
return sprintf(_('%1$s group members, page %2$d'), return sprintf(_('%1$s group members, page %2$d'),
$this->group->nickname, $this->group->nickname,
$this->page); $this->page);
@ -389,7 +393,14 @@ class GroupBlockForm extends Form
function formActions() function formActions()
{ {
$this->out->submit('submit', _('Block'), 'submit', null, _('Block this user')); $this->out->submit(
'submit',
// TRANS: Button text for the form that will block a user from a group.
_m('BUTTON','Block'),
'submit',
null,
// TRANS: Submit button title.
_m('TOOLTIP', 'Block this user'));
} }
} }
@ -516,6 +527,13 @@ class MakeAdminForm extends Form
function formActions() function formActions()
{ {
$this->out->submit('submit', _('Make Admin'), 'submit', null, _('Make this user an admin')); $this->out->submit(
'submit',
// TRANS: Button text for the form that will make a user administrator.
_m('BUTTON','Make Admin'),
'submit',
null,
// TRANS: Submit button title.
_m('TOOLTIP','Make this user an admin'));
} }
} }

View File

@ -32,7 +32,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
} }
/** /**
* Unlock a user from a group * Unblock a user from a group
* *
* @category Action * @category Action
* @package StatusNet * @package StatusNet
@ -40,7 +40,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/ * @link http://status.net/
*/ */
class GroupunblockAction extends Action class GroupunblockAction extends Action
{ {
var $profile = null; var $profile = null;
@ -53,11 +52,11 @@ class GroupunblockAction extends Action
* *
* @return boolean success flag * @return boolean success flag
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Client error displayed when trying to unblock a user from a group while not logged in.
$this->clientError(_('Not logged in.')); $this->clientError(_('Not logged in.'));
return false; return false;
} }
@ -68,11 +67,13 @@ class GroupunblockAction extends Action
} }
$id = $this->trimmed('unblockto'); $id = $this->trimmed('unblockto');
if (empty($id)) { if (empty($id)) {
// TRANS: Client error displayed when trying to unblock a user from a group without providing a profile.
$this->clientError(_('No profile specified.')); $this->clientError(_('No profile specified.'));
return false; return false;
} }
$this->profile = Profile::staticGet('id', $id); $this->profile = Profile::staticGet('id', $id);
if (empty($this->profile)) { if (empty($this->profile)) {
// TRANS: Client error displayed when trying to unblock a user from a group without providing an existing profile.
$this->clientError(_('No profile with that ID.')); $this->clientError(_('No profile with that ID.'));
return false; return false;
} }
@ -83,15 +84,18 @@ class GroupunblockAction extends Action
} }
$this->group = User_group::staticGet('id', $group_id); $this->group = User_group::staticGet('id', $group_id);
if (empty($this->group)) { if (empty($this->group)) {
// TRANS: Client error displayed when trying to unblock a user from a non-existing group.
$this->clientError(_('No such group.')); $this->clientError(_('No such group.'));
return false; return false;
} }
$user = common_current_user(); $user = common_current_user();
if (!$user->isAdmin($this->group)) { if (!$user->isAdmin($this->group)) {
// TRANS: Client error displayed when trying to unblock a user from a group without being an administrator for the group.
$this->clientError(_('Only an admin can unblock group members.'), 401); $this->clientError(_('Only an admin can unblock group members.'), 401);
return false; return false;
} }
if (!Group_block::isBlocked($this->group, $this->profile)) { if (!Group_block::isBlocked($this->group, $this->profile)) {
// TRANS: Client error displayed when trying to unblock a non-blocked user from a group.
$this->clientError(_('User is not blocked from group.')); $this->clientError(_('User is not blocked from group.'));
return false; return false;
} }
@ -105,7 +109,6 @@ class GroupunblockAction extends Action
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -119,12 +122,12 @@ class GroupunblockAction extends Action
* *
* @return void * @return void
*/ */
function unblockProfile() function unblockProfile()
{ {
$result = Group_block::unblockProfile($this->group, $this->profile); $result = Group_block::unblockProfile($this->group, $this->profile);
if (!$result) { if (!$result) {
// TRANS: Server error displayed when unblocking a user from a group fails because of an unknown error.
$this->serverError(_('Error removing the block.')); $this->serverError(_('Error removing the block.'));
return; return;
} }
@ -146,4 +149,3 @@ class GroupunblockAction extends Action
} }
} }
} }

View File

@ -18,28 +18,46 @@
*/ */
/** /**
* @package OStatusPlugin * @category Action
* @package StatusNet
* @maintainer James Walker <james@status.net> * @maintainer James Walker <james@status.net>
* @author Craig Andrews <candrews@integralblue.com>
*/ */
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } if (!defined('STATUSNET')) {
exit(1);
}
class HostMetaAction extends Action class HostMetaAction extends Action
{ {
/**
* Is read only?
*
* @return boolean true
*/
function isReadOnly()
{
return true;
}
function handle() function handle()
{ {
parent::handle(); parent::handle();
$domain = common_config('site', 'server'); $domain = common_config('site', 'server');
$url = common_local_url('userxrd');
$url.= '?uri={uri}';
$xrd = new XRD(); $xrd = new XRD();
$xrd->host = $domain; $xrd->host = $domain;
$xrd->links[] = array('rel' => Discovery::LRDD_REL,
'template' => $url, if(Event::handle('StartHostMetaLinks', array(&$xrd->links))) {
'title' => array('Resource Descriptor')); $url = common_local_url('userxrd');
$url.= '?uri={uri}';
$xrd->links[] = array('rel' => Discovery::LRDD_REL,
'template' => $url,
'title' => array('Resource Descriptor'));
Event::handle('EndHostMetaLinks', array(&$xrd->links));
}
header('Content-type: application/xrd+xml'); header('Content-type: application/xrd+xml');
print $xrd->toXML(); print $xrd->toXML();

View File

@ -133,7 +133,7 @@ class ImsettingsAction extends ConnectSettingsAction
'message with further instructions. '. 'message with further instructions. '.
'(Did you add %s to your buddy list?)'), '(Did you add %s to your buddy list?)'),
$transport_info['display'], $transport_info['display'],
$transport_info['daemon_screenname'])); $transport_info['daemonScreenname']));
$this->hidden('screenname', $confirm->address); $this->hidden('screenname', $confirm->address);
// TRANS: Button label to cancel an IM address confirmation procedure. // TRANS: Button label to cancel an IM address confirmation procedure.
$this->submit('cancel', _m('BUTTON','Cancel')); $this->submit('cancel', _m('BUTTON','Cancel'));

View File

@ -36,8 +36,11 @@ class InviteAction extends CurrentUserDesignAction
{ {
parent::handle($args); parent::handle($args);
if (!common_config('invite', 'enabled')) { if (!common_config('invite', 'enabled')) {
// TRANS: Client error displayed when trying to sent invites while they have been disabled.
$this->clientError(_('Invites have been disabled.')); $this->clientError(_('Invites have been disabled.'));
} else if (!common_logged_in()) { } else if (!common_logged_in()) {
// TRANS: Client error displayed when trying to sent invites while not logged in.
// TRANS: %s is the StatusNet site name.
$this->clientError(sprintf(_('You must be logged in to invite other users to use %s.'), $this->clientError(sprintf(_('You must be logged in to invite other users to use %s.'),
common_config('site', 'name'))); common_config('site', 'name')));
return; return;
@ -69,7 +72,9 @@ class InviteAction extends CurrentUserDesignAction
foreach ($addresses as $email) { foreach ($addresses as $email) {
$email = trim($email); $email = trim($email);
if (!Validate::email($email, common_config('email', 'check_domain'))) { if (!Validate::email($email, common_config('email', 'check_domain'))) {
$this->showForm(sprintf(_('Invalid email address: %s'), $email)); // TRANS: Form validation message when providing an e-mail address that does not validate.
// TRANS: %s is an invalid e-mail address.
$this->showForm(sprintf(_('Invalid email address: %s.'), $email));
return; return;
} }
} }
@ -107,8 +112,10 @@ class InviteAction extends CurrentUserDesignAction
function title() function title()
{ {
if ($this->mode == 'sent') { if ($this->mode == 'sent') {
return _('Invitation(s) sent'); // TRANS: Page title when invitations have been sent.
return _('Invitations sent');
} else { } else {
// TRANS: Page title when inviting potential users.
return _('Invite new users'); return _('Invite new users');
} }
} }
@ -125,28 +132,48 @@ class InviteAction extends CurrentUserDesignAction
function showInvitationSuccess() function showInvitationSuccess()
{ {
if ($this->already) { if ($this->already) {
$this->element('p', null, _('You are already subscribed to these users:')); // TRANS: Message displayed inviting users to use a StatusNet site while the inviting user
// TRANS: is already subscribed to one or more users with the given e-mail address(es).
// TRANS: Plural form is based on the number of reported already subscribed e-mail addresses.
// TRANS: Followed by a bullet list.
$this->element('p', null, _m('You are already subscribed to this user:',
'You are already subscribed to these users:',
count($this->already)));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($this->already as $other) { foreach ($this->already as $other) {
$this->element('li', null, sprintf(_('%1$s (%2$s)'), $other->nickname, $other->email)); // TRANS: Used as list item for already subscribed users (%1$s is nickname, %2$s is e-mail address).
$this->element('li', null, sprintf(_m('INVITE','%1$s (%2$s)'), $other->nickname, $other->email));
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
} }
if ($this->subbed) { if ($this->subbed) {
$this->element('p', null, _('These people are already users and you were automatically subscribed to them:')); // TRANS: Message displayed inviting users to use a StatusNet site while the invited user
// TRANS: already uses a this StatusNet site. Plural form is based on the number of
// TRANS: reported already present people. Followed by a bullet list.
$this->element('p', null, _m('This person is already a user and you were automatically subscribed:',
'These people are already users and you were automatically subscribed to them:',
count($this->subbed)));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($this->subbed as $other) { foreach ($this->subbed as $other) {
$this->element('li', null, sprintf(_('%1$s (%2$s)'), $other->nickname, $other->email)); // TRANS: Used as list item for already registered people (%1$s is nickname, %2$s is e-mail address).
$this->element('li', null, sprintf(_m('INVITE','%1$s (%2$s)'), $other->nickname, $other->email));
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
} }
if ($this->sent) { if ($this->sent) {
$this->element('p', null, _('Invitation(s) sent to the following people:')); // TRANS: Message displayed inviting users to use a StatusNet site. Plural form is
// TRANS: based on the number of invitations sent. Followed by a bullet list of
// TRANS: e-mail addresses to which invitations were sent.
$this->element('p', null, _m('Invitation sent to the following person:',
'Invitations sent to the following people:',
count($this->sent)));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($this->sent as $other) { foreach ($this->sent as $other) {
$this->element('li', null, $other); $this->element('li', null, $other);
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
// TRANS: Generic message displayed after sending out one or more invitations to
// TRANS: people to join a StatusNet site.
$this->element('p', null, _('You will be notified when your invitees accept the invitation and register on the site. Thanks for growing the community!')); $this->element('p', null, _('You will be notified when your invitees accept the invitation and register on the site. Thanks for growing the community!'));
} }
} }
@ -159,6 +186,7 @@ class InviteAction extends CurrentUserDesignAction
} else { } else {
$this->elementStart('div', 'instructions'); $this->elementStart('div', 'instructions');
$this->element('p', null, $this->element('p', null,
// TRANS: Form instructions.
_('Use this form to invite your friends and colleagues to use this service.')); _('Use this form to invite your friends and colleagues to use this service.'));
$this->elementEnd('div'); $this->elementEnd('div');
} }
@ -179,18 +207,23 @@ class InviteAction extends CurrentUserDesignAction
'class' => 'form_settings', 'class' => 'form_settings',
'action' => common_local_url('invite'))); 'action' => common_local_url('invite')));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
// TRANS: Form legend.
$this->element('legend', null, 'Send an invitation'); $this->element('legend', null, 'Send an invitation');
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->elementStart('ul', 'form_data'); $this->elementStart('ul', 'form_data');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label for a list of e-mail addresses.
$this->textarea('addresses', _('Email addresses'), $this->textarea('addresses', _('Email addresses'),
$this->trimmed('addresses'), $this->trimmed('addresses'),
// TRANS: Tooltip for field label for a list of e-mail addresses.
_('Addresses of friends to invite (one per line)')); _('Addresses of friends to invite (one per line)'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li'); $this->elementStart('li');
// TRANS: Field label for a personal message to send to invitees.
$this->textarea('personal', _('Personal message'), $this->textarea('personal', _('Personal message'),
$this->trimmed('personal'), $this->trimmed('personal'),
// TRANS: Tooltip for field label for a personal message to send to invitees.
_('Optionally add a personal message to the invitation.')); _('Optionally add a personal message to the invitation.'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
@ -224,10 +257,16 @@ class InviteAction extends CurrentUserDesignAction
$headers['From'] = mail_notify_from(); $headers['From'] = mail_notify_from();
$headers['To'] = trim($email); $headers['To'] = trim($email);
// TRANS: Subject for invitation email. Note that 'them' is correct as a gender-neutral singular 3rd-person pronoun in English. // TRANS: Subject for invitation email. Note that 'them' is correct as a gender-neutral
// TRANS: singular 3rd-person pronoun in English. %1$s is the inviting user, $2$s is
// TRANS: the StatusNet sitename.
$headers['Subject'] = sprintf(_('%1$s has invited you to join them on %2$s'), $bestname, $sitename); $headers['Subject'] = sprintf(_('%1$s has invited you to join them on %2$s'), $bestname, $sitename);
// TRANS: Body text for invitation email. Note that 'them' is correct as a gender-neutral singular 3rd-person pronoun in English. // TRANS: Body text for invitation email. Note that 'them' is correct as a gender-neutral
// TRANS: singular 3rd-person pronoun in English. %1$s is the inviting user, %2$s is the
// TRANS: StatusNet sitename, %3$s is the site URL, %4$s is the personal message from the
// TRANS: inviting user, %s%5 a link to the timeline for the inviting user, %s$6 is a link
// TRANS: to register with the StatusNet site.
$body = sprintf(_("%1\$s has invited you to join them on %2\$s (%3\$s).\n\n". $body = sprintf(_("%1\$s has invited you to join them on %2\$s (%3\$s).\n\n".
"%2\$s is a micro-blogging service that lets you keep up-to-date with people you know and people who interest you.\n\n". "%2\$s is a micro-blogging service that lets you keep up-to-date with people you know and people who interest you.\n\n".
"You can also share news about yourself, your thoughts, or your life online with people who know about you. ". "You can also share news about yourself, your thoughts, or your life online with people who know about you. ".

View File

@ -0,0 +1,322 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* License 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 Zach Copley <zach@status.net>
* @copyright 2010 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);
}
/**
* License settings
*
* @category Admin
* @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 LicenseadminpanelAction extends AdminPanelAction
{
/**
* Returns the page title
*
* @return string page title
*/
function title()
{
// TRANS: User admin panel title
return _m('TITLE', 'License');
}
/**
* Instructions for using this form.
*
* @return string instructions
*/
function getInstructions()
{
return _('License for this StatusNet site');
}
/**
* Show the site admin panel form
*
* @return void
*/
function showForm()
{
$form = new LicenseAdminPanelForm($this);
$form->show();
return;
}
/**
* Save settings from the form
*
* @return void
*/
function saveSettings()
{
static $settings = array(
'license' => array('type', 'owner', 'url', 'title', 'image')
);
$values = array();
foreach ($settings as $section => $parts) {
foreach ($parts as $setting) {
$values[$section][$setting] = $this->trimmed($setting);
}
}
// This throws an exception on validation errors
$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;
}
/**
* Validate License admin form values
*
* @param array &$values from the form
*
* @return nothing
*/
function validate(&$values)
{
// Validate license type (shouldn't have to do it, but just in case)
$types = array('private', 'allrightsreserved', 'cc');
if (!in_array($values['license']['type'], $types)) {
$this->clientError(_("Invalid license selection."));
}
// Make sure the user has set an owner if the site has a private
// license
if ($values['license']['type'] == 'allrightsreserved'
&& empty($values['license']['owner'])
) {
$this->clientError(
_("You must specify the owner of the content when using the All Rights Reserved license.")
);
}
// Make sure the license title is not too long
if (mb_strlen($values['license']['type']) > 255) {
$this->clientError(
_('Invalid license title. Maximum length is 255 characters.')
);
}
// make sure the license URL and license image URL are valid URLs
$options = array('allowed_schemes' => array('http', 'https'));
// URLs should be set for cc license
if ($values['license']['type'] == 'cc') {
if (!Validate::uri($values['license']['url'], $options)) {
$this->clientError(_("Invalid license URL."));
}
if (!Validate::uri($values['license']['image'], $options)) {
$this->clientError(_("Invalid license image URL."));
}
}
// can be either blank or a valid URL for private & allrightsreserved
if (!empty($values['license']['url'])) {
if (!Validate::uri($values['license']['url'], $options)) {
$this->clientError(_("License URL must be blank or a valid URL."));
}
}
// can be either blank or a valid URL for private & allrightsreserved
if (!empty($values['license']['image'])) {
if (!Validate::uri($values['license']['image'], $options)) {
$this->clientError(_("License image must be blank or valid URL."));
}
}
}
}
class LicenseAdminPanelForm extends AdminForm
{
/**
* ID of the form
*
* @return int ID of the form
*/
function id()
{
return 'licenseadminpanel';
}
/**
* 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('licenseadminpanel');
}
/**
* Data elements of the form
*
* @return void
*/
function formData()
{
$this->out->elementStart(
'fieldset', array('id' => 'settings_license-selection')
);
$this->out->element('legend', null, _('License selection'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$types = array(
'private' => _('Private'),
'allrightsreserved' => _('All Rights Reserved'),
'cc' => _('Creative Commons')
);
$this->out->dropdown(
'type',
_('Type'),
$types,
_('Select license'),
false,
$this->value('type', 'license')
);
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart(
'fieldset',
array('id' => 'settings_license-details')
);
$this->out->element('legend', null, _('License details'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input(
'owner',
_('Owner'),
_('Name of the owner of the site\'s content (if applicable).'),
'license'
);
$this->unli();
$this->li();
$this->input(
'title',
_('License Title'),
_('The title of the license.'),
'license'
);
$this->unli();
$this->li();
$this->input(
'url',
_('License URL'),
_('URL for more information about the license.'),
'license'
);
$this->unli();
$this->li();
$this->input(
'image', _('License Image URL'),
_('URL for an image to display with the license.'),
'license'
);
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
}
/**
* Action elements
*
* @return void
*/
function formActions()
{
$this->out->submit(
'submit', _('Save'), 'submit', null, _('Save license settings')
);
}
}

View File

@ -62,28 +62,6 @@ class LoginAction extends Action
return false; return false;
} }
/**
* Prepare page to run
*
*
* @param $args
* @return string title
*/
function prepare($args)
{
parent::prepare($args);
// @todo this check should really be in index.php for all sensitive actions
$ssl = common_config('site', 'ssl');
if (empty($_SERVER['HTTPS']) && ($ssl == 'always' || $ssl == 'sometimes')) {
common_redirect(common_local_url('login'));
// exit
}
return true;
}
/** /**
* Handle input, produce output * Handle input, produce output
* *
@ -118,27 +96,10 @@ class LoginAction extends Action
* @return void * @return void
*/ */
function checkLogin($user_id=null, $token=null) function checkLogin($user_id=null)
{ {
// XXX: login throttle // XXX: login throttle
// CSRF protection - token set in NoticeForm
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$st = common_session_token();
if (empty($token)) {
common_log(LOG_WARNING, 'No token provided by client.');
} else if (empty($st)) {
common_log(LOG_WARNING, 'No session token stored.');
} else {
common_log(LOG_WARNING, 'Token = ' . $token . ' and session token = ' . $st);
}
$this->clientError(_('There was a problem with your session token. '.
'Try again, please.'));
return;
}
$nickname = $this->trimmed('nickname'); $nickname = $this->trimmed('nickname');
$password = $this->arg('password'); $password = $this->arg('password');
@ -261,7 +222,6 @@ class LoginAction extends Action
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
$this->submit('submit', _('Login')); $this->submit('submit', _('Login'));
$this->hidden('token', common_session_token());
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
$this->elementStart('p'); $this->elementStart('p');

View File

@ -148,7 +148,7 @@ class MakeadminAction extends RedirectingAction
$this->group->getBestName()); $this->group->getBestName());
} }
$this->returnToArgs(); $this->returnToPrevious();
} }
/** /**

View File

@ -42,14 +42,14 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class NewApplicationAction extends OwnerDesignAction class NewApplicationAction extends OwnerDesignAction
{ {
var $msg; var $msg;
function title() function title()
{ {
return _('New Application'); // TRANS: This is the title of the form for adding a new application.
return _('New application');
} }
/** /**
@ -61,6 +61,7 @@ class NewApplicationAction extends OwnerDesignAction
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Client error displayed trying to add a new application while not logged in.
$this->clientError(_('You must be logged in to register an application.')); $this->clientError(_('You must be logged in to register an application.'));
return false; return false;
} }
@ -91,35 +92,38 @@ class NewApplicationAction extends OwnerDesignAction
function handlePost($args) function handlePost($args)
{ {
// Workaround for PHP returning empty $_POST and $_FILES when POST // Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini // length > post_max_size in php.ini
if (empty($_FILES) if (empty($_FILES)
&& empty($_POST) && empty($_POST)
&& ($_SERVER['CONTENT_LENGTH'] > 0) && ($_SERVER['CONTENT_LENGTH'] > 0)
) { ) {
$msg = _('The server was unable to handle that much POST ' . // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
'data (%s bytes) due to its current configuration.'); // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
intval($_SERVER['CONTENT_LENGTH']));
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH'])); $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return; return;
} }
// CSRF protection // CSRF protection
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->clientError(_('There was a problem with your session token.')); $this->clientError(_('There was a problem with your session token.'));
return; return;
} }
$cur = common_current_user(); $cur = common_current_user();
if ($this->arg('cancel')) { if ($this->arg('cancel')) {
common_redirect(common_local_url('oauthappssettings'), 303); common_redirect(common_local_url('oauthappssettings'), 303);
} elseif ($this->arg('save')) { } elseif ($this->arg('save')) {
$this->trySave(); $this->trySave();
} else { } else {
$this->clientError(_('Unexpected form submission.')); $this->clientError(_('Unexpected form submission.'));
} }
} }
function showForm($msg=null) function showForm($msg=null)
@ -162,15 +166,19 @@ class NewApplicationAction extends OwnerDesignAction
$this->showForm(_('Name already in use. Try another one.')); $this->showForm(_('Name already in use. Try another one.'));
return; return;
} elseif (mb_strlen($name) > 255) { } elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).')); $this->showForm(_('Name is too long (maximum 255 characters).'));
return; return;
} elseif (empty($description)) { } elseif (empty($description)) {
$this->showForm(_('Description is required.')); $this->showForm(_('Description is required.'));
return; return;
} elseif (Oauth_application::descriptionTooLong($description)) { } elseif (Oauth_application::descriptionTooLong($description)) {
$this->showForm(sprintf( $this->showForm(sprintf(
_('Description is too long (max %d chars).'), // TRANS: Form validation error in New application form.
Oauth_application::maxDescription())); // TRANS: %d is the maximum number of characters for the description.
_m('Description is too long (maximum %d character).',
'Description is too long (maximum %d characters).',
Oauth_application::maxDesc()),
Oauth_application::maxDesc()));
return; return;
} elseif (empty($source_url)) { } elseif (empty($source_url)) {
$this->showForm(_('Source URL is required.')); $this->showForm(_('Source URL is required.'));
@ -188,7 +196,7 @@ class NewApplicationAction extends OwnerDesignAction
$this->showForm(_('Organization is required.')); $this->showForm(_('Organization is required.'));
return; return;
} elseif (mb_strlen($organization) > 255) { } elseif (mb_strlen($organization) > 255) {
$this->showForm(_('Organization is too long (max 255 chars).')); $this->showForm(_('Organization is too long (maximum 255 characters).'));
return; return;
} elseif (empty($homepage)) { } elseif (empty($homepage)) {
$this->showForm(_('Organization homepage is required.')); $this->showForm(_('Organization homepage is required.'));

View File

@ -43,25 +43,25 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
class NewgroupAction extends Action class NewgroupAction extends Action
{ {
var $msg; var $msg;
function title() function title()
{ {
// TRANS: Title for form to create a group.
return _('New group'); return _('New group');
} }
/** /**
* Prepare to run * Prepare to run
*/ */
function prepare($args) function prepare($args)
{ {
parent::prepare($args); parent::prepare($args);
if (!common_logged_in()) { if (!common_logged_in()) {
// TRANS: Client error displayed trying to create a group while not logged in.
$this->clientError(_('You must be logged in to create a group.')); $this->clientError(_('You must be logged in to create a group.'));
return false; return false;
} }
@ -78,7 +78,6 @@ class NewgroupAction extends Action
* *
* @return void * @return void
*/ */
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -107,45 +106,54 @@ class NewgroupAction extends Action
$this->element('p', 'error', $this->msg); $this->element('p', 'error', $this->msg);
} else { } else {
$this->element('p', 'instructions', $this->element('p', 'instructions',
// TRANS: Form instructions for group create form.
_('Use this form to create a new group.')); _('Use this form to create a new group.'));
} }
} }
function trySave() function trySave()
{ {
$nickname = $this->trimmed('nickname'); try {
$nickname = Nickname::normalize($this->trimmed('nickname'));
} catch (NicknameException $e) {
$this->showForm($e->getMessage());
}
$fullname = $this->trimmed('fullname'); $fullname = $this->trimmed('fullname');
$homepage = $this->trimmed('homepage'); $homepage = $this->trimmed('homepage');
$description = $this->trimmed('description'); $description = $this->trimmed('description');
$location = $this->trimmed('location'); $location = $this->trimmed('location');
$aliasstring = $this->trimmed('aliases'); $aliasstring = $this->trimmed('aliases');
if (!Validate::string($nickname, array('min_length' => 1, if ($this->nicknameExists($nickname)) {
'max_length' => 64, // TRANS: Group create form validation error.
'format' => NICKNAME_FMT))) {
$this->showForm(_('Nickname must have only lowercase letters '.
'and numbers and no spaces.'));
return;
} else if ($this->nicknameExists($nickname)) {
$this->showForm(_('Nickname already in use. Try another one.')); $this->showForm(_('Nickname already in use. Try another one.'));
return; return;
} else if (!User_group::allowedNickname($nickname)) { } else if (!User_group::allowedNickname($nickname)) {
// TRANS: Group create form validation error.
$this->showForm(_('Not a valid nickname.')); $this->showForm(_('Not a valid nickname.'));
return; return;
} else if (!is_null($homepage) && (strlen($homepage) > 0) && } else if (!is_null($homepage) && (strlen($homepage) > 0) &&
!Validate::uri($homepage, !Validate::uri($homepage,
array('allowed_schemes' => array('allowed_schemes' =>
array('http', 'https')))) { array('http', 'https')))) {
// TRANS: Group create form validation error.
$this->showForm(_('Homepage is not a valid URL.')); $this->showForm(_('Homepage is not a valid URL.'));
return; return;
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) { } else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).')); // TRANS: Group create form validation error.
$this->showForm(_('Full name is too long (maximum 255 characters).'));
return; return;
} else if (User_group::descriptionTooLong($description)) { } else if (User_group::descriptionTooLong($description)) {
$this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription())); // TRANS: Group create form validation error.
// TRANS: %d is the maximum number of allowed characters.
$this->showForm(sprintf(_m('Description is too long (maximum %d character).',
'Description is too long (maximum %d characters).',
User_group::maxDescription()),
User_group::maxDescription()));
return; return;
} else if (!is_null($location) && mb_strlen($location) > 255) { } else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).')); // TRANS: Group create form validation error.
$this->showForm(_('Location is too long (maximum 255 characters).'));
return; return;
} }
@ -156,25 +164,30 @@ class NewgroupAction extends Action
} }
if (count($aliases) > common_config('group', 'maxaliases')) { if (count($aliases) > common_config('group', 'maxaliases')) {
$this->showForm(sprintf(_('Too many aliases! Maximum %d.'), // TRANS: Group create form validation error.
// TRANS: %d is the maximum number of allowed aliases.
$this->showForm(sprintf(_m('Too many aliases! Maximum %d allowed.',
'Too many aliases! Maximum %d allowed.',
common_config('group', 'maxaliases')),
common_config('group', 'maxaliases'))); common_config('group', 'maxaliases')));
return; return;
} }
foreach ($aliases as $alias) { foreach ($aliases as $alias) {
if (!Validate::string($alias, array('min_length' => 1, if (!Nickname::isValid($alias)) {
'max_length' => 64, // TRANS: Group create form validation error.
'format' => NICKNAME_FMT))) {
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias)); $this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
return; return;
} }
if ($this->nicknameExists($alias)) { if ($this->nicknameExists($alias)) {
// TRANS: Group create form validation error.
$this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'), $this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'),
$alias)); $alias));
return; return;
} }
// XXX assumes alphanum nicknames // XXX assumes alphanum nicknames
if (strcmp($alias, $nickname) == 0) { if (strcmp($alias, $nickname) == 0) {
// TRANS: Group create form validation error.
$this->showForm(_('Alias can\'t be the same as nickname.')); $this->showForm(_('Alias can\'t be the same as nickname.'));
return; return;
} }
@ -218,4 +231,3 @@ class NewgroupAction extends Action
return false; return false;
} }
} }

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