{"action":"created","comment":{"url":"https://api.github.com/repos/aces/Loris/pulls/comments/169427087","pull_request_review_id":97951760,"id":169427087,"diff_hunk":"@@ -0,0 +1,142 @@\n+<?php\n+/**\n+ * Implements BaseRouter, a Router to handle the base of a LORIS\n+ * install.\n+ *\n+ * PHP Version 7\n+ *\n+ * @category Router\n+ * @package  Router\n+ * @author   Dave MacFarlane <david.macfarlane2@mcgill.ca>\n+ * @license  http://www.gnu.org/licenses/gpl-3.0.txt GPLv3\n+ * @link     https://www.github.com/aces/Loris/\n+ */\n+\n+namespace LORIS\\Router;\n+use \\Psr\\Http\\Message\\ServerRequestInterface;\n+use \\Psr\\Http\\Message\\ResponseInterface;\n+use \\Psr\\Http\\Server\\RequestHandlerInterface;\n+use \\LORIS\\Http\\StringStream;\n+\n+/**\n+ * Handles the root of a LORIS install. It will mostly delegate to the\n+ * A BaseRouter handles the base of a LORIS install and delegates to\n+ * other routers (such as Module routers)\n+ *\n+ * @category Router\n+ * @package  Router\n+ * @author   Dave MacFarlane <david.macfarlane2@mcgill.ca>\n+ * @license  http://www.gnu.org/licenses/gpl-3.0.txt GPLv3\n+ * @link     https://www.github.com/aces/Loris/\n+ */\n+class BaseRouter extends PrefixRouter implements RequestHandlerInterface\n+{\n+    protected $projectdir;\n+    protected $moduledir;\n+    protected $user;\n+\n+    /**\n+     * Construct a BaseRouter\n+     *\n+     * @param \\User  $user       The user accessing LORIS. (May be an AnonymousUser\n+     *                           instance).\n+     * @param string $projectdir The base of the LORIS project directory.\n+     * @param string $moduledir  The base of the LORIS modules directory.\n+     */\n+    public function __construct(\\User $user, string $projectdir, string $moduledir)\n+    {\n+        $this->user       = $user;\n+        $this->projectdir = $projectdir;\n+        $this->moduledir  = $moduledir;\n+    }\n+\n+    /**\n+     * Handle delegates to an appropriate sub-router to do the real handling of a\n+     * LORIS request.\n+     *\n+     * @param ServerRequestInterface $request The PSR7 request\n+     *\n+     * @return ServerResponse The PSR15 response.\n+     */\n+    public function handle(ServerRequestInterface $request) : ResponseInterface\n+    {\n+        $uri  = $request->getUri();\n+        $path = $uri->getPath();\n+        // Replace multiple slashes in the URL with a single slash\n+        $path = preg_replace(\"/\\/+/\", \"/\", $path);\n+        // Remove a training slash remaining, so that foo/ and foo are the same","path":"src/Router/BaseRouter.php","position":67,"original_position":67,"commit_id":"9b3bb1c22a6cc0978a556b3ccf6df960b07aa10a","original_commit_id":"9b3bb1c22a6cc0978a556b3ccf6df960b07aa10a","user":{"login":"PapillonMcGill","id":34311645,"avatar_url":"https://avatars0.githubusercontent.com/u/34311645?v=4","gravatar_id":"","url":"https://api.github.com/users/PapillonMcGill","html_url":"https://github.com/PapillonMcGill","followers_url":"https://api.github.com/users/PapillonMcGill/followers","following_url":"https://api.github.com/users/PapillonMcGill/following{/other_user}","gists_url":"https://api.github.com/users/PapillonMcGill/gists{/gist_id}","starred_url":"https://api.github.com/users/PapillonMcGill/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PapillonMcGill/subscriptions","organizations_url":"https://api.github.com/users/PapillonMcGill/orgs","repos_url":"https://api.github.com/users/PapillonMcGill/repos","events_url":"https://api.github.com/users/PapillonMcGill/events{/privacy}","received_events_url":"https://api.github.com/users/PapillonMcGill/received_events","type":"User","site_admin":false},"body":"Yes, that would be better","created_at":"2018-02-20T19:10:50Z","updated_at":"2018-02-20T19:10:50Z","html_url":"https://github.com/aces/Loris/pull/3480#discussion_r169427087","pull_request_url":"https://api.github.com/repos/aces/Loris/pulls/3480","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/aces/Loris/pulls/comments/169427087"},"html":{"href":"https://github.com/aces/Loris/pull/3480#discussion_r169427087"},"pull_request":{"href":"https://api.github.com/repos/aces/Loris/pulls/3480"}},"in_reply_to_id":169419156},"pull_request":{"url":"https://api.github.com/repos/aces/Loris/pulls/3480","id":168074012,"html_url":"https://github.com/aces/Loris/pull/3480","diff_url":"https://github.com/aces/Loris/pull/3480.diff","patch_url":"https://github.com/aces/Loris/pull/3480.patch","issue_url":"https://api.github.com/repos/aces/Loris/issues/3480","number":3480,"state":"open","locked":false,"title":"PSR15 Base Router","user":{"login":"driusan","id":498329,"avatar_url":"https://avatars0.githubusercontent.com/u/498329?v=4","gravatar_id":"","url":"https://api.github.com/users/driusan","html_url":"https://github.com/driusan","followers_url":"https://api.github.com/users/driusan/followers","following_url":"https://api.github.com/users/driusan/following{/other_user}","gists_url":"https://api.github.com/users/driusan/gists{/gist_id}","starred_url":"https://api.github.com/users/driusan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/driusan/subscriptions","organizations_url":"https://api.github.com/users/driusan/orgs","repos_url":"https://api.github.com/users/driusan/repos","events_url":"https://api.github.com/users/driusan/events{/privacy}","received_events_url":"https://api.github.com/users/driusan/received_events","type":"User","site_admin":false},"body":"This builds on #3477 to add the classes which implement (but not yet use) a PSR15 request handler based router for LORIS, as well as adding authentication middleware. (This is part of breaking my PSR7RouterZend branch into multiple smaller pull requests which are easier to review.)\r\n\r\nA PrefixRouter is a type of Router which, based on the prefix of the request, strips off the prefix and delegates to another router.\r\n\r\nA BaseRouter serves the root of a LORIS install and, effectively, replaces .htaccess. It annotates the PSR7 request with common properties like the user accessing LORIS and the BaseURL being served, but otherwise acts like a PrefixRouter to strip part of the URL and delegate to another router.\r\n\r\nA ModuleRouter is a type of router which adds authentication middleware based on whether or not the module being loaded is public, and delegate's to the module's handler. This is done outside of the module itself's handler to ensure the authentication middleware can't be accidentally removed by a module without setting the public flag.\r\n\r\nA ModuleFileRouter is a type of PrefixRouter which handles serving the /css, /js, and /static files of a module off the filesystem.\r\n\r\nThe other changes in this PR are inherited from #3477. ","created_at":"2018-02-08T20:07:56Z","updated_at":"2018-02-20T19:10:50Z","closed_at":null,"merged_at":null,"merge_commit_sha":"db4db309d8a675e4bf7749896c391c116f617ac5","assignee":{"login":"xlecours","id":12155214,"avatar_url":"https://avatars3.githubusercontent.com/u/12155214?v=4","gravatar_id":"","url":"https://api.github.com/users/xlecours","html_url":"https://github.com/xlecours","followers_url":"https://api.github.com/users/xlecours/followers","following_url":"https://api.github.com/users/xlecours/following{/other_user}","gists_url":"https://api.github.com/users/xlecours/gists{/gist_id}","starred_url":"https://api.github.com/users/xlecours/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xlecours/subscriptions","organizations_url":"https://api.github.com/users/xlecours/orgs","repos_url":"https://api.github.com/users/xlecours/repos","events_url":"https://api.github.com/users/xlecours/events{/privacy}","received_events_url":"https://api.github.com/users/xlecours/received_events","type":"User","site_admin":false},"assignees":[{"login":"xlecours","id":12155214,"avatar_url":"https://avatars3.githubusercontent.com/u/12155214?v=4","gravatar_id":"","url":"https://api.github.com/users/xlecours","html_url":"https://github.com/xlecours","followers_url":"https://api.github.com/users/xlecours/followers","following_url":"https://api.github.com/users/xlecours/following{/other_user}","gists_url":"https://api.github.com/users/xlecours/gists{/gist_id}","starred_url":"https://api.github.com/users/xlecours/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xlecours/subscriptions","organizations_url":"https://api.github.com/users/xlecours/orgs","repos_url":"https://api.github.com/users/xlecours/repos","events_url":"https://api.github.com/users/xlecours/events{/privacy}","received_events_url":"https://api.github.com/users/xlecours/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":152314516,"url":"https://api.github.com/repos/aces/Loris/labels/Cleanup","name":"Cleanup","color":"006b75","default":false},{"id":152305520,"url":"https://api.github.com/repos/aces/Loris/labels/Feature","name":"Feature","color":"1d76db","default":false},{"id":217901777,"url":"https://api.github.com/repos/aces/Loris/labels/Meta","name":"Meta","color":"DDDDDD","default":false},{"id":708896092,"url":"https://api.github.com/repos/aces/Loris/labels/[branch]%20major","name":"[branch] major","color":"4d3319","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/aces/Loris/pulls/3480/commits","review_comments_url":"https://api.github.com/repos/aces/Loris/pulls/3480/comments","review_comment_url":"https://api.github.com/repos/aces/Loris/pulls/comments{/number}","comments_url":"https://api.github.com/repos/aces/Loris/issues/3480/comments","statuses_url":"https://api.github.com/repos/aces/Loris/statuses/9b3bb1c22a6cc0978a556b3ccf6df960b07aa10a","head":{"label":"driusan:PSR15BaseRouting","ref":"PSR15BaseRouting","sha":"9b3bb1c22a6cc0978a556b3ccf6df960b07aa10a","user":{"login":"driusan","id":498329,"avatar_url":"https://avatars0.githubusercontent.com/u/498329?v=4","gravatar_id":"","url":"https://api.github.com/users/driusan","html_url":"https://github.com/driusan","followers_url":"https://api.github.com/users/driusan/followers","following_url":"https://api.github.com/users/driusan/following{/other_user}","gists_url":"https://api.github.com/users/driusan/gists{/gist_id}","starred_url":"https://api.github.com/users/driusan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/driusan/subscriptions","organizations_url":"https://api.github.com/users/driusan/orgs","repos_url":"https://api.github.com/users/driusan/repos","events_url":"https://api.github.com/users/driusan/events{/privacy}","received_events_url":"https://api.github.com/users/driusan/received_events","type":"User","site_admin":false},"repo":{"id":25378793,"name":"Loris","full_name":"driusan/Loris","owner":{"login":"driusan","id":498329,"avatar_url":"https://avatars0.githubusercontent.com/u/498329?v=4","gravatar_id":"","url":"https://api.github.com/users/driusan","html_url":"https://github.com/driusan","followers_url":"https://api.github.com/users/driusan/followers","following_url":"https://api.github.com/users/driusan/following{/other_user}","gists_url":"https://api.github.com/users/driusan/gists{/gist_id}","starred_url":"https://api.github.com/users/driusan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/driusan/subscriptions","organizations_url":"https://api.github.com/users/driusan/orgs","repos_url":"https://api.github.com/users/driusan/repos","events_url":"https://api.github.com/users/driusan/events{/privacy}","received_events_url":"https://api.github.com/users/driusan/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/driusan/Loris","description":"LORIS (Longitudinal Online Research and Imaging System) is a web-accessible database solution for neuroimaging.","fork":true,"url":"https://api.github.com/repos/driusan/Loris","forks_url":"https://api.github.com/repos/driusan/Loris/forks","keys_url":"https://api.github.com/repos/driusan/Loris/keys{/key_id}","collaborators_url":"https://api.github.com/repos/driusan/Loris/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/driusan/Loris/teams","hooks_url":"https://api.github.com/repos/driusan/Loris/hooks","issue_events_url":"https://api.github.com/repos/driusan/Loris/issues/events{/number}","events_url":"https://api.github.com/repos/driusan/Loris/events","assignees_url":"https://api.github.com/repos/driusan/Loris/assignees{/user}","branches_url":"https://api.github.com/repos/driusan/Loris/branches{/branch}","tags_url":"https://api.github.com/repos/driusan/Loris/tags","blobs_url":"https://api.github.com/repos/driusan/Loris/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/driusan/Loris/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/driusan/Loris/git/refs{/sha}","trees_url":"https://api.github.com/repos/driusan/Loris/git/trees{/sha}","statuses_url":"https://api.github.com/repos/driusan/Loris/statuses/{sha}","languages_url":"https://api.github.com/repos/driusan/Loris/languages","stargazers_url":"https://api.github.com/repos/driusan/Loris/stargazers","contributors_url":"https://api.github.com/repos/driusan/Loris/contributors","subscribers_url":"https://api.github.com/repos/driusan/Loris/subscribers","subscription_url":"https://api.github.com/repos/driusan/Loris/subscription","commits_url":"https://api.github.com/repos/driusan/Loris/commits{/sha}","git_commits_url":"https://api.github.com/repos/driusan/Loris/git/commits{/sha}","comments_url":"https://api.github.com/repos/driusan/Loris/comments{/number}","issue_comment_url":"https://api.github.com/repos/driusan/Loris/issues/comments{/number}","contents_url":"https://api.github.com/repos/driusan/Loris/contents/{+path}","compare_url":"https://api.github.com/repos/driusan/Loris/compare/{base}...{head}","merges_url":"https://api.github.com/repos/driusan/Loris/merges","archive_url":"https://api.github.com/repos/driusan/Loris/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/driusan/Loris/downloads","issues_url":"https://api.github.com/repos/driusan/Loris/issues{/number}","pulls_url":"https://api.github.com/repos/driusan/Loris/pulls{/number}","milestones_url":"https://api.github.com/repos/driusan/Loris/milestones{/number}","notifications_url":"https://api.github.com/repos/driusan/Loris/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/driusan/Loris/labels{/name}","releases_url":"https://api.github.com/repos/driusan/Loris/releases{/id}","deployments_url":"https://api.github.com/repos/driusan/Loris/deployments","created_at":"2014-10-17T21:57:06Z","updated_at":"2017-05-25T19:35:05Z","pushed_at":"2018-02-20T17:37:45Z","git_url":"git://github.com/driusan/Loris.git","ssh_url":"git@github.com:driusan/Loris.git","clone_url":"https://github.com/driusan/Loris.git","svn_url":"https://github.com/driusan/Loris","homepage":"","size":75012,"stargazers_count":0,"watchers_count":0,"language":"PHP","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0"},"forks":0,"open_issues":3,"watchers":0,"default_branch":"master"}},"base":{"label":"aces:major","ref":"major","sha":"3dd00b788c3dbc1d9fbfa99c97d6e9509a46b427","user":{"login":"aces","id":472868,"avatar_url":"https://avatars2.githubusercontent.com/u/472868?v=4","gravatar_id":"","url":"https://api.github.com/users/aces","html_url":"https://github.com/aces","followers_url":"https://api.github.com/users/aces/followers","following_url":"https://api.github.com/users/aces/following{/other_user}","gists_url":"https://api.github.com/users/aces/gists{/gist_id}","starred_url":"https://api.github.com/users/aces/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aces/subscriptions","organizations_url":"https://api.github.com/users/aces/orgs","repos_url":"https://api.github.com/users/aces/repos","events_url":"https://api.github.com/users/aces/events{/privacy}","received_events_url":"https://api.github.com/users/aces/received_events","type":"Organization","site_admin":false},"repo":{"id":1125630,"name":"Loris","full_name":"aces/Loris","owner":{"login":"aces","id":472868,"avatar_url":"https://avatars2.githubusercontent.com/u/472868?v=4","gravatar_id":"","url":"https://api.github.com/users/aces","html_url":"https://github.com/aces","followers_url":"https://api.github.com/users/aces/followers","following_url":"https://api.github.com/users/aces/following{/other_user}","gists_url":"https://api.github.com/users/aces/gists{/gist_id}","starred_url":"https://api.github.com/users/aces/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aces/subscriptions","organizations_url":"https://api.github.com/users/aces/orgs","repos_url":"https://api.github.com/users/aces/repos","events_url":"https://api.github.com/users/aces/events{/privacy}","received_events_url":"https://api.github.com/users/aces/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/aces/Loris","description":"LORIS is a web-accessible database solution for longitudinal multi-site studies.","fork":false,"url":"https://api.github.com/repos/aces/Loris","forks_url":"https://api.github.com/repos/aces/Loris/forks","keys_url":"https://api.github.com/repos/aces/Loris/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aces/Loris/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aces/Loris/teams","hooks_url":"https://api.github.com/repos/aces/Loris/hooks","issue_events_url":"https://api.github.com/repos/aces/Loris/issues/events{/number}","events_url":"https://api.github.com/repos/aces/Loris/events","assignees_url":"https://api.github.com/repos/aces/Loris/assignees{/user}","branches_url":"https://api.github.com/repos/aces/Loris/branches{/branch}","tags_url":"https://api.github.com/repos/aces/Loris/tags","blobs_url":"https://api.github.com/repos/aces/Loris/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aces/Loris/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aces/Loris/git/refs{/sha}","trees_url":"https://api.github.com/repos/aces/Loris/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aces/Loris/statuses/{sha}","languages_url":"https://api.github.com/repos/aces/Loris/languages","stargazers_url":"https://api.github.com/repos/aces/Loris/stargazers","contributors_url":"https://api.github.com/repos/aces/Loris/contributors","subscribers_url":"https://api.github.com/repos/aces/Loris/subscribers","subscription_url":"https://api.github.com/repos/aces/Loris/subscription","commits_url":"https://api.github.com/repos/aces/Loris/commits{/sha}","git_commits_url":"https://api.github.com/repos/aces/Loris/git/commits{/sha}","comments_url":"https://api.github.com/repos/aces/Loris/comments{/number}","issue_comment_url":"https://api.github.com/repos/aces/Loris/issues/comments{/number}","contents_url":"https://api.github.com/repos/aces/Loris/contents/{+path}","compare_url":"https://api.github.com/repos/aces/Loris/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aces/Loris/merges","archive_url":"https://api.github.com/repos/aces/Loris/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aces/Loris/downloads","issues_url":"https://api.github.com/repos/aces/Loris/issues{/number}","pulls_url":"https://api.github.com/repos/aces/Loris/pulls{/number}","milestones_url":"https://api.github.com/repos/aces/Loris/milestones{/number}","notifications_url":"https://api.github.com/repos/aces/Loris/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aces/Loris/labels{/name}","releases_url":"https://api.github.com/repos/aces/Loris/releases{/id}","deployments_url":"https://api.github.com/repos/aces/Loris/deployments","created_at":"2010-11-30T14:57:57Z","updated_at":"2018-02-13T09:36:32Z","pushed_at":"2018-02-20T18:15:19Z","git_url":"git://github.com/aces/Loris.git","ssh_url":"git@github.com:aces/Loris.git","clone_url":"https://github.com/aces/Loris.git","svn_url":"https://github.com/aces/Loris","homepage":"","size":74067,"stargazers_count":58,"watchers_count":58,"language":"PHP","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":84,"mirror_url":null,"archived":false,"open_issues_count":73,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0"},"forks":84,"open_issues":73,"watchers":58,"default_branch":"minor"}},"_links":{"self":{"href":"https://api.github.com/repos/aces/Loris/pulls/3480"},"html":{"href":"https://github.com/aces/Loris/pull/3480"},"issue":{"href":"https://api.github.com/repos/aces/Loris/issues/3480"},"comments":{"href":"https://api.github.com/repos/aces/Loris/issues/3480/comments"},"review_comments":{"href":"https://api.github.com/repos/aces/Loris/pulls/3480/comments"},"review_comment":{"href":"https://api.github.com/repos/aces/Loris/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/aces/Loris/pulls/3480/commits"},"statuses":{"href":"https://api.github.com/repos/aces/Loris/statuses/9b3bb1c22a6cc0978a556b3ccf6df960b07aa10a"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"PapillonMcGill"}}