X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=lib%2Frouter.php;h=6533e24e57ff672b578e23057e9bfdda775e4f53;hb=b41c62a27c6ef8039fb0853a6cf0663de77b1e05;hp=7d675bb5471713dc7b0733672613593b810c5608;hpb=8161bf079758f5a07549081c24a5e68ec66113b6;p=quix0rs-gnu-social.git diff --git a/lib/router.php b/lib/router.php index 7d675bb547..6533e24e57 100644 --- a/lib/router.php +++ b/lib/router.php @@ -33,8 +33,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { require_once 'Net/URL/Mapper.php'; -class StatusNet_URL_Mapper extends Net_URL_Mapper { +class StatusNet_URL_Mapper extends Net_URL_Mapper +{ private static $_singleton = null; + private $_actionToPath = array(); private function __construct() { @@ -53,10 +55,47 @@ class StatusNet_URL_Mapper extends Net_URL_Mapper { $result = null; if (Event::handle('StartConnectPath', array(&$path, &$defaults, &$rules, &$result))) { $result = parent::connect($path, $defaults, $rules); + if (array_key_exists('action', $defaults)) { + $action = $defaults['action']; + } elseif (array_key_exists('action', $rules)) { + $action = $rules['action']; + } else { + $action = null; + } + $this->_mapAction($action, $result); Event::handle('EndConnectPath', array($path, $defaults, $rules, $result)); } return $result; } + + protected function _mapAction($action, $path) + { + if (!array_key_exists($action, $this->_actionToPath)) { + $this->_actionToPath[$action] = array(); + } + $this->_actionToPath[$action][] = $path; + return; + } + + public function generate($values = array(), $qstring = array(), $anchor = '') + { + if (!array_key_exists('action', $values)) { + return parent::generate($values, $qstring, $anchor); + } + + $action = $values['action']; + + if (!array_key_exists($action, $this->_actionToPath)) { + return parent::generate($values, $qstring, $anchor); + } + + $oldPaths = $this->paths; + $this->paths = $this->_actionToPath[$action]; + $result = parent::generate($values, $qstring, $anchor); + $this->paths = $oldPaths; + + return $result; + } } /** @@ -77,6 +116,8 @@ class Router static $bare = array('requesttoken', 'accesstoken', 'userauthorization', 'postnotice', 'updateprofile', 'finishremotesubscribe'); + const REGEX_TAG = '[^\/]+'; // [\pL\pN_\-\.]{1,64} better if we can do unicode regexes + static function get() { if (!Router::$inst) { @@ -87,9 +128,50 @@ class Router function __construct() { - if (!$this->m) { - $this->m = $this->initialize(); + if (empty($this->m)) { + if (!common_config('router', 'cache')) { + $this->m = $this->initialize(); + } else { + $k = self::cacheKey(); + $c = Cache::instance(); + $m = $c->get($k); + if (!empty($m)) { + $this->m = $m; + } else { + $this->m = $this->initialize(); + $c->set($k, $this->m); + } + } + } + } + + /** + * Create a unique hashkey for the router. + * + * The router's url map can change based on the version of the software + * you're running and the plugins that are enabled. To avoid having bad routes + * get stuck in the cache, the key includes a list of plugins and the software + * version. + * + * There can still be problems with a) differences in versions of the plugins and + * b) people running code between official versions, but these tend to be more + * sophisticated users who can grok what's going on and clear their caches. + * + * @return string cache key string that should uniquely identify a router + */ + + static function cacheKey() + { + $parts = array('router'); + + // Many router paths depend on this setting. + if (common_config('singleuser', 'enabled')) { + $parts[] = '1user'; + } else { + $parts[] = 'multi'; } + + return Cache::codeKey(implode(':', $parts)); } function initialize() @@ -117,7 +199,8 @@ class Router // main stuff is repetitive $main = array('login', 'logout', 'register', 'subscribe', - 'unsubscribe', 'confirmaddress', 'recoverpassword', + 'unsubscribe', 'cancelsubscription', 'approvesub', + 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', 'block', 'unblock', 'subedit', 'groupblock', 'groupunblock', @@ -128,7 +211,10 @@ class Router 'deleteuser', 'geocode', 'version', - ); + 'backupaccount', + 'deleteaccount', + 'restoreaccount', + ); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); @@ -151,8 +237,8 @@ class Router array('action' => 'publicxrds')); $m->connect('.well-known/host-meta', array('action' => 'hostmeta')); - $m->connect('main/xrd', - array('action' => 'userxrd')); + $m->connect('main/xrd', + array('action' => 'userxrd')); // these take a code @@ -172,24 +258,24 @@ class Router // settings foreach (array('profile', 'avatar', 'password', 'im', 'oauthconnections', - 'oauthapps', 'email', 'sms', 'userdesign', 'other') as $s) { + 'oauthapps', 'email', 'sms', 'userdesign', 'url') as $s) { $m->connect('settings/'.$s, array('action' => $s.'settings')); } $m->connect('settings/oauthapps/show/:id', - array('action' => 'showapplication'), - array('id' => '[0-9]+') + array('action' => 'showapplication'), + array('id' => '[0-9]+') ); $m->connect('settings/oauthapps/new', - array('action' => 'newapplication') + array('action' => 'newapplication') ); $m->connect('settings/oauthapps/edit/:id', - array('action' => 'editapplication'), - array('id' => '[0-9]+') + array('action' => 'editapplication'), + array('id' => '[0-9]+') ); $m->connect('settings/oauthapps/delete/:id', - array('action' => 'deleteapplication'), - array('id' => '[0-9]+') + array('action' => 'deleteapplication'), + array('id' => '[0-9]+') ); // search @@ -248,6 +334,9 @@ class Router $m->connect('conversation/:id', array('action' => 'conversation'), array('id' => '[0-9]+')); + $m->connect('conversation/:id/replies', + array('action' => 'conversationreplies'), + array('id' => '[0-9]+')); $m->connect('message/new', array('action' => 'newmessage')); $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => Nickname::DISPLAY_FMT)); @@ -265,20 +354,20 @@ class Router $m->connect('tag', array('action' => 'publictagcloud')); $m->connect('tag/:tag/rss', array('action' => 'tagrss'), - array('tag' => '[\pL\pN_\-\.]{1,64}')); + array('tag' => self::REGEX_TAG)); $m->connect('tag/:tag', array('action' => 'tag'), - array('tag' => '[\pL\pN_\-\.]{1,64}')); + array('tag' => self::REGEX_TAG)); $m->connect('peopletag/:tag', array('action' => 'peopletag'), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => self::REGEX_TAG)); // groups $m->connect('group/new', array('action' => 'newgroup')); - foreach (array('edit', 'join', 'leave', 'delete') as $v) { + foreach (array('edit', 'join', 'leave', 'delete', 'cancel', 'approve') as $v) { $m->connect('group/:nickname/'.$v, array('action' => $v.'group'), array('nickname' => Nickname::DISPLAY_FMT)); @@ -305,6 +394,10 @@ class Router array('action' => 'makeadmin'), array('nickname' => Nickname::DISPLAY_FMT)); + $m->connect('group/:nickname/members/pending', + array('action' => 'groupqueue'), + array('nickname' => Nickname::DISPLAY_FMT)); + $m->connect('group/:id/id', array('action' => 'groupbyid'), array('id' => '[0-9]+')); @@ -322,66 +415,71 @@ class Router // statuses API + $m->connect('api', + array('action' => 'Redirect', + 'nextAction' => 'doc', + 'args' => array('title' => 'api'))); + $m->connect('api/statuses/public_timeline.:format', array('action' => 'ApiTimelinePublic', - 'format' => '(xml|json|rss|atom)')); + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/friends_timeline.:format', array('action' => 'ApiTimelineFriends', - 'format' => '(xml|json|rss|atom)')); + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/friends_timeline/:id.:format', array('action' => 'ApiTimelineFriends', - 'id' => Nickname::DISPLAY_FMT, - 'format' => '(xml|json|rss|atom)')); + 'id' => Nickname::INPUT_FMT, + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/home_timeline.:format', array('action' => 'ApiTimelineHome', - 'format' => '(xml|json|rss|atom)')); + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/home_timeline/:id.:format', array('action' => 'ApiTimelineHome', - 'id' => Nickname::DISPLAY_FMT, - 'format' => '(xml|json|rss|atom)')); + 'id' => Nickname::INPUT_FMT, + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/user_timeline.:format', array('action' => 'ApiTimelineUser', - 'format' => '(xml|json|rss|atom)')); + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/user_timeline/:id.:format', array('action' => 'ApiTimelineUser', - 'id' => Nickname::DISPLAY_FMT, - 'format' => '(xml|json|rss|atom)')); + 'id' => Nickname::INPUT_FMT, + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/mentions.:format', array('action' => 'ApiTimelineMentions', - 'format' => '(xml|json|rss|atom)')); + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/mentions/:id.:format', array('action' => 'ApiTimelineMentions', - 'id' => Nickname::DISPLAY_FMT, - 'format' => '(xml|json|rss|atom)')); + 'id' => Nickname::INPUT_FMT, + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/replies.:format', array('action' => 'ApiTimelineMentions', - 'format' => '(xml|json|rss|atom)')); + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/replies/:id.:format', array('action' => 'ApiTimelineMentions', - 'id' => Nickname::DISPLAY_FMT, - 'format' => '(xml|json|rss|atom)')); + 'id' => Nickname::INPUT_FMT, + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statuses/retweeted_by_me.:format', array('action' => 'ApiTimelineRetweetedByMe', - 'format' => '(xml|json|atom)')); + 'format' => '(xml|json|atom|as)')); $m->connect('api/statuses/retweeted_to_me.:format', array('action' => 'ApiTimelineRetweetedToMe', - 'format' => '(xml|json|atom)')); + 'format' => '(xml|json|atom|as)')); $m->connect('api/statuses/retweets_of_me.:format', array('action' => 'ApiTimelineRetweetsOfMe', - 'format' => '(xml|json|atom)')); + 'format' => '(xml|json|atom|as)')); $m->connect('api/statuses/friends.:format', array('action' => 'ApiUserFriends', @@ -389,7 +487,7 @@ class Router $m->connect('api/statuses/friends/:id.:format', array('action' => 'ApiUserFriends', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); $m->connect('api/statuses/followers.:format', @@ -398,7 +496,7 @@ class Router $m->connect('api/statuses/followers/:id.:format', array('action' => 'ApiUserFollowers', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); $m->connect('api/statuses/show.:format', @@ -441,7 +539,12 @@ class Router $m->connect('api/users/show/:id.:format', array('action' => 'ApiUserShow', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, + 'format' => '(xml|json)')); + + $m->connect('api/users/profile_image/:screen_name.:format', + array('action' => 'ApiUserProfileImage', + 'screen_name' => Nickname::DISPLAY_FMT, 'format' => '(xml|json)')); // direct messages @@ -479,12 +582,12 @@ class Router $m->connect('api/friendships/create/:id.:format', array('action' => 'ApiFriendshipsCreate', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); $m->connect('api/friendships/destroy/:id.:format', array('action' => 'ApiFriendshipsDestroy', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); // Social graph @@ -537,21 +640,21 @@ class Router $m->connect('api/favorites.:format', array('action' => 'ApiTimelineFavorites', - 'format' => '(xml|json|rss|atom)')); + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/favorites/:id.:format', array('action' => 'ApiTimelineFavorites', - 'id' => Nickname::DISPLAY_FMT, - 'format' => '(xml|json|rss|atom)')); + 'id' => Nickname::INPUT_FMT, + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/favorites/create/:id.:format', array('action' => 'ApiFavoriteCreate', - 'id' => Nickname::DISPLAY_FMT, + 'id' => '[0-9]+', 'format' => '(xml|json)')); $m->connect('api/favorites/destroy/:id.:format', array('action' => 'ApiFavoriteDestroy', - 'id' => Nickname::DISPLAY_FMT, + 'id' => '[0-9]+', 'format' => '(xml|json)')); // blocks @@ -561,7 +664,7 @@ class Router $m->connect('api/blocks/create/:id.:format', array('action' => 'ApiBlockCreate', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); $m->connect('api/blocks/destroy.:format', @@ -570,7 +673,7 @@ class Router $m->connect('api/blocks/destroy/:id.:format', array('action' => 'ApiBlockDestroy', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); // help @@ -606,8 +709,8 @@ class Router $m->connect('api/statusnet/groups/timeline/:id.:format', array('action' => 'ApiTimelineGroup', - 'id' => Nickname::DISPLAY_FMT, - 'format' => '(xml|json|rss|atom)')); + 'id' => Nickname::INPUT_FMT, + 'format' => '(xml|json|rss|atom|as)')); $m->connect('api/statusnet/groups/show.:format', array('action' => 'ApiGroupShow', @@ -615,12 +718,12 @@ class Router $m->connect('api/statusnet/groups/show/:id.:format', array('action' => 'ApiGroupShow', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); $m->connect('api/statusnet/groups/join.:format', array('action' => 'ApiGroupJoin', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); $m->connect('api/statusnet/groups/join/:id.:format', @@ -629,7 +732,7 @@ class Router $m->connect('api/statusnet/groups/leave.:format', array('action' => 'ApiGroupLeave', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); $m->connect('api/statusnet/groups/leave/:id.:format', @@ -646,7 +749,7 @@ class Router $m->connect('api/statusnet/groups/list/:id.:format', array('action' => 'ApiGroupList', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json|rss|atom)')); $m->connect('api/statusnet/groups/list_all.:format', @@ -659,16 +762,22 @@ class Router $m->connect('api/statusnet/groups/membership/:id.:format', array('action' => 'ApiGroupMembership', - 'id' => Nickname::DISPLAY_FMT, + 'id' => Nickname::INPUT_FMT, 'format' => '(xml|json)')); $m->connect('api/statusnet/groups/create.:format', array('action' => 'ApiGroupCreate', 'format' => '(xml|json)')); + + $m->connect('api/statusnet/groups/update/:id.:format', + array('action' => 'ApiGroupProfileUpdate', + 'id' => '[a-zA-Z0-9]+', + 'format' => '(xml|json)')); + // Tags $m->connect('api/statusnet/tags/timeline/:tag.:format', array('action' => 'ApiTimelineTag', - 'format' => '(xml|json|rss|atom)')); + 'format' => '(xml|json|rss|atom|as)')); // media related $m->connect( @@ -690,24 +799,25 @@ class Router $m->connect('api/oauth/authorize', array('action' => 'ApiOauthAuthorize')); - $m->connect('api/statusnet/app/service/:id.xml', - array('action' => 'ApiAtomService', - 'id' => Nickname::DISPLAY_FMT)); - - $m->connect('api/statusnet/app/service.xml', - array('action' => 'ApiAtomService')); - // Admin - $m->connect('admin/site', array('action' => 'siteadminpanel')); - $m->connect('admin/design', array('action' => 'designadminpanel')); - $m->connect('admin/user', array('action' => 'useradminpanel')); - $m->connect('admin/access', array('action' => 'accessadminpanel')); - $m->connect('admin/paths', array('action' => 'pathsadminpanel')); - $m->connect('admin/sessions', array('action' => 'sessionsadminpanel')); - $m->connect('admin/sitenotice', array('action' => 'sitenoticeadminpanel')); - $m->connect('admin/snapshot', array('action' => 'snapshotadminpanel')); - $m->connect('admin/license', array('action' => 'licenseadminpanel')); + $m->connect('panel/site', array('action' => 'siteadminpanel')); + $m->connect('panel/design', array('action' => 'designadminpanel')); + $m->connect('panel/user', array('action' => 'useradminpanel')); + $m->connect('panel/access', array('action' => 'accessadminpanel')); + $m->connect('panel/paths', array('action' => 'pathsadminpanel')); + $m->connect('panel/sessions', array('action' => 'sessionsadminpanel')); + $m->connect('panel/sitenotice', array('action' => 'sitenoticeadminpanel')); + $m->connect('panel/snapshot', array('action' => 'snapshotadminpanel')); + $m->connect('panel/license', array('action' => 'licenseadminpanel')); + + $m->connect('panel/plugins', array('action' => 'pluginsadminpanel')); + $m->connect('panel/plugins/enable/:plugin', + array('action' => 'pluginenable'), + array('plugin' => '[A-Za-z0-9_]+')); + $m->connect('panel/plugins/disable/:plugin', + array('action' => 'plugindisable'), + array('plugin' => '[A-Za-z0-9_]+')); $m->connect('getfile/:filename', array('action' => 'getfile'), @@ -717,8 +827,7 @@ class Router if (common_config('singleuser', 'enabled')) { - $user = User::singleUser(); - $nickname = $user->nickname; + $nickname = User::singleUserNickname(); foreach (array('subscriptions', 'subscribers', 'all', 'foaf', 'xrds', @@ -732,9 +841,13 @@ class Router $m->connect($a.'/:tag', array('action' => $a, 'nickname' => $nickname), - array('tag' => '[a-zA-Z0-9]+')); + array('tag' => self::REGEX_TAG)); } + $m->connect('subscribers/pending', + array('action' => 'subqueue', + 'nickname' => $nickname)); + foreach (array('rss', 'groups') as $a) { $m->connect($a, array('action' => 'user'.$a, @@ -759,12 +872,12 @@ class Router $m->connect('tag/:tag/rss', array('action' => 'userrss', 'nickname' => $nickname), - array('tag' => '[\pL\pN_\-\.]{1,64}')); + array('tag' => self::REGEX_TAG)); $m->connect('tag/:tag', array('action' => 'showstream', 'nickname' => $nickname), - array('tag' => '[\pL\pN_\-\.]{1,64}')); + array('tag' => self::REGEX_TAG)); $m->connect('rsd.xml', array('action' => 'rsd', @@ -791,11 +904,14 @@ class Router array('action' => $a), array('nickname' => Nickname::DISPLAY_FMT)); } + $m->connect(':nickname/subscribers/pending', + array('action' => 'subqueue'), + array('nickname' => Nickname::DISPLAY_FMT)); foreach (array('subscriptions', 'subscribers') as $a) { $m->connect(':nickname/'.$a.'/:tag', array('action' => $a), - array('tag' => '[a-zA-Z0-9]+', + array('tag' => self::REGEX_TAG, 'nickname' => Nickname::DISPLAY_FMT)); } @@ -823,12 +939,12 @@ class Router $m->connect(':nickname/tag/:tag/rss', array('action' => 'userrss'), array('nickname' => Nickname::DISPLAY_FMT), - array('tag' => '[\pL\pN_\-\.]{1,64}')); + array('tag' => self::REGEX_TAG)); $m->connect(':nickname/tag/:tag', array('action' => 'showstream'), array('nickname' => Nickname::DISPLAY_FMT), - array('tag' => '[\pL\pN_\-\.]{1,64}')); + array('tag' => self::REGEX_TAG)); $m->connect(':nickname/rsd.xml', array('action' => 'rsd'), @@ -839,6 +955,48 @@ class Router array('nickname' => Nickname::DISPLAY_FMT)); } + // AtomPub API + + $m->connect('api/statusnet/app/service/:id.xml', + array('action' => 'ApiAtomService'), + array('id' => Nickname::DISPLAY_FMT)); + + $m->connect('api/statusnet/app/service.xml', + array('action' => 'ApiAtomService')); + + $m->connect('api/statusnet/app/subscriptions/:subscriber/:subscribed.atom', + array('action' => 'AtomPubShowSubscription'), + array('subscriber' => '[0-9]+', + 'subscribed' => '[0-9]+')); + + $m->connect('api/statusnet/app/subscriptions/:subscriber.atom', + array('action' => 'AtomPubSubscriptionFeed'), + array('subscriber' => '[0-9]+')); + + $m->connect('api/statusnet/app/favorites/:profile/:notice.atom', + array('action' => 'AtomPubShowFavorite'), + array('profile' => '[0-9]+', + 'notice' => '[0-9]+')); + + $m->connect('api/statusnet/app/favorites/:profile.atom', + array('action' => 'AtomPubFavoriteFeed'), + array('profile' => '[0-9]+')); + + $m->connect('api/statusnet/app/memberships/:profile/:group.atom', + array('action' => 'AtomPubShowMembership'), + array('profile' => '[0-9]+', + 'group' => '[0-9]+')); + + $m->connect('api/statusnet/app/memberships/:profile.atom', + array('action' => 'AtomPubMembershipFeed'), + array('profile' => '[0-9]+')); + + // URL shortening + + $m->connect('url/:id', + array('action' => 'redirecturl', + 'id' => '[0-9]+')); + // user stuff Event::handle('RouterInitialized', array($m)); @@ -881,14 +1039,14 @@ class Router $qpos = strpos($url, '?'); if ($qpos !== false) { $url = substr($url, 0, $qpos+1) . - str_replace('?', '&', substr($url, $qpos+1)); + str_replace('?', '&', substr($url, $qpos+1)); // @fixme this is a hacky workaround for http_build_query in the // lower-level code and bad configs that set the default separator // to & instead of &. Encoded &s in parameters will not be // affected. $url = substr($url, 0, $qpos+1) . - str_replace('&', '&', substr($url, $qpos+1)); + str_replace('&', '&', substr($url, $qpos+1)); }