<?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($db, &$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']($db, $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']) : '';
rg_log('DEBUG: branch=' . $branch);
$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;
}
?>