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.

166 lines
4.9 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($json, $url) {
  78. $data = @json_decode($json, true);
  79. if(!$data)
  80. return self::_unknown();
  81. $parts = self::extract_url_parts($url);
  82. if(!$parts)
  83. return self::_unknown();
  84. // Start building the h-entry
  85. $entry = array(
  86. 'type' => ($parts['type'] == 'repo' ? 'repo' : 'entry'),
  87. 'url' => $url,
  88. 'author' => [
  89. 'type' => 'card',
  90. 'name' => null,
  91. 'photo' => null,
  92. 'url' => null
  93. ]
  94. );
  95. if($parts['type'] == 'repo')
  96. $authorkey = 'owner';
  97. else
  98. $authorkey = 'user';
  99. $entry['author']['name'] = $data[$authorkey]['login'];
  100. $entry['author']['photo'] = $data[$authorkey]['avatar_url'];
  101. $entry['author']['url'] = $data[$authorkey]['html_url'];
  102. if($parts['type'] == 'pull') {
  103. $entry['name'] = '#' . $parts['pull'] . ' ' . $data['title'];
  104. } elseif($parts['type'] == 'issue') {
  105. $entry['name'] = '#' . $parts['issue'] . ' ' . $data['title'];
  106. } elseif($parts['type'] == 'repo') {
  107. $entry['name'] = $data['name'];
  108. }
  109. if($parts['type'] == 'repo') {
  110. if(!empty($data['description']))
  111. $entry['summary'] = $data['description'];
  112. }
  113. if($parts['type'] != 'repo' && !empty($data['body'])) {
  114. $parser = new GithubMarkdown();
  115. $entry['content'] = [
  116. 'text' => $data['body'],
  117. 'html' => $parser->parse($data['body'])
  118. ];
  119. }
  120. if($parts['type'] == 'comment') {
  121. $entry['in-reply-to'] = ['https://github.com/'.$parts['org'].'/'.$parts['repo'].'/issues/'.$parts['issue']];
  122. }
  123. if(!empty($data['labels'])) {
  124. $entry['category'] = array_map(function($l){
  125. return $l['name'];
  126. }, $data['labels']);
  127. }
  128. $entry['published'] = $data['created_at'];
  129. return [
  130. 'data' => $entry,
  131. 'original' => $json
  132. ];
  133. }
  134. }