<?php require_once($INC . "/util.inc.php"); require_once($INC . "/log.inc.php"); require_once($INC . "/sql.inc.php"); require_once($INC . "/prof.inc.php"); $rg_wh_error = ""; function rg_wh_set_error($str) { global $rg_wh_error; $rg_wh_error = $str; rg_log($str); } function rg_wh_error() { global $rg_wh_error; return $rg_wh_error; } // Here plugins will store the functions $rg_wh_plugins = array(); $rg_wh_flags = array( 'D' => 'Hook disabled' ); $rg_wh_events = array( 'C' => 'Create repository', 'P' => 'Push', 'B' => 'Create branch' ); /* * Generates event list as html */ function rg_wh_check_events($events) { global $rg_wh_events; if (empty($rg_wh_events)) return ''; $ret = '<fieldset>'; $ret .= '<legend>Select trigger events</legend>'; $br = ''; foreach ($rg_wh_events as $id => $name) { $add = ''; if (strchr($events, $id)) $add = ' checked="checked"'; $ret .= $br . '<input type="checkbox" name="wh::idata::events[' . $id . ']"' . ' id="events-' . $id . '"' . $add . ' />' . "\n" . '<label for="events-' . $id . '">' . $name . '</label>'; $br = '<br />' . "\n"; } $ret .= '</fieldset>' . "\n"; return $ret; } /* * Generates an events list as text */ function rg_wh_events($events) { global $rg_wh_events; $a = array(); foreach ($rg_wh_events as $id => $name) { if (strchr($events, $id)) $a[] = $name; } return implode(', ', $a); } /* * Generates flags list */ function rg_wh_check_flags($all_flags, $flags) { global $rg_wh_flags; $ret = ''; $br = ''; $list = array_merge($rg_wh_flags, $all_flags); foreach ($list as $id => $name) { $add = ''; if (strchr($flags, $id)) $add = ' checked="checked"'; $ret .= $br . '<input type="checkbox" name="wh::flags[' . $id . ']"' . ' id="flags-' . $id . '"' . $add . ' />' . "\n" . '<label for="flags-' . $id . '">' . $name . '</label>'; $br = '<br />' . "\n"; } return $ret; } /* * Generates a flags list as text */ function rg_wh_flags($all_flags, $flags) { global $rg_wh_flags; $a = array(); $list = array_merge($rg_wh_flags, $all_flags); foreach ($list as $id => $name) { if (strchr($flags, $id)) $a[] = $name; } return implode(', ', $a); } /* * Some cosmetics applied to a webhook */ function rg_wh_cosmetic(&$list) { global $rg_wh_plugins; foreach ($list as $id => &$row) { $t = $row['htype']; if (isset($row['itime'])) $row['itime_nice'] = gmdate('Y-m-d H:i', $row['itime']); $row['HTML:flags_text'] = rg_wh_flags($rg_wh_plugins[$t]['flags'], $row['flags']); if (isset($row['description'])) { if (empty($row['description'])) $row['HTML:description_nice'] = 'n/a'; else $row['HTML:description_nice'] = nl2br(rg_xss_safe($row['description'])); } if (isset($row['last_output'])) { if (empty($row['last_output'])) $row['HTML:last_output_nice'] = 'n/a'; else $row['HTML:last_output_nice'] = nl2br(rg_xss_safe($row['last_output'])); } if ($rg_wh_plugins[$t]['have_events'] == 1) { if (isset($row['idata']['events'])) $row['idata']['events_text'] = rg_wh_events($row['idata']['events']); } if (isset($rg_wh_plugins[$t]['cosmetic'])) $rg_wh_plugins[$t]['cosmetic']($row); } } /* * Set last_output field of a webhook */ function rg_wh_set_last_output($db, $uid, $id, $output) { rg_prof_start('wh_set_last_output'); rg_log_enter('wh_set_last_output id=' . $id); $ret = FALSE; while (1) { $params = array('id' => $id, 'last_output' => $output); $sql = 'UPDATE webhooks' . ' SET last_output = @@last_output@@' . ' WHERE id = @@id@@'; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { rg_wh_set_error('cannot insert/update data'); break; } rg_sql_free_result($res); $key = 'wh' . '::' . $uid . '::' . 'list' . '::' . $id . '::' . 'last_output'; rg_cache_set($key, $output, RG_SOCKET_NO_WAIT); $ret = TRUE; break; } rg_log_exit(); rg_prof_end('wh_set_last_output'); return $ret; } /* * Sorting the webhooks list by itime DESC */ function rg_wh_sort_helper($a, $b) { if ($a['itime'] > $b['itime']) return -1; if ($a['itime'] == $b['itime']) return 0; return 1; } /* * Returns a list of webhooks associated with a user */ function rg_wh_list($db, $uid) { rg_prof_start('wh_list'); rg_log_enter('wh_list'); $ret = array('ok' => 0, 'list' => array()); while (1) { $key = 'wh' . '::' . $uid; $r = rg_cache_get($key); if (($r !== FALSE) && isset($r['LIST_LOADED'])) { $ret['list'] = $r['list']; $ret['ok'] = 1; break; } $params = array('uid' => $uid); $sql = 'SELECT * FROM webhooks' . ' WHERE uid = @@uid@@' . ' ORDER BY itime DESC'; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { rg_wh_set_error('cannot load data'); break; } while (($row = rg_sql_fetch_array($res))) { //rg_log_ml('DEBUG: wh_list: row: ' . print_r($row, TRUE)); $id = $row['id']; if (strcmp($row['idata'], "") != 0) { $row['idata'] = unserialize($row['idata']); if ($row['idata'] === FALSE) { rg_internal_error('cannot unserialize data'); // we try to continue $row['idata'] = array(); } } else { $row['idata'] = array(); } $ret['list'][$id] = $row; } rg_sql_free_result($res); $a = array('LIST_LOADED' => 1, 'list' => $ret['list']); rg_cache_merge($key, $a, RG_SOCKET_NO_WAIT); $ret['ok'] = 1; break; } uasort($ret['list'], 'rg_wh_sort_helper'); rg_log_exit(); rg_prof_end('wh_list'); return $ret; } /* * Adds/edits a webhook */ function rg_wh_add($db, $uid, $data) { rg_prof_start('wh_add'); rg_log_enter('wh_add'); $ret = array('ok' => 0); while (1) { $data['uid'] = $uid; $data['itime'] = time(); $params = $data; $params['idata'] = serialize($params['idata']); if ($data['id'] == 0) { $data['last_output'] = ''; $sql = 'INSERT INTO webhooks (uid, itime' . ', htype, flags, repo, refname' . ', add_ip, description, idata)' . ' VALUES (@@uid@@, @@itime@@' . ', @@htype@@, @@flags@@, @@repo@@' . ', @@refname@@' . ', @@add_ip@@' . ', @@description@@, @@idata@@)' . ' RETURNING id'; } else { $sql = 'UPDATE webhooks' . ' SET description = @@description@@' . ', flags = @@flags@@' . ', repo = @@repo@@' . ', refname = @@refname@@' . ', idata = @@idata@@' . ' WHERE uid = @@uid@@' . ' AND id = @@id@@'; } $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { rg_wh_set_error('cannot insert/update data'); break; } if ($data['id'] == 0) $row = rg_sql_fetch_array($res); rg_sql_free_result($res); if ($data['id'] == 0) $data['id'] = $row['id']; $key = 'wh' . '::' . $uid . '::' . 'list' . '::' . $data['id']; rg_cache_merge($key, $data, RG_SOCKET_NO_WAIT); $ret['ok'] = 1; break; } rg_log_exit(); rg_prof_end('wh_add'); return $ret; } /* * Removes a list of webhooks */ function rg_wh_remove($db, $uid, $list) { rg_prof_start('wh_remove'); rg_log_enter('wh_remove'); $ret = array('ok' => 0); while (1) { if (empty($list)) { rg_wh_set_error('you did not select anything'); break; } $my_list = array(); foreach ($list as $id => $junk) $my_list[] = sprintf("%u", $id); $params = array('uid' => $uid); $sql_list = implode(', ', $my_list); $sql = 'DELETE FROM webhooks' . ' WHERE uid = @@uid@@' . ' AND id IN (' . $sql_list . ')'; $res = rg_sql_query_params($db, $sql, $params); if ($res === FALSE) { rg_wh_set_error('cannot remove webhooks'); break; } rg_sql_free_result($res); foreach ($my_list as $junk => $id) { $key = 'wh' . '::' . $uid . '::' . 'list' . '::' . $id; rg_cache_unset($key, RG_SOCKET_NO_WAIT); } $ret['ok'] = 1; break; } rg_log_exit(); rg_prof_end('wh_remove'); return $ret; } /* * Extract vars from request */ function rg_wh_fill_vars(&$rg) { global $rg_wh_plugins; $ret = FALSE; while (1) { $t = $rg['wh']['htype']; $rg['wh']['repo'] = rg_var_str('wh::repo'); $rg['wh']['flags'] = rg_var_a2s('wh::flags'); $rg['wh']['refname'] = rg_var_str('wh::refname'); $rg['wh']['itime'] = time(); $rg['wh']['add_ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; $rg['wh']['description'] = trim(rg_var_str('wh::description')); $rg['wh']['idata'] = array(); $rg['wh']['idata']['debug'] = $rg['debug']; $rg['wh']['idata']['events'] = rg_var_a2s('wh::idata::events'); // TODO if (!isset($rg_wh_plugins[$t])) { $errmsg[] = rg_template('user/settings/wh/invalid_htype', $rg, TRUE /*xss*/); break; } if (isset($rg_wh_plugins[$t]['fill_vars'])) { $rg_wh_plugins[$t]['fill_vars']($rg); break; } $ret = TRUE; break; } return $ret; } /* * Validate parameters */ function rg_wh_validate_vars($rg, &$errmsg) { global $rg_wh_flags; global $rg_wh_plugins; $ret = FALSE; while (1) { $t = $rg['wh']['htype']; if (!isset($rg_wh_plugins[$t])) { $errmsg[] = rg_template('user/settings/wh/invalid_htype.txt', $rg, TRUE /*xss*/); break; } $all_ok = TRUE; $list = array_merge($rg_wh_flags, $rg_wh_plugins[$t]['flags']); $len = strlen($rg['wh']['flags']); for ($i = 0; $i < $len; $i++) { $f = $rg['wh']['flags'][$i]; if (!isset($list[$f])) { $all_ok = FALSE; $errmsg[] = rg_template('user/settings/wh/inv_flag.txt', $rg, TRUE /*xss*/); break; } } if (!$all_ok) break; // Some hooks do not need events, for example CodeDeploy if ($rg_wh_plugins[$t]['have_events'] == 1) { if (empty($rg['wh']['idata']['events'])) { $errmsg[] = rg_template('user/settings/wh/inv_events.txt', $rg, TRUE /*xss*/); break; } } if (isset($rg_wh_plugins[$t]['validate_vars'])) { $r = $rg_wh_plugins[$t]['validate_vars']($rg, $errmsg); if ($r !== TRUE) break; } $ret = TRUE; break; } return $ret; } /* * Generic add_form function */ function rg_wh_add_form(&$rg) { global $rg_wh_plugins; while (1) { $t = $rg['wh']['htype']; if (!isset($rg_wh_plugins[$t])) break; $rg['HTML:check_flags'] = rg_wh_check_flags($rg_wh_plugins[$t]['flags'], $rg['wh']['flags']); if ($rg_wh_plugins[$t]['have_events'] == 1) $rg['HTML:check_events'] = rg_wh_check_events($rg['wh']['idata']['events']); if (isset($rg_wh_plugins[$t]['add_form'])) { $rg_wh_plugins[$t]['add_form']($rg); break; } break; } } /* * Generic default_paras function */ function rg_wh_default_paras(&$rg) { global $rg_wh_plugins; while (1) { $t = $rg['wh']['htype']; $rg['wh']['id'] = 0; $rg['wh']['description'] = ''; $rg['wh']['flags'] = ''; $rg['wh']['repo'] = ''; $rg['wh']['refname'] = ''; $rg['wh']['idata'] = array(); $rg['wh']['idata']['events'] = ''; if (!isset($rg_wh_plugins[$t])) break; if (isset($rg_wh_plugins[$t]['default_paras'])) { $rg_wh_plugins[$t]['default_paras']($rg); break; } break; } } /* * Generic hints add function */ function rg_wh_fill_hints(&$rg, &$hints) { global $rg_wh_plugins; while (1) { $t = $rg['wh']['htype']; $hints[]['HTML:hint'] = rg_template('user/settings/wh/hints_tags.html', $rg, TRUE /*xss*/); if (!isset($rg_wh_plugins[$t])) break; if (isset($rg_wh_plugins[$t]['fill_hints'])) { $rg_wh_plugins[$t]['fill_hints']($rg, $hints); break; } break; } } /* * Returns a HTML list with possible htypes */ function rg_wh_htypes($rg) { global $rg_wh_plugins; foreach ($rg_wh_plugins as $htype => &$pi) { if (!isset($pi['subtypes'])) $pi['subtypes'] = array(); $list = array_merge($pi['subtypes'], array('generic' => 'Generic')); $pi['HTML:hsubtype_list'] = ''; $add = ''; foreach ($list as $st => $info) { $a = array( 'htype' => $htype, 'hsubtype' => $st, 'info' => $info ); $pi['HTML:hsubtype_list'] .= $add . rg_template('user/settings/wh/subtype.html', $a, TRUE /*xss*/); $add = ', '; } } asort($rg_wh_plugins); return rg_template_table('user/settings/wh/plugins_list', $rg_wh_plugins, $rg); } /* * Returns TRUE if htype is valid */ function rg_wh_valid($htype) { global $rg_wh_plugins; return isset($rg_wh_plugins[$htype]); } /* * Function used to replace ##tag## */ function rg_wh_replace_tags(&$ev) { rg_log_ml('wh_replace_tags: ev=' . print_r($ev, TRUE)); $wh = &$ev['wh']; $idata = &$wh['idata']; $branch = isset($ev['refname']) ? rg_repo_ref_nice($ev['refname']) : ''; $repo_name = isset($ev['ri']['name']) ? $ev['ri']['name'] : ''; $new_rev = isset($ev['new_rev']) ? $ev['new_rev'] : ''; $keys = array('##repo_url##', '##commit_url##', '##branch##', '##repo##', '##hook_id##', '##commit##', '##date##', '##time##', '##ip##', '##timestamp##'); $values = array($ev['ri']['url'], $ev['ri']['url'] . '/source/log/commit/' . $new_rev, $branch, $repo_name, $wh['id'], $new_rev, gmdate('Y-m-d', $ev['itime']), gmdate('H:i:s', $ev['itime']), $ev['ip'], $ev['itime']); foreach ($idata as $var => &$value) $value = str_replace($keys, $values, $value); rg_log_ml('after: ' . print_r($idata, TRUE)); } /* * Used to filter hooks by repo name */ function rg_wh_repo_match($pattern, $repo_name) { rg_log('wh_repo_match pattern=[' . $pattern . ']' . ' repo_name=[' . $repo_name . ']'); $pattern = str_replace('|', '', $pattern); return preg_match('|' . $pattern . '|uD', $repo_name) === 1; } ?>