| 1: | <?php |
| 2: | |
| 3: | |
| 4: | |
| 5: | |
| 6: | |
| 7: | |
| 8: | |
| 9: | if (!defined('DEBUG_MODE')) { die(); } |
| 10: | |
| 11: | |
| 12: | |
| 13: | |
| 14: | |
| 15: | class Hm_Github_Uid_Cache { |
| 16: | use Hm_Uid_Cache; |
| 17: | } |
| 18: | |
| 19: | |
| 20: | |
| 21: | |
| 22: | class Hm_Handler_process_github_limit_setting extends Hm_Handler_Module { |
| 23: | public function process() { |
| 24: | process_site_setting('github_limit', $this, 'max_source_setting_callback', DEFAULT_GITHUB_PER_SOURCE); |
| 25: | } |
| 26: | } |
| 27: | |
| 28: | |
| 29: | |
| 30: | |
| 31: | class Hm_Handler_process_github_since_setting extends Hm_Handler_Module { |
| 32: | public function process() { |
| 33: | process_site_setting('github_since', $this, 'since_setting_callback',DEFAULT_GITHUB_SINCE); |
| 34: | } |
| 35: | } |
| 36: | |
| 37: | |
| 38: | |
| 39: | |
| 40: | class Hm_Handler_process_unread_github_included extends Hm_Handler_Module { |
| 41: | public function process() { |
| 42: | function unread_github_setting_callback($val) { return $val; } |
| 43: | process_site_setting('unread_exclude_github', $this, 'unread_github_setting_callback', DEFAULT_UNREAD_EXCLUDE_GITHUB, true); |
| 44: | } |
| 45: | } |
| 46: | |
| 47: | |
| 48: | |
| 49: | |
| 50: | class Hm_Handler_github_status extends Hm_Handler_Module { |
| 51: | public function process() { |
| 52: | list($success, $form) = $this->process_form(array('github_repo')); |
| 53: | if ($success) { |
| 54: | $details = $this->user_config->get('github_connect_details', array()); |
| 55: | if (!empty($details)) { |
| 56: | $repos = $this->user_config->get('github_repos', array()); |
| 57: | if (in_array($form['github_repo'], $repos, true)) { |
| 58: | $url = sprintf('https://api.github.com/repos/%s/events?page=1&per_page=1', $form['github_repo']); |
| 59: | $start = microtime(true); |
| 60: | $api = new Hm_API_Curl(); |
| 61: | $data = $api->command($url, array('Authorization: token ' . $details['access_token'])); |
| 62: | if (!empty($data)) { |
| 63: | $this->out('github_status', 'success'); |
| 64: | $this->out('github_connect_time', (microtime(true) - $start)); |
| 65: | $this->out('github_repo', $form['github_repo']); |
| 66: | return; |
| 67: | } |
| 68: | } |
| 69: | } |
| 70: | $this->out('github_status', 'failed'); |
| 71: | $this->out('github_repo', $form['github_repo']); |
| 72: | } |
| 73: | } |
| 74: | } |
| 75: | |
| 76: | |
| 77: | |
| 78: | |
| 79: | class Hm_Handler_load_github_repos extends Hm_Handler_Module { |
| 80: | public function process() { |
| 81: | $this->out('github_repos', $this->user_config->get('github_repos', array())); |
| 82: | } |
| 83: | } |
| 84: | |
| 85: | |
| 86: | |
| 87: | |
| 88: | class Hm_Handler_github_message_action extends Hm_Handler_Module { |
| 89: | public function process() { |
| 90: | |
| 91: | list($success, $form) = $this->process_form(array('action_type', 'message_ids')); |
| 92: | if ($success) { |
| 93: | $id_list = explode(',', $form['message_ids']); |
| 94: | Hm_Github_Uid_Cache::load($this->cache->get('github_read_uids', array(), true)); |
| 95: | foreach ($id_list as $msg_id) { |
| 96: | if (preg_match("/^github_(\d)+_(\d)+$/", $msg_id)) { |
| 97: | $parts = explode('_', $msg_id, 3); |
| 98: | $guid = $parts[2]; |
| 99: | switch($form['action_type']) { |
| 100: | case 'unread': |
| 101: | Hm_Github_Uid_Cache::unread($guid); |
| 102: | break; |
| 103: | case 'read': |
| 104: | case 'delete': |
| 105: | Hm_Github_Uid_Cache::read($guid); |
| 106: | break; |
| 107: | } |
| 108: | } |
| 109: | } |
| 110: | $this->cache->set('github_read_uids', Hm_Github_Uid_Cache::dump(), 0, true); |
| 111: | } |
| 112: | } |
| 113: | } |
| 114: | |
| 115: | |
| 116: | |
| 117: | |
| 118: | class Hm_Handler_github_folders_data extends Hm_Handler_Module { |
| 119: | public function process() { |
| 120: | $this->out('github_connect_details', $this->user_config->get('github_connect_details', array())); |
| 121: | $this->out('github_repos', $this->user_config->get('github_repos', array())); |
| 122: | } |
| 123: | } |
| 124: | |
| 125: | |
| 126: | |
| 127: | |
| 128: | class Hm_Handler_github_event_detail extends Hm_Handler_Module { |
| 129: | public function process() { |
| 130: | list($success, $form) = $this->process_form(array('list_path', 'github_uid')); |
| 131: | if ($success) { |
| 132: | Hm_Github_Uid_Cache::load($this->cache->get('github_read_uids', array(), true)); |
| 133: | $details = $this->user_config->get('github_connect_details', array()); |
| 134: | $repos = $this->user_config->get('github_repos', array()); |
| 135: | $limit = $this->user_config->get('github_limit_setting', DEFAULT_GITHUB_PER_SOURCE); |
| 136: | $repo = mb_substr($form['list_path'], 7); |
| 137: | if (in_array($repo, $repos, true)) { |
| 138: | $url = sprintf('https://api.github.com/repos/%s/events?page=1&per_page='.$limit, $repo); |
| 139: | $api = new Hm_API_Curl(); |
| 140: | $data = $api->command($url, array('Authorization: token ' . $details['access_token'])); |
| 141: | $event = array(); |
| 142: | $uid = explode('_', $form['github_uid'])[2]; |
| 143: | if (is_array($data)) { |
| 144: | foreach ($data as $item) { |
| 145: | if ($item['id'] == $uid) { |
| 146: | $event = $item; |
| 147: | break; |
| 148: | } |
| 149: | } |
| 150: | } |
| 151: | Hm_Github_Uid_Cache::read($item['id']); |
| 152: | $this->cache->set('github_read_uids', Hm_Github_Uid_Cache::dump(), 0, true); |
| 153: | $this->out('github_event_detail', $event); |
| 154: | } |
| 155: | } |
| 156: | } |
| 157: | } |
| 158: | |
| 159: | |
| 160: | |
| 161: | |
| 162: | class Hm_Handler_process_github_authorization extends Hm_Handler_Module { |
| 163: | public function process() { |
| 164: | if (array_key_exists('state', $this->request->get) && $this->request->get['state'] == 'github_authorization') { |
| 165: | if (array_key_exists('code', $this->request->get)) { |
| 166: | $details = github_connect_details($this->config); |
| 167: | $oauth2 = new Hm_Oauth2($details['client_id'], $details['client_secret'], $details['redirect_uri']); |
| 168: | $result = $oauth2->request_token($details['token_url'], $this->request->get['code'], array('Accept: application/json')); |
| 169: | if (count($result) > 0 && array_key_exists('access_token', $result)) { |
| 170: | $this->load_repositories($result['access_token']); |
| 171: | Hm_Msgs::add('Github connection established', 'info'); |
| 172: | $this->user_config->set('github_connect_details', $result); |
| 173: | $user_data = $this->user_config->dump(); |
| 174: | $this->session->set('user_data', $user_data); |
| 175: | $this->session->record_unsaved('Github connection'); |
| 176: | $this->session->secure_cookie($this->request, 'hm_reload_folders', '1'); |
| 177: | $this->session->close_early(); |
| 178: | } |
| 179: | else { |
| 180: | Hm_Msgs::add('An Error Occurred', 'danger'); |
| 181: | } |
| 182: | } |
| 183: | elseif (array_key_exists('error', $this->request->get)) { |
| 184: | Hm_Msgs::add(''.ucwords(str_replace('_', ' ', $this->request->get['error'])), 'danger'); |
| 185: | } |
| 186: | else { |
| 187: | Hm_Msgs::add('An Error Occurred', 'danger'); |
| 188: | } |
| 189: | $this->save_hm_msgs(); |
| 190: | Hm_Dispatch::page_redirect('?page=servers'); |
| 191: | } |
| 192: | } |
| 193: | |
| 194: | public function load_repositories($token) { |
| 195: | $repos = $this->user_config->get('github_repos', array()); |
| 196: | $url = sprintf('https://api.github.com/user/repos'); |
| 197: | $api = new Hm_API_Curl(); |
| 198: | $data = $api->command($url, array('Authorization: token ' . $token)); |
| 199: | foreach ($data as $value) { |
| 200: | if (!in_array($value['full_name'], $repos)) { |
| 201: | $repos[] = $value['full_name']; |
| 202: | } |
| 203: | } |
| 204: | $this->user_config->set('github_repos', $repos); |
| 205: | } |
| 206: | } |
| 207: | |
| 208: | |
| 209: | |
| 210: | |
| 211: | class Hm_Handler_setup_github_connect extends Hm_Handler_Module { |
| 212: | public function process() { |
| 213: | $details = github_connect_details($this->config); |
| 214: | if (!empty($details)) { |
| 215: | $oauth2 = new Hm_Oauth2($details['client_id'], $details['client_secret'], $details['redirect_uri']); |
| 216: | $this->out('github_auth_url', $oauth2->request_authorization_url($details['auth_url'], 'repo', 'github_authorization')); |
| 217: | $this->out('github_connect_details', $this->user_config->get('github_connect_details', array())); |
| 218: | $this->out('github_repos', $this->user_config->get('github_repos', array())); |
| 219: | } |
| 220: | } |
| 221: | } |
| 222: | |
| 223: | |
| 224: | |
| 225: | |
| 226: | class Hm_Handler_github_process_remove_repo extends Hm_Handler_Module { |
| 227: | public function process() { |
| 228: | list($success, $form) = $this->process_form(array('github_repo', 'github_remove_repo')); |
| 229: | if ($success) { |
| 230: | $details = $this->user_config->get('github_connect_details'); |
| 231: | if ($details) { |
| 232: | $repos = $this->user_config->get('github_repos', array()); |
| 233: | if (in_array($form['github_repo'], $repos, true)) { |
| 234: | foreach ($repos as $index => $repo) { |
| 235: | if ($repo === $form['github_repo']) { |
| 236: | unset($repos[$index]); |
| 237: | break; |
| 238: | } |
| 239: | } |
| 240: | $this->user_config->set('github_repos', $repos); |
| 241: | $user_data = $this->user_config->dump(); |
| 242: | $this->session->set('user_data', $user_data); |
| 243: | $this->session->record_unsaved('Github repository removed'); |
| 244: | $this->session->secure_cookie($this->request, 'hm_reload_folders', '1'); |
| 245: | Hm_Msgs::add('Removed repository'); |
| 246: | } |
| 247: | } |
| 248: | } |
| 249: | } |
| 250: | } |
| 251: | |
| 252: | |
| 253: | |
| 254: | |
| 255: | class Hm_Handler_github_process_add_repo extends Hm_Handler_Module { |
| 256: | public function process() { |
| 257: | list($success, $form) = $this->process_form(array('new_github_repo', 'new_github_repo_owner', 'github_add_repo')); |
| 258: | if ($success) { |
| 259: | $details = $this->user_config->get('github_connect_details'); |
| 260: | if ($details) { |
| 261: | $url = sprintf('https://api.github.com/repos/%s/%s/events?page=1&per_page=1', urlencode($form['new_github_repo_owner']), urlencode($form['new_github_repo'])); |
| 262: | $api = new Hm_API_Curl(); |
| 263: | $data = $api->command($url, array('Authorization: token ' . $details['access_token'])); |
| 264: | if (!empty($data)) { |
| 265: | $repos = $this->user_config->get('github_repos', array()); |
| 266: | $new_repo = urlencode($form['new_github_repo_owner']).'/'.urlencode($form['new_github_repo']); |
| 267: | if (!in_array($new_repo, $repos, true)) { |
| 268: | $repos[] = $new_repo; |
| 269: | $this->user_config->set('github_repos', $repos); |
| 270: | $user_data = $this->user_config->dump(); |
| 271: | $this->session->set('user_data', $user_data); |
| 272: | $this->session->record_unsaved('Github repository added'); |
| 273: | $this->session->secure_cookie($this->request, 'hm_reload_folders', '1'); |
| 274: | Hm_Msgs::add('Added repository'); |
| 275: | } |
| 276: | else { |
| 277: | Hm_Msgs::add('Repository is already added', 'warning'); |
| 278: | } |
| 279: | } |
| 280: | else { |
| 281: | Hm_Msgs::add('Could not find that repository/owner combination at github.com', 'warning'); |
| 282: | } |
| 283: | } |
| 284: | } |
| 285: | } |
| 286: | } |
| 287: | |
| 288: | |
| 289: | |
| 290: | |
| 291: | class Hm_Handler_github_disconnect extends Hm_Handler_Module { |
| 292: | public function process() { |
| 293: | if (array_key_exists('github_disconnect', $this->request->post)) { |
| 294: | $this->user_config->set('github_connect_details', array()); |
| 295: | $user_data = $this->user_config->dump(); |
| 296: | $this->session->set('user_data', $user_data); |
| 297: | $this->out('reload_folders', true, false); |
| 298: | $this->session->record_unsaved('Github connection deleted'); |
| 299: | Hm_Msgs::add('Github connection deleted'); |
| 300: | } |
| 301: | } |
| 302: | } |
| 303: | |
| 304: | |
| 305: | |
| 306: | |
| 307: | class Hm_Handler_github_list_data extends Hm_Handler_Module { |
| 308: | public function process() { |
| 309: | list($success, $form) = $this->process_form(array('github_repo')); |
| 310: | if ($success) { |
| 311: | $login_time = $this->session->get('login_time', false); |
| 312: | if ($login_time) { |
| 313: | $this->out('login_time', $login_time); |
| 314: | } |
| 315: | if (array_key_exists('list_path', $this->request->get)) { |
| 316: | if (in_array($this->request->get['list_path'], array('combined_inbox', 'unread'), true)) { |
| 317: | $this->out('list_parent', $this->request->get['list_path']); |
| 318: | } |
| 319: | } |
| 320: | Hm_Github_Uid_Cache::load($this->cache->get('github_read_uids', array(), true)); |
| 321: | $details = $this->user_config->get('github_connect_details'); |
| 322: | $repos = $this->user_config->get('github_repos'); |
| 323: | if (in_array($form['github_repo'], $repos, true) && $details) { |
| 324: | $limit = $this->user_config->get('github_limit_setting', DEFAULT_GITHUB_PER_SOURCE); |
| 325: | $url = sprintf('https://api.github.com/repos/%s/events?page=1&per_page='.$limit, $form['github_repo']); |
| 326: | $api = new Hm_API_Curl(); |
| 327: | $this->out('github_data', $api->command($url, array('Authorization: token ' . $details['access_token']))); |
| 328: | $this->out('github_data_source', $form['github_repo']); |
| 329: | $this->out('github_data_source_id', array_search($form['github_repo'], $repos, true)); |
| 330: | } |
| 331: | if (array_key_exists('list_path', $this->request->get)) { |
| 332: | if ($this->request->get['list_path'] == 'unread') { |
| 333: | $this->out('github_list_since', process_since_argument($this->user_config->get('unread_since_setting', DEFAULT_UNREAD_SINCE))); |
| 334: | } |
| 335: | if ($this->request->get['list_path'] == 'combined_inbox') { |
| 336: | $this->out('github_list_since', process_since_argument($this->user_config->get('all_since_setting', DEFAULT_ALL_SINCE))); |
| 337: | } |
| 338: | if ($this->request->get['list_path'] == 'github_all') { |
| 339: | $this->out('github_list_since', process_since_argument($this->user_config->get('github_since_setting', DEFAULT_GITHUB_SINCE))); |
| 340: | } |
| 341: | } |
| 342: | if (array_key_exists('github_unread', $this->request->post) && $this->request->post['github_unread']) { |
| 343: | $this->out('github_unread', true); |
| 344: | } |
| 345: | } |
| 346: | } |
| 347: | } |
| 348: | |
| 349: | |
| 350: | |
| 351: | |
| 352: | class Hm_Handler_github_list_type extends Hm_Handler_Module { |
| 353: | public function process() { |
| 354: | $repos = $this->user_config->get('github_repos', array()); |
| 355: | $excluded = $this->user_config->get('unread_exclude_github_setting', DEFAULT_UNREAD_EXCLUDE_GITHUB); |
| 356: | $github_list = false; |
| 357: | $parent = ''; |
| 358: | if (array_key_exists('list_parent', $this->request->get)) { |
| 359: | $parent = $this->request->get['list_parent']; |
| 360: | } |
| 361: | if (array_key_exists('list_path', $this->request->get)) { |
| 362: | $path = $this->request->get['list_path']; |
| 363: | if ($this->page == 'message_list' && preg_match("/^github_(.+)$/", $path)) { |
| 364: | $github_list = true; |
| 365: | if ($path == 'github_all') { |
| 366: | $this->out('list_path', 'github_all', false); |
| 367: | $this->out('list_parent', $parent, false); |
| 368: | $this->out('mailbox_list_title', array('Github', 'All')); |
| 369: | $this->out('message_list_since', $this->user_config->get('github_since_setting', DEFAULT_GITHUB_SINCE)); |
| 370: | $this->out('per_source_limit', $this->user_config->get('github_limit_setting', DEFAULT_GITHUB_PER_SOURCE)); |
| 371: | foreach ($repos as $repo) { |
| 372: | $this->append('data_sources', array('type' => 'github', 'name' => $repo, 'id' => $repo)); |
| 373: | } |
| 374: | } |
| 375: | else { |
| 376: | $repo = mb_substr($path, 7); |
| 377: | $this->out('list_parent', $parent, false); |
| 378: | if ($parent == 'github_all') { |
| 379: | $this->out('mailbox_list_title', array(urldecode($repo))); |
| 380: | } |
| 381: | else { |
| 382: | $this->out('mailbox_list_title', array('Github', urldecode($repo))); |
| 383: | $this->out('list_path', $path, false); |
| 384: | } |
| 385: | $this->out('custom_list_controls', ' '); |
| 386: | $this->append('data_sources', array('type' => 'github', 'name' => $repo, 'id' => $repo)); |
| 387: | } |
| 388: | } |
| 389: | elseif ($this->page == 'message_list' && ($path == 'combined_inbox' || $path == 'unread')) { |
| 390: | $github_list = true; |
| 391: | if (!$excluded || $path == 'combined_inbox') { |
| 392: | foreach ($repos as $repo) { |
| 393: | $this->append('data_sources', array('type' => 'github', 'name' => $repo, 'id' => $repo)); |
| 394: | } |
| 395: | } |
| 396: | } |
| 397: | elseif ($this->page == 'message' && preg_match("/^github_(.+)$/", $path)) { |
| 398: | if (!$parent) { |
| 399: | $repo = mb_substr($path, 7); |
| 400: | $this->out('mailbox_list_title', array('Github', urldecode($repo))); |
| 401: | } |
| 402: | } |
| 403: | } |
| 404: | if (!$github_list) { |
| 405: | foreach ($repos as $repo) { |
| 406: | if (!$excluded) { |
| 407: | $this->append('data_sources', array('group' => 'background', 'type' => 'github', 'name' => 'Github', 'id' => $repo)); |
| 408: | } |
| 409: | } |
| 410: | } |
| 411: | } |
| 412: | } |
| 413: | |
| 414: | |
| 415: | |
| 416: | |
| 417: | class Hm_Output_github_folders extends Hm_Output_Module { |
| 418: | protected function output() { |
| 419: | $details = $this->get('github_connect_details', array()); |
| 420: | if (!empty($details)) { |
| 421: | $res = '<li class="menu_github_all"><a class="unread_link" href="?page=message_list&list_path=github_all">'; |
| 422: | if (!$this->get('hide_folder_icons')) { |
| 423: | $res .= '<i class="bi bi-code-slash account_icon"></i> '; |
| 424: | } |
| 425: | $res .= $this->trans('All').'</a></li>'; |
| 426: | foreach ($this->get('github_repos', array()) as $repo) { |
| 427: | $res .= '<li class="menu_github_'.$this->html_safe($repo).'"><a class="unread_link" href="?page=message_list&list_path=github_'.$this->html_safe($repo).'">'; |
| 428: | if (!$this->get('hide_folder_icons')) { |
| 429: | $res .= '<i class="bi bi-code-slash account_icon"></i> '; |
| 430: | } |
| 431: | $res .= $this->html_safe(explode('/', urldecode($repo))[1]).'</a></li>'; |
| 432: | } |
| 433: | $this->append('folder_sources', array('github_folders', $res)); |
| 434: | } |
| 435: | } |
| 436: | } |
| 437: | |
| 438: | |
| 439: | |
| 440: | |
| 441: | class Hm_Output_filter_github_data extends Hm_Output_Module { |
| 442: | protected function output() { |
| 443: | $res = array(); |
| 444: | $login_time = false; |
| 445: | $unread_only = false; |
| 446: | $show_icons = $this->get('msg_list_icons'); |
| 447: | if ($this->get('login_time')) { |
| 448: | $login_time = $this->get('login_time'); |
| 449: | } |
| 450: | if ($this->get('list_path', '') == 'unread' || $this->get('github_unread', false)) { |
| 451: | $unread_only = true; |
| 452: | } |
| 453: | $repo_id = $this->get('github_data_source_id'); |
| 454: | $repo = $this->get('github_data_source', 'Github'); |
| 455: | $repo_parts = explode('/', $repo); |
| 456: | $repo_name = $repo_parts[1]; |
| 457: | $cutoff = $this->get('github_list_since', ''); |
| 458: | if ($cutoff) { |
| 459: | $cutoff = strtotime($cutoff); |
| 460: | } |
| 461: | else { |
| 462: | $cutoff = 0; |
| 463: | } |
| 464: | $list_parent = false; |
| 465: | if ($this->get('list_parent', '')) { |
| 466: | $list_parent = $this->get('list_parent'); |
| 467: | } |
| 468: | elseif ($this->get('list_path') == 'github_all') { |
| 469: | $list_parent = $this->get('list_path'); |
| 470: | } |
| 471: | foreach ($this->get('github_data', array()) as $event) { |
| 472: | if (!is_array($event) || !array_key_exists('id', $event)) { |
| 473: | continue; |
| 474: | } |
| 475: | $row_class = 'github'; |
| 476: | $id = 'github_'.$repo_id.'_'.$event['id']; |
| 477: | $subject = build_github_subject($event, $this); |
| 478: | $url = '?page=message&uid='.$this->html_safe($id).'&list_path=github_'.$this->html_safe($repo); |
| 479: | if ($list_parent) { |
| 480: | $url .= '&list_parent='.$this->html_safe($list_parent); |
| 481: | } |
| 482: | $from = $event['actor']['login']; |
| 483: | $ts = strtotime($event['created_at']); |
| 484: | if ($ts < $cutoff) { |
| 485: | continue; |
| 486: | } |
| 487: | if (Hm_Github_Uid_Cache::is_read($event['id'])) { |
| 488: | $flags = array(); |
| 489: | } |
| 490: | elseif (Hm_Github_Uid_Cache::is_unread($event['id'])) { |
| 491: | $flags = array('unseen'); |
| 492: | $row_class .= ' unseen'; |
| 493: | } |
| 494: | elseif ($ts && $login_time && $ts <= $login_time) { |
| 495: | $flags = array(); |
| 496: | } |
| 497: | else { |
| 498: | $row_class .= ' unseen'; |
| 499: | $flags = array('unseen'); |
| 500: | } |
| 501: | if ($unread_only && !in_array('unseen', $flags)) { |
| 502: | continue; |
| 503: | } |
| 504: | $date = date('r', $ts); |
| 505: | $style = $this->get('news_list_style') ? 'news' : 'email'; |
| 506: | if ($this->get('is_mobile')) { |
| 507: | $style = 'news'; |
| 508: | } |
| 509: | $row_class .= ' '.$repo_name; |
| 510: | $icon = 'code'; |
| 511: | if (!$show_icons) { |
| 512: | $icon = ''; |
| 513: | } |
| 514: | if ($style == 'news') { |
| 515: | $res[$id] = message_list_row(array( |
| 516: | array('checkbox_callback', $id), |
| 517: | array('icon_callback', $flags), |
| 518: | array('subject_callback', $subject, $url, $flags, $icon), |
| 519: | array('safe_output_callback', 'source', $repo_name), |
| 520: | array('safe_output_callback', 'from', $from), |
| 521: | array('date_callback', translate_time_str(human_readable_interval($date), $this), $ts), |
| 522: | ), |
| 523: | $id, |
| 524: | $style, |
| 525: | $this, |
| 526: | $row_class |
| 527: | ); |
| 528: | } |
| 529: | else { |
| 530: | $res[$id] = message_list_row(array( |
| 531: | array('checkbox_callback', $id), |
| 532: | array('safe_output_callback', 'source', $repo_name, $icon), |
| 533: | array('safe_output_callback', 'from', $from), |
| 534: | array('subject_callback', $subject, $url, $flags), |
| 535: | array('date_callback', translate_time_str(human_readable_interval($date), $this), $ts), |
| 536: | array('icon_callback', $flags) |
| 537: | ), |
| 538: | $id, |
| 539: | $style, |
| 540: | $this, |
| 541: | $row_class |
| 542: | ); |
| 543: | } |
| 544: | } |
| 545: | $this->out('formatted_message_list', $res); |
| 546: | $this->out('github_server_id', $repo_id); |
| 547: | } |
| 548: | } |
| 549: | |
| 550: | |
| 551: | |
| 552: | |
| 553: | class Hm_Output_github_add_repo extends Hm_Output_Module { |
| 554: | protected function output() { |
| 555: | $res = ''; |
| 556: | $details = $this->get('github_connect_details', array()); |
| 557: | if (!empty($details)) { |
| 558: | $res = '<div class="configured_server col-12 col-lg-4 mb-4 mt-3"> |
| 559: | <div class="subtitle">'.$this->trans('Add a Repository').'</div>'. |
| 560: | '<form method="POST">'. |
| 561: | '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />'. |
| 562: | '<label class="screen_reader">'.$this->trans('Name').'</label>'. |
| 563: | '<input type="text" value="" class="form-control mb-4" placeholder="'.$this->trans('Name').'" name="new_github_repo" />'. |
| 564: | '<label class="screen_reader">'.$this->trans('Owner').'</label>'. |
| 565: | '<input type="text" value="" class="form-control mb-4" placeholder="'.$this->trans('Owner').'" name="new_github_repo_owner" />'. |
| 566: | '<input type="submit" class="btn btn-primary" name="github_add_repo" value="Add" />'. |
| 567: | '</form></div>'; |
| 568: | $res .= '<div class="configured_server mt-2"><h5 class="server_title">'.$this->trans('Repositories').'</h5></div>'. |
| 569: | '<table class="table">'; |
| 570: | foreach ($this->get('github_repos', array()) as $repo) { |
| 571: | $res .= '<tr>'. |
| 572: | '<td class="col-sm-2 col-lg-1 py-2 align-middle">'. |
| 573: | '<form class="remove_repo" method="POST">'. |
| 574: | '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />'. |
| 575: | '<input type="hidden" name="github_repo" value="'.$this->html_safe($repo).'" />'. |
| 576: | '<input type="submit" name="github_remove_repo" value="'.$this->trans('Remove').'" class="github_remove_repo btn btn-outline-danger btn-sm" />'. |
| 577: | '</form>'. |
| 578: | '</td>'. |
| 579: | '<td>'.$this->html_safe($repo).'</td>'. |
| 580: | '<tr>'; |
| 581: | } |
| 582: | $res .= '</table></div></div><div class="end_float"></div></div>'; |
| 583: | } |
| 584: | return $res; |
| 585: | } |
| 586: | } |
| 587: | |
| 588: | |
| 589: | |
| 590: | |
| 591: | class Hm_Output_filter_github_event_detail extends Hm_Output_Module { |
| 592: | protected function output() { |
| 593: | $details = $this->get('github_event_detail', array()); |
| 594: | if (!empty($details)) { |
| 595: | if (array_key_exists('payload', $details)) { |
| 596: | $body = github_parse_payload($details, $this); |
| 597: | $headers = github_parse_headers($details, $this); |
| 598: | } |
| 599: | $this->out('github_msg_text', $headers.$body); |
| 600: | } |
| 601: | } |
| 602: | } |
| 603: | |
| 604: | |
| 605: | |
| 606: | |
| 607: | class Hm_Output_filter_github_status extends Hm_Output_Module { |
| 608: | protected function output() { |
| 609: | if ($this->get('github_status') == 'success') { |
| 610: | $this->out('github_status_display', '<span class="online">'.$this->trans('Connected').'</span> in '.round($this->get('github_connect_time'), 3)); |
| 611: | } |
| 612: | else { |
| 613: | $this->out('github_status_display', '<span class="down">'.$this->trans('Down').'</span>'); |
| 614: | } |
| 615: | $this->out('github_status_repo', $this->get('github_repo', '')); |
| 616: | } |
| 617: | }; |
| 618: | |
| 619: | |
| 620: | |
| 621: | |
| 622: | class Hm_Output_display_github_status extends Hm_Output_Module { |
| 623: | protected function output() { |
| 624: | $res = ''; |
| 625: | $repos = $this->get('github_repos', array()); |
| 626: | if (!empty($repos)) { |
| 627: | foreach ($repos as $repo) { |
| 628: | $res .= '<tr><td class="github_repo" data-id="'.$this->html_safe($repo).'">'.$this->trans('Github repo').'</td><td>'.$this->html_safe($repo).'</td><td class="github_'.$this->html_safe($repo).'"></td></tr>'; |
| 629: | } |
| 630: | } |
| 631: | return $res; |
| 632: | } |
| 633: | } |
| 634: | |
| 635: | |
| 636: | |
| 637: | |
| 638: | class Hm_Output_github_connect_section extends Hm_Output_Module { |
| 639: | protected function output() { |
| 640: | $details = $this->get('github_connect_details', array()); |
| 641: | $res = '<div class="github_connect"><div data-target=".github_connect_section" class="server_section border-bottom cursor-pointer px-1 py-3 pe-auto"> |
| 642: | <a href="#" class="pe-auto"> |
| 643: | <i class="bi bi-github me-3"></i> |
| 644: | <b>'.$this->trans('Github Connect').'</b> |
| 645: | </a> |
| 646: | </div>'; |
| 647: | |
| 648: | $res .= '<div class="github_connect_section"><div class="add_server">'; |
| 649: | |
| 650: | if (empty($details)) { |
| 651: | $res .= 'Connect to Github<br /><br />'; |
| 652: | $res .= '<a class="btn btn-secondary" href="'.$this->get('github_auth_url', '').'" data-external="true">'.$this->trans('Enable').'</a></div></div><div class="end_float"</div>'; |
| 653: | } |
| 654: | else { |
| 655: | $res .='<h6>'. $this->trans('Already connected').'</h6>'; |
| 656: | $res .= '<form id="github_disconnect_form" method="POST">'; |
| 657: | $res .= '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />'; |
| 658: | $res .= '<input type="submit" name="github_disconnect" class="github_disconnect btn btn-secondary" value="'.$this->trans('Disconnect').'" />'; |
| 659: | $res .= '</form>'; |
| 660: | } |
| 661: | return $res.'</div>'; |
| 662: | } |
| 663: | } |
| 664: | |
| 665: | |
| 666: | |
| 667: | |
| 668: | class Hm_Output_unread_github_included_setting extends Hm_Output_Module { |
| 669: | protected function output() { |
| 670: | $settings = $this->get('user_settings'); |
| 671: | if (array_key_exists('unread_exclude_github', $settings) && $settings['unread_exclude_github']) { |
| 672: | $checked = ' checked="checked"'; |
| 673: | } |
| 674: | else { |
| 675: | $checked = ''; |
| 676: | } |
| 677: | return '<tr class="unread_setting"><td><label for="unread_exclude_github">'.$this->trans('Exclude unread Github notices').'</label></td>'. |
| 678: | '<td><input class="form-check-input" type="checkbox" '.$checked.' value="1" id="unread_exclude_github" name="unread_exclude_github" /></td></tr>'; |
| 679: | } |
| 680: | } |
| 681: | |
| 682: | |
| 683: | |
| 684: | |
| 685: | class Hm_Output_start_github_settings extends Hm_Output_Module { |
| 686: | protected function output() { |
| 687: | return '<tr><td colspan="2" data-target=".github_all_setting" class="settings_subtitle cursor-pointer border-bottom p-2">'. |
| 688: | '<i class="bi bi-github fs-5 me-2"></i>'.$this->trans('Github Settings').'</td></tr>'; |
| 689: | } |
| 690: | } |
| 691: | |
| 692: | |
| 693: | |
| 694: | |
| 695: | class Hm_Output_github_since_setting extends Hm_Output_Module { |
| 696: | protected function output() { |
| 697: | $since = DEFAULT_GITHUB_SINCE; |
| 698: | $settings = $this->get('user_settings'); |
| 699: | if (array_key_exists('github_since', $settings) && $settings['github_since']) { |
| 700: | $since = $settings['github_since']; |
| 701: | } |
| 702: | return '<tr class="github_all_setting"><td><label for="github_since">'.$this->trans('Show Github notices received since').'</label></td>'. |
| 703: | '<td>'.message_since_dropdown($since, 'github_since', $this, DEFAULT_GITHUB_SINCE).'</td></tr>'; |
| 704: | } |
| 705: | } |
| 706: | |
| 707: | |
| 708: | |
| 709: | |
| 710: | class Hm_Output_github_limit_setting extends Hm_Output_Module { |
| 711: | protected function output() { |
| 712: | $limit = DEFAULT_GITHUB_PER_SOURCE; |
| 713: | $settings = $this->get('user_settings'); |
| 714: | if (array_key_exists('github_limit', $settings)) { |
| 715: | $limit = $settings['github_limit']; |
| 716: | } |
| 717: | return '<tr class="github_all_setting"><td><label for="github_limit">'.$this->trans('Max Github notices per repository').'</label></td>'. |
| 718: | '<td class="d-flex"><input type="text" id="github_limit" name="github_limit" size="2" value="'.$this->html_safe($limit).'" data-default-value="'.DEFAULT_GITHUB_PER_SOURCE.'"/></td></tr>'; |
| 719: | } |
| 720: | } |
| 721: | |
| 722: | |
| 723: | |
| 724: | |
| 725: | if (!hm_exists('github_connect_details')) { |
| 726: | function github_connect_details($config) { |
| 727: | $confs = $config->dump(); |
| 728: | return $confs['github']; |
| 729: | }} |
| 730: | |
| 731: | |
| 732: | |
| 733: | |
| 734: | if (!hm_exists('build_github_subject')) { |
| 735: | function build_github_subject($event, $output_mod) { |
| 736: | $ref = ''; |
| 737: | if (array_key_exists('payload', $event) && array_key_exists('ref', $event['payload'])) { |
| 738: | $ref = sprintf(' / %s', preg_replace("/^refs\/heads\//", '', $event['payload']['ref'])); |
| 739: | } |
| 740: | $pre = '['.$output_mod->html_safe(trim(str_replace('Event', '', trim(preg_replace("/([A-Z])/", " $1", $event['type']))))).']'; |
| 741: | $post = ''; |
| 742: | $max = 100; |
| 743: | switch (mb_strtolower($event['type'])) { |
| 744: | case 'issuecommentevent': |
| 745: | $post = $event['payload']['issue']['title']; |
| 746: | break; |
| 747: | case 'issuesevent': |
| 748: | $post = $event['payload']['issue']['title'].' - '.$event['payload']['action']; |
| 749: | break; |
| 750: | case 'pushevent': |
| 751: | if (count($event['payload']['commits']) > 1) { |
| 752: | $post .= sprintf($output_mod->trans('%d commits: '), count($event['payload']['commits'])); |
| 753: | } |
| 754: | else { |
| 755: | $post .= sprintf($output_mod->trans('%d commit: '), count($event['payload']['commits'])); |
| 756: | } |
| 757: | $post .= mb_substr($event['payload']['commits'][0]['message'], 0, $max); |
| 758: | break; |
| 759: | case 'watchevent': |
| 760: | if ($event['payload']['action'] == 'started') { |
| 761: | $post .= sprintf($output_mod->trans('%s started watching this repo'), $event['actor']['login']); |
| 762: | } |
| 763: | else { |
| 764: | $post .= sprintf($output_mod->trans('%s stopped watching this repo'), $event['actor']['login']); |
| 765: | } |
| 766: | break; |
| 767: | case 'forkevent': |
| 768: | $post = sprintf($output_mod->trans("%s forked %s"), $event['actor']['login'], $event['repo']['name']); |
| 769: | break; |
| 770: | case 'createevent': |
| 771: | $post = sprintf($output_mod->trans("%s repository created"), $event['repo']['name']); |
| 772: | break; |
| 773: | case 'pullrequestevent': |
| 774: | $post = mb_substr($event['payload']['pull_request']['body'], 0, $max); |
| 775: | break; |
| 776: | case 'commitcommentevent': |
| 777: | $post = mb_substr($event['payload']['comment']['body'], 0, $max); |
| 778: | break; |
| 779: | case 'releaseevent': |
| 780: | $post = mb_substr($event['payload']['release']['name'], 0, $max); |
| 781: | default: |
| 782: | break; |
| 783: | } |
| 784: | if ($ref) { |
| 785: | $post .= $output_mod->html_safe($ref); |
| 786: | } |
| 787: | return $pre.' '.$post; |
| 788: | }} |
| 789: | |
| 790: | |
| 791: | |
| 792: | |
| 793: | if (!hm_exists('github_parse_headers')) { |
| 794: | function github_parse_headers($data, $output_mod) { |
| 795: | $res = '<div class="msg_headers d-flex flex-column border-bottom border-2 border-secondary-subtle pb-3 mb-3">'; |
| 796: | if (array_key_exists('type', $data)) { |
| 797: | $type = build_github_subject($data, $output_mod); |
| 798: | } |
| 799: | else { |
| 800: | $type = '[Unknown Type]'; |
| 801: | } |
| 802: | if (array_key_exists('created_at', $data)) { |
| 803: | $date = sprintf("%s (%s)", date('r', strtotime($data['created_at'])), human_readable_interval($data['created_at'])); |
| 804: | } |
| 805: | else { |
| 806: | $date = '[No date]'; |
| 807: | } |
| 808: | $repo_link = ''; |
| 809: | $from_link = ''; |
| 810: | |
| 811: | if (array_key_exists('actor', $data) && array_key_exists('login', $data['actor'])) { |
| 812: | $from = $data['actor']['login']; |
| 813: | $from_link = sprintf(' - <a href="https://github.com/%s" target="_blank" rel="noopener">https://github.com/%s</a>', $output_mod->html_safe($from), $output_mod->html_safe($from)); |
| 814: | } |
| 815: | else { |
| 816: | $from = '[No From]'; |
| 817: | } |
| 818: | if (array_key_exists('repo', $data) && array_key_exists('name', $data['repo'])) { |
| 819: | $name = $data['repo']['name']; |
| 820: | $repo_link = sprintf(' - <a href="https://github.com/%s" target="_blank" rel="noopener">https://github.com/%s</a>', $output_mod->html_safe($name), $output_mod->html_safe($name)); |
| 821: | } |
| 822: | else { |
| 823: | $name = '[No Repo]'; |
| 824: | } |
| 825: | $res .= '<div class="header_subject d-flex justify-content-center"><h4 class="text-center mb-0 fw-bold">'.$output_mod->html_safe($type).'</h4></div>'; |
| 826: | $res .= '<div class="header_date d-flex align-items-center py-1"><span class="fw-semibold me-2 text-nowrap">'.$output_mod->trans('Date').':</span><span class="text-break">'.$output_mod->html_safe($date).'</span></div>'; |
| 827: | $res .= '<div class="header_from d-flex align-items-center py-1"><span class="fw-semibold me-2 text-nowrap">'.$output_mod->trans('Author').':</span><span class="text-break">'.$output_mod->html_safe($from).$from_link.'</span></div>'; |
| 828: | $res .= '<div class="d-flex align-items-center py-1"><span class="fw-semibold me-2 text-nowrap">'.$output_mod->trans('Repository').':</span><span class="text-break">'.$output_mod->html_safe($name).$repo_link.'</span></div>'; |
| 829: | $res .= '</div>'; |
| 830: | return $res; |
| 831: | }} |
| 832: | |
| 833: | |
| 834: | |
| 835: | |
| 836: | if (!hm_exists('github_parse_payload')) { |
| 837: | function github_parse_payload($data, $output_mod) { |
| 838: | $type = false; |
| 839: | if (array_key_exists('type', $data)) { |
| 840: | $type = $data['type']; |
| 841: | } |
| 842: | |
| 843: | |
| 844: | |
| 845: | |
| 846: | |
| 847: | $data = $data['payload']; |
| 848: | $content = payload_search($data); |
| 849: | $res = '<div class="msg_text_inner">'; |
| 850: | foreach ($content as $vals) { |
| 851: | $res .= '<div class="github_para">'; |
| 852: | if (array_key_exists('name', $vals)) { |
| 853: | $res .= $output_mod->html_safe($vals['name']); |
| 854: | $res .= '</div><div class="github_para">'; |
| 855: | } |
| 856: | if (array_key_exists('body', $vals)) { |
| 857: | $res .= $output_mod->html_safe(wordwrap($vals['body'], 100)); |
| 858: | } |
| 859: | if (array_key_exists('message', $vals)) { |
| 860: | $res .= $output_mod->html_safe(wordwrap($vals['message'], 100)); |
| 861: | } |
| 862: | if (array_key_exists('html_url', $vals)) { |
| 863: | $res .= sprintf('<div class="github_link"><a href="%s" data-external="true">%s</a></div>', |
| 864: | $output_mod->html_safe($vals['html_url']), $output_mod->html_safe($vals['html_url'])); |
| 865: | } |
| 866: | if (array_key_exists('url', $vals) && array_key_exists('sha', $vals)) { |
| 867: | $url = str_replace(array('commits', 'https://api.github.com/repos'), array('commit', 'https://github.com'), $vals['url']); |
| 868: | $res .= sprintf('<div class="github_link"><a href="%s" target="_blank" rel="noopener">%s</a></div>', |
| 869: | $output_mod->html_safe($url), $output_mod->html_safe($vals['sha'])); |
| 870: | } |
| 871: | $res .= '</div>'; |
| 872: | } |
| 873: | $res .= '</div>'; |
| 874: | return $res; |
| 875: | }} |
| 876: | |
| 877: | |
| 878: | |
| 879: | |
| 880: | if (!hm_exists('payload_search')) { |
| 881: | function payload_search($data) { |
| 882: | $res = array(); |
| 883: | $data_flds = array('url', 'sha', 'body', 'description', 'message', 'name'); |
| 884: | foreach($data as $vals) { |
| 885: | if (is_array($vals)) { |
| 886: | $item = array(); |
| 887: | foreach ($data_flds as $fld) { |
| 888: | if (array_key_exists($fld, $vals)) { |
| 889: | $item[$fld] = $vals[$fld]; |
| 890: | } |
| 891: | } |
| 892: | if (!empty($item)) { |
| 893: | if (array_key_exists('html_url', $data)) { |
| 894: | $item['html_url'] = $vals['html_url']; |
| 895: | } |
| 896: | } |
| 897: | else { |
| 898: | $res = array_merge($res, payload_search($vals)); |
| 899: | } |
| 900: | if (count($item) > 0) { |
| 901: | $res[] = $item; |
| 902: | } |
| 903: | } |
| 904: | } |
| 905: | return $res; |
| 906: | }} |
| 907: | |