{"action":"created","comment":{"url":"https://api.github.com/repos/concrete5/concrete5/pulls/comments/195642868","pull_request_review_id":129052801,"id":195642868,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NTY0Mjg2OA==","diff_hunk":"@@ -1,243 +1,78 @@\n <?php\n+\n namespace Concrete\\Job;\n \n-use Concrete\\Core\\Cache\\Cache;\n-use Concrete\\Core\\Console\\ConsoleAwareInterface;\n-use Concrete\\Core\\Console\\ConsoleAwareTrait;\n-use Config;\n+use Concrete\\Core\\Application\\ApplicationAwareInterface;\n+use Concrete\\Core\\Application\\ApplicationAwareTrait;\n+use Concrete\\Core\\Error\\UserMessageException;\n+use Concrete\\Core\\Http\\Request;\n+use Concrete\\Core\\Page\\Sitemap\\Element\\SitemapElement;\n+use Concrete\\Core\\Page\\Sitemap\\Element\\SitemapPage;\n+use Concrete\\Core\\Page\\Sitemap\\SitemapWriter;\n use Job as AbstractJob;\n-use Core;\n-use Database;\n-use PermissionKey;\n-use Group;\n-use DateTime;\n-use CollectionAttributeKey;\n-use Concrete\\Core\\Permission\\Access\\Entity\\GroupEntity as GroupPermissionAccessEntity;\n-use Concrete\\Core\\Multilingual\\Page\\Section\\Section as MultilingualSection;\n-use SimpleXMLElement;\n-use Page;\n-use Events;\n-use Symfony\\Component\\Console\\Helper\\ProgressBar;\n \n-class GenerateSitemap extends AbstractJob implements ConsoleAwareInterface\n+class GenerateSitemap extends AbstractJob implements ApplicationAwareInterface\n {\n+    use ApplicationAwareTrait;\n \n-    use ConsoleAwareTrait;\n-\n-    /** The end-of-line terminator.\n-     * @var string\n-     */\n-    const EOL = \"\\n\";\n-\n-    /** Returns the job name.\n+    /**\n+     * Returns the job name.\n+     *\n      * @return string\n      */\n     public function getJobName()\n     {\n         return t('Generate the sitemap.xml file');\n     }\n \n-    /** Returns the job description.\n+    /**\n+     * Returns the job description.\n+     *\n      * @return string\n      */\n     public function getJobDescription()\n     {\n         return t('Generate the sitemap.xml file that search engines use to crawl your site.');\n     }\n \n-    /** Executes the job.\n-     * @throws \\Exception Throws an exception in case of errors.\n+    /**\n+     * Executes the job.\n      *\n-     * @return string Returns a string describing the job result in case of success.\n-     */\n-    public function run()\n-    {\n-        $output = $this->getOutput();\n-        Cache::disableAll();\n-        try {\n-            $instances = array(\n-                'navigation' => Core::make('helper/navigation'),\n-                'dashboard' => Core::make('helper/concrete/dashboard'),\n-                'view_page' => PermissionKey::getByHandle('view_page'),\n-                'guestGroup' => Group::getByID(GUEST_GROUP_ID),\n-                'now' => new DateTime('now'),\n-                'ak_exclude_sitemapxml' => CollectionAttributeKey::getByHandle('exclude_sitemapxml'),\n-                'ak_sitemap_changefreq' => CollectionAttributeKey::getByHandle('sitemap_changefreq'),\n-                'ak_sitemap_priority' => CollectionAttributeKey::getByHandle('sitemap_priority'),\n-            );\n-            $instances['guestGroupAE'] = array(GroupPermissionAccessEntity::getOrCreate($instances['guestGroup']));\n-            if (\\Core::make('multilingual/detector')->isEnabled()) {\n-                $instances['multilingualSections'] = MultilingualSection::getList();\n-            } else {\n-                $instances['multilingualSections'] = array();\n-            }\n-            $xml = '<?xml version=\"1.0\" encoding=\"' . APP_CHARSET . '\"?>';\n-            $xml .= '<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"';\n-            if ($instances['multilingualSections']) {\n-                $xml .= ' xmlns:x=\"http://www.w3.org/1999/xhtml\"';\n-            }\n-            $xml .= ' />';\n-            $xmlDoc = new SimpleXMLElement($xml);\n-            $rs = Database::get()->query('SELECT cID FROM Pages');\n-\n-            $count = $rs->rowCount();\n-            $progress = new ProgressBar($output, $count);\n-            $progress->setMessage('Adding pages to sitemap');\n-            $progress->display();\n-\n-            while ($row = $rs->FetchRow()) {\n-                $progress->advance();\n-                self::addPage($xmlDoc, intval($row['cID']), $instances);\n-            }\n-            $rs->Close();\n-            $progress->clear();\n-\n-            $event = new \\Symfony\\Component\\EventDispatcher\\GenericEvent();\n-            $event->setArgument('xmlDoc', $xmlDoc);\n-            Events::dispatch('on_sitemap_xml_ready', $event);\n-\n-            $dom = dom_import_simplexml($xmlDoc)->ownerDocument;\n-            $dom->formatOutput = true;\n-            $addedPages = count($xmlDoc->url);\n-            $relName = ltrim(Config::get('concrete.sitemap_xml.file'), '\\\\/');\n-            $osName = rtrim(DIR_BASE, '\\\\/') . '/' . $relName;\n-            $urlName = rtrim(\\Core::getApplicationURL(), '\\\\/') . '/' . $relName;\n-            if (!file_exists($osName)) {\n-                @touch($osName);\n-            }\n-            if (!is_writable($osName)) {\n-                throw new \\Exception(t('The file %s is not writable', $osName));\n-            }\n-            if (!$hFile = @fopen($osName, 'w')) {\n-                throw new \\Exception(t('Cannot open file %s', $osName));\n-            }\n-            if (!@fwrite($hFile, $dom->saveXML())) {\n-                throw new \\Exception(t('Error writing to file %s', $osName));\n-            }\n-            @fflush($hFile);\n-            @fclose($hFile);\n-            unset($hFile);\n-\n-            return t(\n-                '%1$s file saved (%2$d pages).',\n-                sprintf('<a href=\"%s\" target=\"_blank\">%s</a>', $urlName, preg_replace('/^https?:\\/\\//i', '', $urlName)),\n-                $addedPages\n-            );\n-        } catch (\\Exception $x) {\n-            if (isset($hFile) && $hFile) {\n-                @fflush($hFile);\n-                @ftruncate($hFile, 0);\n-                @fclose($hFile);\n-                $hFile = null;\n-            }\n-            throw $x;\n-        }\n-    }\n-\n-    /** Check if the specified page should be included in the sitemap.xml file; if so adds it to the XML document.\n-     * @param SimpleXMLElement $xmlDoc The xml document containing the sitemap nodes.\n-     * @param int $cID The page collection id.\n-     * @param array $instances An array with some already instantiated helpers, models, ...\n+     * @throws \\Exception throws an exception in case of errors\n      *\n-     * @throws \\Exception Throws an exception in case of errors.\n+     * @return string returns a string describing the job result in case of success\n      */\n-    private static function addPage($xmlDoc, $cID, $instances)\n+    public function run()\n     {\n-        $page = Page::getByID($cID, 'ACTIVE');\n-        if (!static::canIncludePageInSitemap($page, $instances)) {\n-            return;\n-        }\n-        $lastmod = new DateTime($page->getCollectionDateLastModified());\n-        $changefreq = $page->getAttribute($instances['ak_sitemap_changefreq']);\n-        $priority = $page->getAttribute($instances['ak_sitemap_priority']);\n-        $xmlNode = $xmlDoc->addChild('url');\n-        $xmlNode->addChild(\n-            'loc',\n-            $instances['navigation']->getLinkToCollection($page)\n-        );\n-        $xmlNode->addChild('lastmod', $lastmod->format(DateTime::ATOM));\n-        $xmlNode->addChild(\n-            'changefreq',\n-            Core::make('helper/validation/strings')->notempty($changefreq) ? $changefreq : Config::get('concrete.sitemap_xml.frequency')\n-        );\n-        $xmlNode->addChild(\n-            'priority',\n-            is_numeric($priority) ? $priority : Config::get('concrete.sitemap_xml.priority')\n-        );\n-        if ($instances['multilingualSections']) {\n-            $thisSection = MultilingualSection::getBySectionOfSite($page);\n-            if (is_object($thisSection) && !$thisSection->isError()) {\n-                foreach ($instances['multilingualSections'] as $section) {\n-                    $relatedPageID = $section->getTranslatedPageID($page);\n-                    if ($relatedPageID) {\n-                        $relatedPage = Page::getByID($relatedPageID);\n-                        if (static::canIncludePageInSitemap($relatedPage, $instances)) {\n-                            $xmlAltNode = $xmlNode->addChild('link', null, 'http://www.w3.org/1999/xhtml');\n-                            $xmlAltNode->addAttribute('rel', 'alternate');\n-                            $xmlAltNode->addAttribute('hreflang', strtolower(str_replace('_', '-', $section->getLocale())));\n-                            $xmlAltNode->addAttribute('href', $instances['navigation']->getLinkToCollection($relatedPage));\n-                        }\n-                    }\n-                }\n+        $writer = $this->app->make(SitemapWriter::class);\n+        $generator = $writer->getSitemapGenerator();\n+        if ($generator->getSiteCanonicalUrl() === '') {\n+            $request = $this->app->make(Request::class);\n+            if (!$request->getHost()) {\n+                throw new UserMessageException(t('Canonical URL is not set and no HTTP request to retrieve the site URL from.'));","path":"concrete/jobs/generate_sitemap.php","position":208,"original_position":208,"commit_id":"89a096c162d2dea2eaea2fa49abe16ae9892650d","original_commit_id":"89a096c162d2dea2eaea2fa49abe16ae9892650d","user":{"login":"a3020","id":1431100,"node_id":"MDQ6VXNlcjE0MzExMDA=","avatar_url":"https://avatars2.githubusercontent.com/u/1431100?v=4","gravatar_id":"","url":"https://api.github.com/users/a3020","html_url":"https://github.com/a3020","followers_url":"https://api.github.com/users/a3020/followers","following_url":"https://api.github.com/users/a3020/following{/other_user}","gists_url":"https://api.github.com/users/a3020/gists{/gist_id}","starred_url":"https://api.github.com/users/a3020/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/a3020/subscriptions","organizations_url":"https://api.github.com/users/a3020/orgs","repos_url":"https://api.github.com/users/a3020/repos","events_url":"https://api.github.com/users/a3020/events{/privacy}","received_events_url":"https://api.github.com/users/a3020/received_events","type":"User","site_admin":false},"body":"'Canonical URL is not set and **there is** no HTTP request to retrieve the site URL from.'?","created_at":"2018-06-15T06:28:34Z","updated_at":"2018-06-15T06:59:53Z","html_url":"https://github.com/concrete5/concrete5/pull/6777#discussion_r195642868","pull_request_url":"https://api.github.com/repos/concrete5/concrete5/pulls/6777","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/concrete5/concrete5/pulls/comments/195642868"},"html":{"href":"https://github.com/concrete5/concrete5/pull/6777#discussion_r195642868"},"pull_request":{"href":"https://api.github.com/repos/concrete5/concrete5/pulls/6777"}}},"pull_request":{"url":"https://api.github.com/repos/concrete5/concrete5/pulls/6777","id":194888928,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk0ODg4OTI4","html_url":"https://github.com/concrete5/concrete5/pull/6777","diff_url":"https://github.com/concrete5/concrete5/pull/6777.diff","patch_url":"https://github.com/concrete5/concrete5/pull/6777.patch","issue_url":"https://api.github.com/repos/concrete5/concrete5/issues/6777","number":6777,"state":"open","locked":false,"title":"Rewrite XML Sitemap generation","user":{"login":"mlocati","id":928116,"node_id":"MDQ6VXNlcjkyODExNg==","avatar_url":"https://avatars3.githubusercontent.com/u/928116?v=4","gravatar_id":"","url":"https://api.github.com/users/mlocati","html_url":"https://github.com/mlocati","followers_url":"https://api.github.com/users/mlocati/followers","following_url":"https://api.github.com/users/mlocati/following{/other_user}","gists_url":"https://api.github.com/users/mlocati/gists{/gist_id}","starred_url":"https://api.github.com/users/mlocati/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mlocati/subscriptions","organizations_url":"https://api.github.com/users/mlocati/orgs","repos_url":"https://api.github.com/users/mlocati/repos","events_url":"https://api.github.com/users/mlocati/events{/privacy}","received_events_url":"https://api.github.com/users/mlocati/received_events","type":"User","site_admin":false},"body":"The current generation of the sitemap.xml file is all done inside the `generate_sitemap` authomated job.\r\n\r\nThis has a few drawbacks:\r\n1. it's not possible to specify the website URL if it's launched via CLI (with the `c5:job` command) and if the site does not have a canonical URL\r\n2. the whole sitemap is always generated in memory and then written to a file (this is a problem for huge websites)\r\n3. to specify a specific location of the generated file we have to change the concrete configuration (it would be nice to be able to do it easily via a CLI command)\r\n4. the listeners of the events that allow customizing the sitemap have a hard life, since they have to work with a SimpleXml instance, so they have to process it to extract the relevant data\r\n5. in future concrete5 will support multiple sites, but there's no way to specify the site for which we want the sitemap.\r\n\r\nThe implementation of this PR solves all the problems:\r\n1. the new `c5:sitemap:generate` CLI command accepts an `url` parameter to set (or override) the site canonical URL, so that we always have full URLs in the xml file\r\n2. if not needed (that is, there's no listener of the `on_sitemap_xml_ready` event), the sitemap is now written line by line to a temporary file (we don't have anymore a full sitemap loaded in memory)\r\n3. the new `c5:sitemap:generate` CLI command accepts an `url` parameter to specify the location of the sitemap.xml file to be generated\r\n4. the listeners of the `on_sitemap_xml_addingpage` event now have the ability to easily process the data to be included in the sitemap\r\n5. the new `c5:sitemap:generate` CLI command accepts a `site` parameter to specify which is the site to be processed.\r\n\r\n### BC breaks\r\n\r\n1. The class of the `generate_sitemap` authomated job has been completely rewritten: almost everything it contained has been moved to classes in the `Concrete\\Core\\Page\\Sitemap` namespace\r\n2. ~~The arguments of the `on_sitemap_xml_addingpage` event changed from (`page`, `xmlNode`) to `sitemapPage` (an instance of the new `Concrete\\Core\\Page\\Sitemap\\Element\\SitemapPage` class)~~\r\n\r\nPS: fix #6771","created_at":"2018-06-14T13:12:50Z","updated_at":"2018-06-15T06:59:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4e30e598276d1207550d42f0a36deee17525d60a","assignee":null,"assignees":[],"requested_reviewers":[{"login":"KorvinSzanto","id":1007419,"node_id":"MDQ6VXNlcjEwMDc0MTk=","avatar_url":"https://avatars1.githubusercontent.com/u/1007419?v=4","gravatar_id":"","url":"https://api.github.com/users/KorvinSzanto","html_url":"https://github.com/KorvinSzanto","followers_url":"https://api.github.com/users/KorvinSzanto/followers","following_url":"https://api.github.com/users/KorvinSzanto/following{/other_user}","gists_url":"https://api.github.com/users/KorvinSzanto/gists{/gist_id}","starred_url":"https://api.github.com/users/KorvinSzanto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/KorvinSzanto/subscriptions","organizations_url":"https://api.github.com/users/KorvinSzanto/orgs","repos_url":"https://api.github.com/users/KorvinSzanto/repos","events_url":"https://api.github.com/users/KorvinSzanto/events{/privacy}","received_events_url":"https://api.github.com/users/KorvinSzanto/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/concrete5/concrete5/pulls/6777/commits","review_comments_url":"https://api.github.com/repos/concrete5/concrete5/pulls/6777/comments","review_comment_url":"https://api.github.com/repos/concrete5/concrete5/pulls/comments{/number}","comments_url":"https://api.github.com/repos/concrete5/concrete5/issues/6777/comments","statuses_url":"https://api.github.com/repos/concrete5/concrete5/statuses/89a096c162d2dea2eaea2fa49abe16ae9892650d","head":{"label":"mlocati:sitemap-xml-generation","ref":"sitemap-xml-generation","sha":"89a096c162d2dea2eaea2fa49abe16ae9892650d","user":{"login":"mlocati","id":928116,"node_id":"MDQ6VXNlcjkyODExNg==","avatar_url":"https://avatars3.githubusercontent.com/u/928116?v=4","gravatar_id":"","url":"https://api.github.com/users/mlocati","html_url":"https://github.com/mlocati","followers_url":"https://api.github.com/users/mlocati/followers","following_url":"https://api.github.com/users/mlocati/following{/other_user}","gists_url":"https://api.github.com/users/mlocati/gists{/gist_id}","starred_url":"https://api.github.com/users/mlocati/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mlocati/subscriptions","organizations_url":"https://api.github.com/users/mlocati/orgs","repos_url":"https://api.github.com/users/mlocati/repos","events_url":"https://api.github.com/users/mlocati/events{/privacy}","received_events_url":"https://api.github.com/users/mlocati/received_events","type":"User","site_admin":false},"repo":{"id":19068220,"node_id":"MDEwOlJlcG9zaXRvcnkxOTA2ODIyMA==","name":"concrete5","full_name":"mlocati/concrete5","owner":{"login":"mlocati","id":928116,"node_id":"MDQ6VXNlcjkyODExNg==","avatar_url":"https://avatars3.githubusercontent.com/u/928116?v=4","gravatar_id":"","url":"https://api.github.com/users/mlocati","html_url":"https://github.com/mlocati","followers_url":"https://api.github.com/users/mlocati/followers","following_url":"https://api.github.com/users/mlocati/following{/other_user}","gists_url":"https://api.github.com/users/mlocati/gists{/gist_id}","starred_url":"https://api.github.com/users/mlocati/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mlocati/subscriptions","organizations_url":"https://api.github.com/users/mlocati/orgs","repos_url":"https://api.github.com/users/mlocati/repos","events_url":"https://api.github.com/users/mlocati/events{/privacy}","received_events_url":"https://api.github.com/users/mlocati/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mlocati/concrete5","description":"My development fork of concrete5","fork":true,"url":"https://api.github.com/repos/mlocati/concrete5","forks_url":"https://api.github.com/repos/mlocati/concrete5/forks","keys_url":"https://api.github.com/repos/mlocati/concrete5/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mlocati/concrete5/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mlocati/concrete5/teams","hooks_url":"https://api.github.com/repos/mlocati/concrete5/hooks","issue_events_url":"https://api.github.com/repos/mlocati/concrete5/issues/events{/number}","events_url":"https://api.github.com/repos/mlocati/concrete5/events","assignees_url":"https://api.github.com/repos/mlocati/concrete5/assignees{/user}","branches_url":"https://api.github.com/repos/mlocati/concrete5/branches{/branch}","tags_url":"https://api.github.com/repos/mlocati/concrete5/tags","blobs_url":"https://api.github.com/repos/mlocati/concrete5/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mlocati/concrete5/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mlocati/concrete5/git/refs{/sha}","trees_url":"https://api.github.com/repos/mlocati/concrete5/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mlocati/concrete5/statuses/{sha}","languages_url":"https://api.github.com/repos/mlocati/concrete5/languages","stargazers_url":"https://api.github.com/repos/mlocati/concrete5/stargazers","contributors_url":"https://api.github.com/repos/mlocati/concrete5/contributors","subscribers_url":"https://api.github.com/repos/mlocati/concrete5/subscribers","subscription_url":"https://api.github.com/repos/mlocati/concrete5/subscription","commits_url":"https://api.github.com/repos/mlocati/concrete5/commits{/sha}","git_commits_url":"https://api.github.com/repos/mlocati/concrete5/git/commits{/sha}","comments_url":"https://api.github.com/repos/mlocati/concrete5/comments{/number}","issue_comment_url":"https://api.github.com/repos/mlocati/concrete5/issues/comments{/number}","contents_url":"https://api.github.com/repos/mlocati/concrete5/contents/{+path}","compare_url":"https://api.github.com/repos/mlocati/concrete5/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mlocati/concrete5/merges","archive_url":"https://api.github.com/repos/mlocati/concrete5/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mlocati/concrete5/downloads","issues_url":"https://api.github.com/repos/mlocati/concrete5/issues{/number}","pulls_url":"https://api.github.com/repos/mlocati/concrete5/pulls{/number}","milestones_url":"https://api.github.com/repos/mlocati/concrete5/milestones{/number}","notifications_url":"https://api.github.com/repos/mlocati/concrete5/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mlocati/concrete5/labels{/name}","releases_url":"https://api.github.com/repos/mlocati/concrete5/releases{/id}","deployments_url":"https://api.github.com/repos/mlocati/concrete5/deployments","created_at":"2014-04-23T12:09:20Z","updated_at":"2018-06-14T07:50:57Z","pushed_at":"2018-06-15T06:15:48Z","git_url":"git://github.com/mlocati/concrete5.git","ssh_url":"git@github.com:mlocati/concrete5.git","clone_url":"https://github.com/mlocati/concrete5.git","svn_url":"https://github.com/mlocati/concrete5","homepage":"https://github.com/concrete5/concrete5","size":107361,"stargazers_count":1,"watchers_count":1,"language":"PHP","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":1,"open_issues":0,"watchers":1,"default_branch":"develop"}},"base":{"label":"concrete5:develop","ref":"develop","sha":"1bba84b7243857b9c270218db19947b85eba249a","user":{"login":"concrete5","id":657929,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY1NzkyOQ==","avatar_url":"https://avatars3.githubusercontent.com/u/657929?v=4","gravatar_id":"","url":"https://api.github.com/users/concrete5","html_url":"https://github.com/concrete5","followers_url":"https://api.github.com/users/concrete5/followers","following_url":"https://api.github.com/users/concrete5/following{/other_user}","gists_url":"https://api.github.com/users/concrete5/gists{/gist_id}","starred_url":"https://api.github.com/users/concrete5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/concrete5/subscriptions","organizations_url":"https://api.github.com/users/concrete5/orgs","repos_url":"https://api.github.com/users/concrete5/repos","events_url":"https://api.github.com/users/concrete5/events{/privacy}","received_events_url":"https://api.github.com/users/concrete5/received_events","type":"Organization","site_admin":false},"repo":{"id":19040482,"node_id":"MDEwOlJlcG9zaXRvcnkxOTA0MDQ4Mg==","name":"concrete5","full_name":"concrete5/concrete5","owner":{"login":"concrete5","id":657929,"node_id":"MDEyOk9yZ2FuaXphdGlvbjY1NzkyOQ==","avatar_url":"https://avatars3.githubusercontent.com/u/657929?v=4","gravatar_id":"","url":"https://api.github.com/users/concrete5","html_url":"https://github.com/concrete5","followers_url":"https://api.github.com/users/concrete5/followers","following_url":"https://api.github.com/users/concrete5/following{/other_user}","gists_url":"https://api.github.com/users/concrete5/gists{/gist_id}","starred_url":"https://api.github.com/users/concrete5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/concrete5/subscriptions","organizations_url":"https://api.github.com/users/concrete5/orgs","repos_url":"https://api.github.com/users/concrete5/repos","events_url":"https://api.github.com/users/concrete5/events{/privacy}","received_events_url":"https://api.github.com/users/concrete5/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/concrete5/concrete5","description":"Official repository for concrete5 development","fork":false,"url":"https://api.github.com/repos/concrete5/concrete5","forks_url":"https://api.github.com/repos/concrete5/concrete5/forks","keys_url":"https://api.github.com/repos/concrete5/concrete5/keys{/key_id}","collaborators_url":"https://api.github.com/repos/concrete5/concrete5/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/concrete5/concrete5/teams","hooks_url":"https://api.github.com/repos/concrete5/concrete5/hooks","issue_events_url":"https://api.github.com/repos/concrete5/concrete5/issues/events{/number}","events_url":"https://api.github.com/repos/concrete5/concrete5/events","assignees_url":"https://api.github.com/repos/concrete5/concrete5/assignees{/user}","branches_url":"https://api.github.com/repos/concrete5/concrete5/branches{/branch}","tags_url":"https://api.github.com/repos/concrete5/concrete5/tags","blobs_url":"https://api.github.com/repos/concrete5/concrete5/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/concrete5/concrete5/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/concrete5/concrete5/git/refs{/sha}","trees_url":"https://api.github.com/repos/concrete5/concrete5/git/trees{/sha}","statuses_url":"https://api.github.com/repos/concrete5/concrete5/statuses/{sha}","languages_url":"https://api.github.com/repos/concrete5/concrete5/languages","stargazers_url":"https://api.github.com/repos/concrete5/concrete5/stargazers","contributors_url":"https://api.github.com/repos/concrete5/concrete5/contributors","subscribers_url":"https://api.github.com/repos/concrete5/concrete5/subscribers","subscription_url":"https://api.github.com/repos/concrete5/concrete5/subscription","commits_url":"https://api.github.com/repos/concrete5/concrete5/commits{/sha}","git_commits_url":"https://api.github.com/repos/concrete5/concrete5/git/commits{/sha}","comments_url":"https://api.github.com/repos/concrete5/concrete5/comments{/number}","issue_comment_url":"https://api.github.com/repos/concrete5/concrete5/issues/comments{/number}","contents_url":"https://api.github.com/repos/concrete5/concrete5/contents/{+path}","compare_url":"https://api.github.com/repos/concrete5/concrete5/compare/{base}...{head}","merges_url":"https://api.github.com/repos/concrete5/concrete5/merges","archive_url":"https://api.github.com/repos/concrete5/concrete5/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/concrete5/concrete5/downloads","issues_url":"https://api.github.com/repos/concrete5/concrete5/issues{/number}","pulls_url":"https://api.github.com/repos/concrete5/concrete5/pulls{/number}","milestones_url":"https://api.github.com/repos/concrete5/concrete5/milestones{/number}","notifications_url":"https://api.github.com/repos/concrete5/concrete5/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/concrete5/concrete5/labels{/name}","releases_url":"https://api.github.com/repos/concrete5/concrete5/releases{/id}","deployments_url":"https://api.github.com/repos/concrete5/concrete5/deployments","created_at":"2014-04-22T18:12:28Z","updated_at":"2018-06-14T22:02:20Z","pushed_at":"2018-06-15T06:16:02Z","git_url":"git://github.com/concrete5/concrete5.git","ssh_url":"git@github.com:concrete5/concrete5.git","clone_url":"https://github.com/concrete5/concrete5.git","svn_url":"https://github.com/concrete5/concrete5","homepage":"https://www.concrete5.org","size":99536,"stargazers_count":460,"watchers_count":460,"language":"PHP","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":346,"mirror_url":null,"archived":false,"open_issues_count":639,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":346,"open_issues":639,"watchers":460,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/concrete5/concrete5/pulls/6777"},"html":{"href":"https://github.com/concrete5/concrete5/pull/6777"},"issue":{"href":"https://api.github.com/repos/concrete5/concrete5/issues/6777"},"comments":{"href":"https://api.github.com/repos/concrete5/concrete5/issues/6777/comments"},"review_comments":{"href":"https://api.github.com/repos/concrete5/concrete5/pulls/6777/comments"},"review_comment":{"href":"https://api.github.com/repos/concrete5/concrete5/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/concrete5/concrete5/pulls/6777/commits"},"statuses":{"href":"https://api.github.com/repos/concrete5/concrete5/statuses/89a096c162d2dea2eaea2fa49abe16ae9892650d"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"a3020"}}