1<?php
2
3/**
4 * Github modules
5 * @package modules
6 * @subpackage github
7 */
8
9if (!defined('DEBUG_MODE')) { die(); }
10
11/**
12 * Used to cache "read" github items
13 * @subpackage github/lib
14 */
15class Hm_Github_Uid_Cache {
16    use Hm_Uid_Cache;
17}
18
19/**
20 * @subpackage github/handler
21 */
22class 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_PER_SOURCE);
25    }
26}
27
28/**
29 * @subpackage github/handler
30 */
31class Hm_Handler_process_github_since_setting extends Hm_Handler_Module {
32    public function process() {
33        process_site_setting('github_since', $this, 'since_setting_callback');
34    }
35}
36
37/**
38 * @subpackage github/handler
39 */
40class 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', false, true);
44    }
45}
46
47/**
48 * @subpackage github/handler
49 */
50class 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 * @subpackage github/handler
78 */
79class 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 * @subpackage github/handler
87 */
88class 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 * @subpackage github/handler
117 */
118class 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 * @subpackage github/handler
127 */
128class 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_PER_SOURCE);
136            $repo = 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 = substr($form['github_uid'], 9);
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 * @subpackage github/handler
161 */
162class 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                    Hm_Msgs::add('Github connection established');
171                    $this->user_config->set('github_connect_details', $result);
172                    $user_data = $this->user_config->dump();
173                    $this->session->set('user_data', $user_data);
174                    $this->session->record_unsaved('Github connection');
175                    $this->session->secure_cookie($this->request, 'hm_reload_folders', '1');
176                    $this->session->close_early();
177                }
178                else {
179                    Hm_Msgs::add('ERRAn Error Occurred');
180                }
181            }
182            elseif (array_key_exists('error', $this->request->get)) {
183                Hm_Msgs::add('ERR'.ucwords(str_replace('_', ' ', $this->request->get['error'])));
184            }
185            else {
186                Hm_Msgs::add('ERRAn Error Occurred');
187            }
188            $msgs = Hm_Msgs::get();
189            $this->session->secure_cookie($this->request, 'hm_msgs', base64_encode(serialize($msgs)));
190            Hm_Dispatch::page_redirect('?page=servers');
191        }
192    }
193}
194
195/**
196 * @subpackage github/handler
197 */
198class Hm_Handler_setup_github_connect extends Hm_Handler_Module {
199    public function process() {
200        $details = github_connect_details($this->config);
201        if (!empty($details)) {
202            $oauth2 = new Hm_Oauth2($details['client_id'], $details['client_secret'], $details['redirect_uri']);
203            $this->out('github_auth_url', $oauth2->request_authorization_url($details['auth_url'], 'repo', 'github_authorization'));
204            $this->out('github_connect_details', $this->user_config->get('github_connect_details', array()));
205            $this->out('github_repos', $this->user_config->get('github_repos', array()));
206        }
207    }
208}
209
210/**
211 * @subpackage github/handler
212 */
213class Hm_Handler_github_process_remove_repo extends Hm_Handler_Module {
214    public function process() {
215        list($success, $form) = $this->process_form(array('github_repo', 'github_remove_repo'));
216        if ($success) {
217            $details = $this->user_config->get('github_connect_details');
218            if ($details) {
219                $repos = $this->user_config->get('github_repos', array());
220                if (in_array($form['github_repo'], $repos, true)) {
221                    foreach ($repos as $index => $repo) {
222                        if ($repo === $form['github_repo']) {
223                            unset($repos[$index]);
224                            break;
225                        }
226                    }
227                    $this->user_config->set('github_repos', $repos);
228                    $user_data = $this->user_config->dump();
229                    $this->session->set('user_data', $user_data);
230                    $this->session->record_unsaved('Github repository removed');
231                    $this->session->secure_cookie($this->request, 'hm_reload_folders', '1');
232                    Hm_Msgs::add('Removed repository');
233                }
234            }
235        }
236    }
237}
238
239/**
240 * @subpackage github/handler
241 */
242class Hm_Handler_github_process_add_repo extends Hm_Handler_Module {
243    public function process() {
244        list($success, $form) = $this->process_form(array('new_github_repo', 'new_github_repo_owner', 'github_add_repo'));
245        if ($success) {
246            $details = $this->user_config->get('github_connect_details');
247            if ($details) {
248                $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']));
249                $api = new Hm_API_Curl();
250                $data = $api->command($url, array('Authorization: token ' . $details['access_token']));
251                if (!empty($data)) {
252                    $repos = $this->user_config->get('github_repos', array());
253                    $new_repo = urlencode($form['new_github_repo_owner']).'/'.urlencode($form['new_github_repo']);
254                    if (!in_array($new_repo, $repos, true)) {
255                        $repos[] = $new_repo;
256                        $this->user_config->set('github_repos', $repos);
257                        $user_data = $this->user_config->dump();
258                        $this->session->set('user_data', $user_data);
259                        $this->session->record_unsaved('Github repository added');
260                        $this->session->secure_cookie($this->request, 'hm_reload_folders', '1');
261                        Hm_Msgs::add('Added repository');
262                    }
263                    else {
264                        Hm_Msgs::add('ERRRepository is already added');
265                    }
266                }
267                else {
268                    Hm_Msgs::add('ERRCould not find that repository/owner combination at github.com');
269                }
270            }
271        }
272    }
273}
274
275/**
276 * @subpackage github/handler
277 */
278class Hm_Handler_github_disconnect extends Hm_Handler_Module {
279    public function process() {
280        if (array_key_exists('github_disconnect', $this->request->post)) {
281            $this->user_config->set('github_connect_details', array());
282            $user_data = $this->user_config->dump();
283            $this->session->set('user_data', $user_data);
284            $this->out('reload_folders', true, false);
285            $this->session->record_unsaved('Github connection deleted');
286            Hm_Msgs::add('Github connection deleted');
287        }
288    }
289}
290
291/**
292 * @subpackage github/handler
293 */
294class Hm_Handler_github_list_data extends Hm_Handler_Module {
295    public function process() {
296        list($success, $form) = $this->process_form(array('github_repo'));
297        if ($success) {
298            $login_time = $this->session->get('login_time', false);
299            if ($login_time) {
300                $this->out('login_time', $login_time);
301            }
302            if (array_key_exists('list_path', $this->request->get)) {
303                if (in_array($this->request->get['list_path'], array('combined_inbox', 'unread'), true)) {
304                    $this->out('list_parent', $this->request->get['list_path']);
305                }
306            }
307            Hm_Github_Uid_Cache::load($this->cache->get('github_read_uids', array(), true));
308            $details = $this->user_config->get('github_connect_details');
309            $repos = $this->user_config->get('github_repos');
310            if (in_array($form['github_repo'], $repos, true) && $details) {
311                $limit = $this->user_config->get('github_limit_setting', DEFAULT_PER_SOURCE);
312                $url = sprintf('https://api.github.com/repos/%s/events?page=1&per_page='.$limit, $form['github_repo']);
313                $api = new Hm_API_Curl();
314                $this->out('github_data', $api->command($url, array('Authorization: token ' . $details['access_token'])));
315                $this->out('github_data_source', $form['github_repo']);
316                $this->out('github_data_source_id', array_search($form['github_repo'], $repos, true));
317            }
318            if (array_key_exists('list_path', $this->request->get)) {
319                if ($this->request->get['list_path'] == 'unread') {
320                    $this->out('github_list_since', process_since_argument($this->user_config->get('unread_since_setting', DEFAULT_SINCE)));
321                }
322                if ($this->request->get['list_path'] == 'combined_inbox') {
323                    $this->out('github_list_since', process_since_argument($this->user_config->get('all_since_setting', DEFAULT_SINCE)));
324                }
325                if ($this->request->get['list_path'] == 'github_all') {
326                    $this->out('github_list_since', process_since_argument($this->user_config->get('github_since_setting', DEFAULT_SINCE)));
327                }
328            }
329            if (array_key_exists('github_unread', $this->request->post) && $this->request->post['github_unread']) {
330                $this->out('github_unread', true);
331            }
332        }
333    }
334}
335
336/**
337 * @subpackage github/handler
338 */
339class Hm_Handler_github_list_type extends Hm_Handler_Module {
340    public function process() {
341        $repos = $this->user_config->get('github_repos', array());
342        $excluded = $this->user_config->get('unread_exclude_github_setting', false);
343        $github_list = false;
344        $parent = '';
345        if (array_key_exists('list_parent', $this->request->get)) {
346            $parent = $this->request->get['list_parent'];
347        }
348        if (array_key_exists('list_path', $this->request->get)) {
349            $path = $this->request->get['list_path'];
350            if ($this->page == 'message_list' && preg_match("/^github_(.+)$/", $path)) {
351                $github_list = true;
352                if ($path == 'github_all') {
353                    $this->out('list_path', 'github_all', false);
354                    $this->out('list_parent', $parent, false);
355                    $this->out('mailbox_list_title', array('Github', 'All'));
356                    $this->out('message_list_since', $this->user_config->get('github_since_setting', DEFAULT_SINCE));
357                    $this->out('per_source_limit', $this->user_config->get('github_limit_setting', DEFAULT_PER_SOURCE));
358                    foreach ($repos as $repo) {
359                        $this->append('data_sources', array('callback' => 'load_github_data', 'type' => 'github', 'name' => $repo, 'id' => $repo));
360                    }
361                }
362                else {
363                    $repo = substr($path, 7);
364                    $this->out('list_parent', $parent, false);
365                    if ($parent == 'github_all') {
366                        $this->out('mailbox_list_title', array(urldecode($repo)));
367                    }
368                    else {
369                        $this->out('mailbox_list_title', array('Github', urldecode($repo)));
370                        $this->out('list_path', $path, false);
371                    }
372                    $this->out('custom_list_controls', ' ');
373                    $this->append('data_sources', array('callback' => 'load_github_data', 'type' => 'github', 'name' => $repo, 'id' => $repo));
374                }
375            }
376            elseif ($this->page == 'message_list' && ($path == 'combined_inbox' || $path == 'unread')) {
377                $github_list = true;
378                if (!$excluded || $path == 'combined_inbox') {
379                    foreach ($repos as $repo) {
380                        $this->append('data_sources', array('callback' => 'load_github_data', 'type' => 'github', 'name' => $repo, 'id' => $repo));
381                    }
382                }
383            }
384            elseif ($this->page == 'message' && preg_match("/^github_(.+)$/", $path)) {
385                if (!$parent) {
386                    $repo = substr($path, 7);
387                    $this->out('mailbox_list_title', array('Github', urldecode($repo)));
388                }
389            }
390        }
391        if (!$github_list) {
392            foreach ($repos as $repo) {
393                if (!$excluded) {
394                    $this->append('data_sources', array('callback' => 'load_github_data_background', 'group' => 'background', 'type' => 'github', 'name' => 'Github', 'id' => $repo));
395                }
396            }
397        }
398    }
399}
400
401/**
402 * @subpackage github/output
403 */
404class Hm_Output_github_folders extends Hm_Output_Module {
405    protected function output() {
406        $details = $this->get('github_connect_details', array());
407        if (!empty($details)) {
408            $res = '<li class="menu_github_all"><a class="unread_link" href="?page=message_list&list_path=github_all">';
409            if (!$this->get('hide_folder_icons')) {
410                $res .= '<img class="account_icon" src="'.$this->html_safe(Hm_Image_Sources::$code).'" alt="" width="16" height="16" /> ';
411            }
412            $res .= $this->trans('All').'</a></li>';
413            foreach ($this->get('github_repos', array()) as $repo) {
414                $res .= '<li class="menu_github_'.$this->html_safe($repo).'"><a class="unread_link" href="?page=message_list&list_path=github_'.$this->html_safe($repo).'">';
415                if (!$this->get('hide_folder_icons')) {
416                    $res .= '<img class="account_icon" src="'.$this->html_safe(Hm_Image_Sources::$code).'" alt="" width="16" height="16" /> ';
417                }
418                $res .= $this->html_safe(explode('/', urldecode($repo))[1]).'</a></li>';
419            }
420            $this->append('folder_sources', array('github_folders', $res));
421        }
422    }
423}
424
425/**
426 * @subpackage github/output
427 */
428class Hm_Output_filter_github_data extends Hm_Output_Module {
429    protected function output() {
430        $res = array();
431        $login_time = false;
432        $unread_only = false;
433        $show_icons = $this->get('msg_list_icons');
434        if ($this->get('login_time')) {
435            $login_time = $this->get('login_time');
436        }
437        if ($this->get('list_path', '') == 'unread' || $this->get('github_unread', false)) {
438            $unread_only = true;
439        }
440        $repo_id = $this->get('github_data_source_id');
441        $repo = $this->get('github_data_source', 'Github');
442        $repo_parts = explode('/', $repo);
443        $repo_name = $repo_parts[1];
444        $cutoff = $this->get('github_list_since', '');
445        if ($cutoff) {
446            $cutoff = strtotime($cutoff);
447        }
448        else {
449            $cutoff = 0;
450        }
451        $list_parent = false;
452        if ($this->get('list_parent', '')) {
453            $list_parent = $this->get('list_parent');
454        }
455        elseif ($this->get('list_path') == 'github_all') {
456            $list_parent = $this->get('list_path');
457        }
458        foreach ($this->get('github_data', array()) as $event) {
459            if (!is_array($event) || !array_key_exists('id', $event)) {
460                continue;
461            }
462            $row_class = 'github';
463            $id = 'github_'.$repo_id.'_'.$event['id'];
464            $subject = build_github_subject($event, $this);
465            $url = '?page=message&uid='.$this->html_safe($id).'&list_path=github_'.$this->html_safe($repo);
466            if ($list_parent) {
467                $url .= '&list_parent='.$this->html_safe($list_parent);
468            }
469            $from = $event['actor']['login'];
470            $ts = strtotime($event['created_at']);
471            if ($ts < $cutoff) {
472                continue;
473            }
474            if (Hm_Github_Uid_Cache::is_read($event['id'])) {
475                $flags = array();
476            }
477            elseif (Hm_Github_Uid_Cache::is_unread($event['id'])) {
478                $flags = array('unseen');
479                $row_class .= ' unseen';
480            }
481            elseif ($ts && $login_time && $ts <= $login_time) {
482                $flags = array();
483            }
484            else {
485                $row_class .= ' unseen';
486                $flags = array('unseen');
487            }
488            if ($unread_only && !in_array('unseen', $flags)) {
489                continue;
490            }
491            $date = date('r', $ts);
492            $style = $this->get('news_list_style') ? 'news' : 'email';
493            if ($this->get('is_mobile')) {
494                $style = 'news';
495            }
496            $row_class .= ' '.$repo_name;
497            $icon = 'code';
498            if (!$show_icons) {
499                $icon = '';
500            }
501            if ($style == 'news') {
502                $res[$id] = message_list_row(array(
503                        array('checkbox_callback', $id),
504                        array('icon_callback', $flags),
505                        array('subject_callback', $subject, $url, $flags, $icon),
506                        array('safe_output_callback', 'source', $repo_name),
507                        array('safe_output_callback', 'from', $from),
508                        array('date_callback', human_readable_interval($date), $ts),
509                    ),
510                    $id,
511                    $style,
512                    $this,
513                    $row_class
514                );
515            }
516            else {
517                $res[$id] = message_list_row(array(
518                        array('checkbox_callback', $id),
519                        array('safe_output_callback', 'source', $repo_name, $icon),
520                        array('safe_output_callback', 'from', $from),
521                        array('subject_callback', $subject, $url, $flags),
522                        array('date_callback', human_readable_interval($date), $ts),
523                        array('icon_callback', $flags)
524                    ),
525                    $id,
526                    $style,
527                    $this,
528                    $row_class
529                );
530            }
531        }
532        $this->out('formatted_message_list', $res);
533        $this->out('github_server_id', $repo_id);
534    }
535}
536
537/**
538 * @subpackage github/output
539 */
540class Hm_Output_github_add_repo extends Hm_Output_Module {
541    protected function output() {
542        $res = '';
543        $details = $this->get('github_connect_details', array());
544        if (!empty($details)) {
545            $res = '<div class="configured_server"><div class="subtitle">'.$this->trans('Add a Repository').'</div>'.
546                '<form method="POST">'.
547                '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />'.
548                '<label class="screen_reader">'.$this->trans('Name').'</label>'.
549                '<input type="text" value="" placeholder="'.$this->trans('Name').'" name="new_github_repo" />'.
550                '<label class="screen_reader">'.$this->trans('Owner').'</label>'.
551                '<input type="text" value="" placeholder="'.$this->trans('Owner').'" name="new_github_repo_owner" />'.
552                '<input type="submit" name="github_add_repo" value="Add" />'.
553                '</form></div>';
554            $res .= '<div class="configured_server"><div class="server_title">'.$this->trans('Repositories').'</div>';
555            foreach ($this->get('github_repos', array()) as $repo) {
556                $res .= '<div class="configured_repo"><form class="remove_repo" method="POST">'.
557                    '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />'.
558                    '<input type="hidden" name="github_repo" value="'.$this->html_safe($repo).'" />'.
559                    '<input type="submit" name="github_remove_repo" value="'.$this->trans('Remove').'" class="github_remove_repo" />'.$this->html_safe($repo).'</form></div>';
560            }
561            $res .= '</div></div><div class="end_float"></div></div>';
562        }
563        return $res;
564    }
565}
566
567/**
568 * @subpackage github/output
569 */
570class Hm_Output_filter_github_event_detail extends Hm_Output_Module {
571    protected function output() {
572        $details = $this->get('github_event_detail', array());
573        if (!empty($details)) {
574            if (array_key_exists('payload', $details)) {
575                $body = github_parse_payload($details, $this);
576                $headers = github_parse_headers($details, $this);
577            }
578            $this->out('github_msg_text', $headers.$body);
579        }
580    }
581}
582
583/**
584 * @subpackage github/output
585 */
586class Hm_Output_filter_github_status extends Hm_Output_Module {
587    protected function output() {
588        if ($this->get('github_status') == 'success') {
589            $this->out('github_status_display', '<span class="online">'.$this->trans('Connected').'</span> in '.round($this->get('github_connect_time'), 3));
590        }
591        else {
592            $this->out('github_status_display', '<span class="down">'.$this->trans('Down').'</span>');
593        }
594        $this->out('github_status_repo', $this->get('github_repo', ''));
595    }
596};
597
598/**
599 * @subpackage github/output
600 */
601class Hm_Output_display_github_status extends Hm_Output_Module {
602    protected function output() {
603        $res = '';
604        $repos = $this->get('github_repos', array());
605        if (!empty($repos)) {
606            foreach ($repos as $repo) {
607                $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>';
608            }
609        }
610        return $res;
611    }
612}
613
614/**
615 * @subpackage github/output
616 */
617class Hm_Output_github_connect_section extends Hm_Output_Module {
618    protected function output() {
619        $details = $this->get('github_connect_details', array());
620        $res = '<div class="github_connect"><div data-target=".github_connect_section" class="server_section">'.
621            '<img src="'.Hm_Image_Sources::$code.'" alt="" width="16" height="16" /> '.
622            $this->trans('Github Connect').'</div><div class="github_connect_section"><div class="add_server">';
623        if (empty($details)) {
624            $res .= 'Connect to Github<br /><br />';
625            $res .= '<a href="'.$this->get('github_auth_url', '').'">'.$this->trans('Enable').'</a></div></div><div class="end_float"</div>';
626        }
627        else {
628            $res .= $this->trans('Already connected');
629            $res .= '<br /><form id="github_disconnect_form" method="POST">';
630            $res .= '<input type="hidden" name="hm_page_key" value="'.$this->html_safe(Hm_Request_Key::generate()).'" />';
631            $res .= '<input type="submit" name="github_disconnect" class="github_disconnect" value="'.$this->trans('Disconnect').'" />';
632            $res .= '</form>';
633        }
634        return $res.'</div>';
635    }
636}
637
638/**
639 * @subpackage github/output
640 */
641class Hm_Output_unread_github_included_setting extends Hm_Output_Module {
642    protected function output() {
643        $settings = $this->get('user_settings');
644        if (array_key_exists('unread_exclude_github', $settings) && $settings['unread_exclude_github']) {
645            $checked = ' checked="checked"';
646        }
647        else {
648            $checked = '';
649        }
650        return '<tr class="unread_setting"><td><label for="unread_exclude_github">'.$this->trans('Exclude unread Github notices').'</label></td>'.
651            '<td><input type="checkbox" '.$checked.' value="1" id="unread_exclude_github" name="unread_exclude_github" /></td></tr>';
652    }
653}
654
655/**
656 * @subpackage github/output
657 */
658class Hm_Output_start_github_settings extends Hm_Output_Module {
659    protected function output() {
660        return '<tr><td colspan="2" data-target=".github_all_setting" class="settings_subtitle">'.
661            '<img alt="" src="'.Hm_Image_Sources::$code.'" width="16" height="16" />'.$this->trans('Github Settings').'</td></tr>';
662    }
663}
664
665/**
666 * @subpackage github/output
667 */
668class Hm_Output_github_since_setting extends Hm_Output_Module {
669    protected function output() {
670        $since = DEFAULT_SINCE;
671        $settings = $this->get('user_settings');
672        if (array_key_exists('github_since', $settings) && $settings['github_since']) {
673            $since = $settings['github_since'];
674        }
675        return '<tr class="github_all_setting"><td><label for="github_since">'.$this->trans('Show Github notices received since').'</label></td>'.
676            '<td>'.message_since_dropdown($since, 'github_since', $this).'</td></tr>';
677    }
678}
679
680/**
681 * @subpackage github/output
682 */
683class Hm_Output_github_limit_setting extends Hm_Output_Module {
684    protected function output() {
685        $limit = DEFAULT_PER_SOURCE;
686        $settings = $this->get('user_settings');
687        if (array_key_exists('github_limit', $settings)) {
688            $limit = $settings['github_limit'];
689        }
690        return '<tr class="github_all_setting"><td><label for="github_limit">'.$this->trans('Max Github notices per repository').'</label></td>'.
691            '<td><input type="text" id="github_limit" name="github_limit" size="2" value="'.$this->html_safe($limit).'" /></td></tr>';
692    }
693}
694
695/**
696 * @subpackage github/functions
697 */
698if (!hm_exists('github_connect_details')) {
699function github_connect_details($config) {
700    return get_ini($config, 'github.ini');
701}}
702
703/**
704 * @subpackage github/functions
705 */
706if (!hm_exists('build_github_subject')) {
707function build_github_subject($event, $output_mod) {
708    $ref = '';
709    if (array_key_exists('payload', $event) && array_key_exists('ref', $event['payload'])) {
710        $ref = sprintf(' / %s', preg_replace("/^refs\/heads\//", '', $event['payload']['ref']));
711    }
712    $pre = '['.$output_mod->html_safe(trim(str_replace('Event', '', trim(preg_replace("/([A-Z])/", " $1", $event['type']))))).']';
713    $post = '';
714    $max = 100;
715    switch (strtolower($event['type'])) {
716        case 'issuecommentevent':
717            $post = $event['payload']['issue']['title'];
718            break;
719        case 'issuesevent':
720            $post = $event['payload']['issue']['title'].' - '.$event['payload']['action'];
721            break;
722        case 'pushevent':
723            if (count($event['payload']['commits']) > 1) {
724                $post .= sprintf($output_mod->trans('%d commits: '), count($event['payload']['commits']));
725            }
726            else {
727                $post .= sprintf($output_mod->trans('%d commit: '), count($event['payload']['commits']));
728            }
729            $post .= substr($event['payload']['commits'][0]['message'], 0, $max);
730            break;
731        case 'watchevent':
732            if ($event['payload']['action'] == 'started') {
733                $post  .= sprintf($output_mod->trans('%s started watching this repo'), $event['actor']['login']);
734            }
735            else {
736                $post  .= sprintf($output_mod->trans('%s stopped watching this repo'), $event['actor']['login']);
737            }
738            break;
739        case 'forkevent':
740            $post = sprintf($output_mod->trans("%s forked %s"), $event['actor']['login'], $event['repo']['name']);
741            break;
742        case 'createevent':
743            $post = sprintf($output_mod->trans("%s repository created"), $event['repo']['name']);
744            break;
745        case 'pullrequestevent':
746            $post = substr($event['payload']['pull_request']['body'], 0, $max);
747            break;
748        case 'commitcommentevent':
749            $post = substr($event['payload']['comment']['body'], 0, $max);
750            break;
751        case 'releaseevent':
752            $post = substr($event['payload']['release']['name'], 0, $max);
753        default:
754            break;
755    }
756    if ($ref) {
757        $post .= $output_mod->html_safe($ref);
758    }
759    return $pre.' '.$post;
760}}
761
762/**
763 * @subpackage github/functions
764 */
765if (!hm_exists('github_parse_headers')) {
766function github_parse_headers($data, $output_mod) {
767    $res = '<table class="msg_headers"><colgroup><col class="header_name_col"><col class="header_val_col"></colgroup>';
768    if (array_key_exists('type', $data)) {
769        $type = build_github_subject($data, $output_mod);
770    }
771    else {
772        $type = '[Unknown Type]';
773    }
774    if (array_key_exists('created_at', $data)) {
775        $date = sprintf("%s", date('r', strtotime($data['created_at'])));
776    }
777    else {
778        $date = '[No date]';
779    }
780    $repo_link = '';
781    $from_link = '';
782
783    if (array_key_exists('actor', $data) && array_key_exists('login', $data['actor'])) {
784        $from = $data['actor']['login'];
785        $from_link = sprintf(' - <a href="https://github.com/%s">https://github.com/%s</a>', $output_mod->html_safe($from), $output_mod->html_safe($from));
786    }
787    else {
788        $from = '[No From]';
789    }
790    if (array_key_exists('repo', $data) && array_key_exists('name', $data['repo'])) {
791        $name = $data['repo']['name'];
792        $repo_link = sprintf(' - <a href="https://github.com/%s">https://github.com/%s</a>', $output_mod->html_safe($name), $output_mod->html_safe($name));
793    }
794    else {
795        $name = '[No Repo]';
796    }
797    $res .= '<tr class="header_subject"><th colspan="2">'.$output_mod->html_safe($type).'</th></tr>';
798    $res .= '<tr class="header_date"><th>'.$output_mod->trans('Date').'</th><td>'.$output_mod->html_safe($date).'</td></tr>';
799    $res .= '<tr class="header_from"><th>'.$output_mod->trans('Author').'</th><td>'.$output_mod->html_safe($from).$from_link.'</td></tr>';
800    $res .= '<tr><th>'.$output_mod->trans('Repository').'</th><td>'.$output_mod->html_safe($name).$repo_link.'</td></tr>';
801    $res .= '<tr><td></td><td></td></tr></table>';
802    return $res;
803}}
804
805/**
806 * @subpackage github/functions
807 */
808if (!hm_exists('github_parse_payload')) {
809function github_parse_payload($data, $output_mod) {
810    $type = false;
811    if (array_key_exists('type', $data)) {
812        $type = $data['type'];
813    }
814    /* Event types: CommitCommentEvent CreateEvent DeleteEvent DeploymentEvent DeploymentStatusEvent DownloadEvent FollowEvent
815	 * ForkEvent ForkApplyEvent GistEvent GollumEvent IssueCommentEvent IssuesEvent MemberEvent MembershipEvent PageBuildEvent
816	 * PublicEvent PullRequestEvent PullRequestReviewCommentEvent PushEvent ReleaseEvent RepositoryEvent StatusEvent TeamAddEvent
817	 * WatchEvent */
818
819    $data = $data['payload'];
820    $content = payload_search($data);
821    $res = '<div class="msg_text_inner">';
822    foreach ($content as $vals) {
823        $res .= '<div class="github_para">';
824        if (array_key_exists('name', $vals)) {
825            $res .= $output_mod->html_safe($vals['name']);
826            $res .= '</div><div class="github_para">';
827        }
828        if (array_key_exists('body', $vals)) {
829            $res .= $output_mod->html_safe(wordwrap($vals['body'], 100));
830        }
831        if (array_key_exists('message', $vals)) {
832            $res .= $output_mod->html_safe(wordwrap($vals['message'], 100));
833        }
834        if (array_key_exists('html_url', $vals)) {
835            $res .= sprintf('<div class="github_link"><a href="%s">%s</a></div>',
836                $output_mod->html_safe($vals['html_url']), $output_mod->html_safe($vals['html_url']));
837        }
838        if (array_key_exists('url', $vals) && array_key_exists('sha', $vals)) {
839            $url = str_replace(array('commits', 'https://api.github.com/repos'), array('commit', 'https://github.com'), $vals['url']);
840            $res .= sprintf('<div class="github_link"><a href="%s">%s</a></div>',
841                $output_mod->html_safe($url), $output_mod->html_safe($vals['sha']));
842        }
843        $res .= '</div>';
844    }
845    $res .= '</div>';
846    return $res;
847}}
848
849/**
850 * @subpackage github/functions
851 */
852if (!hm_exists('payload_search')) {
853function payload_search($data) {
854    $res = array();
855    $data_flds = array('url', 'sha', 'body', 'description', 'message', 'name');
856    foreach($data as $vals) {
857        if (is_array($vals)) {
858            $item = array();
859            foreach ($data_flds as $fld) {
860                if (array_key_exists($fld, $vals)) {
861                    $item[$fld] = $vals[$fld];
862                }
863            }
864            if (!empty($item)) {
865                if (array_key_exists('html_url', $data)) {
866                    $item['html_url'] = $vals['html_url'];
867                }
868            }
869            else {
870                $res = array_merge($res, payload_search($vals));
871            }
872            if (count($item) > 0) {
873                $res[] = $item;
874            }
875        }
876    }
877    return $res;
878}}
879