You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
5.3 KiB

  1. <?php
  2. namespace p3k\XRay\Formats;
  3. use DateTime, DateTimeZone;
  4. use Config;
  5. use cebe\markdown\GithubMarkdown;
  6. class GitHub extends Format {
  7. public static function matches_host($url) {
  8. $host = parse_url($url, PHP_URL_HOST);
  9. return $host == 'github.com';
  10. }
  11. public static function matches($url) {
  12. return preg_match('~https://github.com/([^/]+)/([^/]+)/pull/(\d+)$~', $url, $match)
  13. || preg_match('~https://github.com/([^/]+)/([^/]+)/issues/(\d+)$~', $url, $match)
  14. || preg_match('~https://github.com/([^/]+)/([^/]+)$~', $url, $match)
  15. || preg_match('~https://github.com/([^/]+)/([^/]+)/issues/(\d+)#issuecomment-(\d+)~', $url, $match);
  16. }
  17. private static function extract_url_parts($url) {
  18. $response = false;
  19. if(preg_match('~https://github.com/([^/]+)/([^/]+)/pull/(\d+)$~', $url, $match)) {
  20. $response = [];
  21. $response['type'] = 'pull';
  22. $response['org'] = $match[1];
  23. $response['repo'] = $match[2];
  24. $response['pull'] = $match[3];
  25. $response['apiurl'] = 'https://api.github.com/repos/'.$response['org'].'/'.$response['repo'].'/pulls/'.$response['pull'];
  26. } elseif(preg_match('~https://github.com/([^/]+)/([^/]+)/issues/(\d+)$~', $url, $match)) {
  27. $response = [];
  28. $response['type'] = 'issue';
  29. $response['org'] = $match[1];
  30. $response['repo'] = $match[2];
  31. $response['issue'] = $match[3];
  32. $response['apiurl'] = 'https://api.github.com/repos/'.$response['org'].'/'.$response['repo'].'/issues/'.$response['issue'];
  33. } elseif(preg_match('~https://github.com/([^/]+)/([^/]+)$~', $url, $match)) {
  34. $response = [];
  35. $response['type'] = 'repo';
  36. $response['org'] = $match[1];
  37. $response['repo'] = $match[2];
  38. $response['apiurl'] = 'https://api.github.com/repos/'.$response['org'].'/'.$response['repo'];
  39. } elseif(preg_match('~https://github.com/([^/]+)/([^/]+)/issues/(\d+)#issuecomment-(\d+)~', $url, $match)) {
  40. $response = [];
  41. $response['type'] = 'comment';
  42. $response['org'] = $match[1];
  43. $response['repo'] = $match[2];
  44. $response['issue'] = $match[3];
  45. $response['comment'] = $match[4];
  46. $response['apiurl'] = 'https://api.github.com/repos/'.$response['org'].'/'.$response['repo'].'/issues/comments/'.$response['comment'];
  47. }
  48. return $response;
  49. }
  50. public static function fetch($http, $url, $creds) {
  51. $parts = self::extract_url_parts($url);
  52. if(!$parts) {
  53. return [
  54. 'error' => 'unsupported_url',
  55. 'error_description' => 'This GitHub URL is not supported',
  56. 'error_code' => 400,
  57. ];
  58. }
  59. $headers = [];
  60. if(isset($creds['github_access_token'])) {
  61. $headers[] = 'Authorization: Bearer ' . $creds['github_access_token'];
  62. }
  63. $response = $http->get($parts['apiurl'], $headers);
  64. if($response['code'] != 200) {
  65. return [
  66. 'error' => 'github_error',
  67. 'error_description' => $response['body'],
  68. 'code' => $response['code'],
  69. ];
  70. }
  71. return [
  72. 'url' => $url,
  73. 'body' => $response['body'],
  74. 'code' => $response['code'],
  75. ];
  76. }
  77. public static function parse($http_response) {
  78. $json = $http_response['body'];
  79. $url = $http_response['url'];
  80. $data = @json_decode($json, true);
  81. if(!$data)
  82. return self::_unknown();
  83. $parts = self::extract_url_parts($url);
  84. if(!$parts)
  85. return self::_unknown();
  86. // Start building the h-entry
  87. $entry = array(
  88. 'type' => ($parts['type'] == 'repo' ? 'repo' : 'entry'),
  89. 'url' => $url,
  90. 'author' => [
  91. 'type' => 'card',
  92. 'name' => null,
  93. 'photo' => null,
  94. 'url' => null
  95. ]
  96. );
  97. if($parts['type'] == 'repo')
  98. $authorkey = 'owner';
  99. else
  100. $authorkey = 'user';
  101. $entry['author']['name'] = $data[$authorkey]['login'];
  102. $entry['author']['photo'] = $data[$authorkey]['avatar_url'];
  103. $entry['author']['url'] = $data[$authorkey]['html_url'];
  104. if($parts['type'] == 'pull') {
  105. $entry['name'] = '#' . $parts['pull'] . ' ' . $data['title'];
  106. } elseif($parts['type'] == 'issue') {
  107. $entry['name'] = '#' . $parts['issue'] . ' ' . $data['title'];
  108. } elseif($parts['type'] == 'repo') {
  109. $entry['name'] = $data['name'];
  110. }
  111. if($parts['type'] == 'repo') {
  112. if(!empty($data['description']))
  113. $entry['summary'] = $data['description'];
  114. }
  115. if($parts['type'] != 'repo' && !empty($data['body'])) {
  116. $parser = new GithubMarkdown();
  117. $entry['content'] = [
  118. 'text' => $data['body'],
  119. 'html' => $parser->parse($data['body'])
  120. ];
  121. }
  122. if($parts['type'] == 'comment') {
  123. $entry['in-reply-to'] = ['https://github.com/'.$parts['org'].'/'.$parts['repo'].'/issues/'.$parts['issue']];
  124. } elseif($parts['type'] == 'pull') {
  125. $entry['in-reply-to'] = ['https://github.com/'.$parts['org'].'/'.$parts['repo']];
  126. } elseif($parts['type'] == 'issue') {
  127. $entry['in-reply-to'] = ['https://github.com/'.$parts['org'].'/'.$parts['repo'].'/issues'];
  128. }
  129. if(!empty($data['labels'])) {
  130. $entry['category'] = array_map(function($l){
  131. return $l['name'];
  132. }, $data['labels']);
  133. }
  134. $entry['published'] = $data['created_at'];
  135. if($entry['type'] != 'repo')
  136. $entry['post-type'] = \p3k\XRay\PostType::discover($entry);
  137. return [
  138. 'data' => $entry,
  139. 'original' => $json,
  140. 'source-format' => 'github',
  141. ];
  142. }
  143. }