<?php
$triggerOptionList = array();
/* Trigger Bit Flags {{{2 */
define ("TRIGGER_FLAG_DISABLED", 1); // Disabled Ticket
define ("TRIGGER_FLAG_MATCH_ANY", 2); // Match any rule
define ("TRIGGER_FLAG_ADD", 4); // Check rules on ADD
define ("TRIGGER_FLAG_MODIFY", 8); // Check rules on MODIFY
define ("TRIGGER_FLAG_TIME", 16); // Check rules on SCHEDULER
/* }}}2 */
/* Trigger Bit Flags }}}2 */
/* Trigger Rule Type Definitions {{{2 */
define ("TRIGGER_RULE_AFTER_TIME", 1); // Scheduled run at X UNIX time
define ("TRIGGER_RULE_AFTER_UNMODIFIED", 2); // Run after unmodified for X amount of time
define ("TRIGGER_RULE_FIELD_CHANGE", 3); // Run when X field changes
define ("TRIGGER_RULE_FIELD_CHANGED_TO", 4); // Run when X field changes
define ("TRIGGER_RULE_FIELD_IS", 5); // Run when field X is set to Y
define ("TRIGGER_RULE_IS_CLOSED", 6); // Run when ticket is closed
define ("TRIGGER_RULE_REGEXP", 7); // Regexp on Short and Long Description
define ("TRIGGER_RULE_REGEXP_SHORTDESC", 8); // Regexp on Short Description
define ("TRIGGER_RULE_REGEXP_LONGDESC", 9); // Regexp on Long Description
define ("TRIGGER_RULE_REGEXP_MODIFICATION", 10); // Regexp on Long Description
$triggerOptionList['RULE'] = "";
$triggerOptionList['RULE'] .= "<option name=\"When time is later than\" value=\"".TRIGGER_RULE_AFTER_TIME."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"When unmodified for X minutes\" value=\"".TRIGGER_RULE_AFTER_UNMODIFIED."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"When field changes\" value=\"".TRIGGER_RULE_FIELD_CHANGE."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"When field X is changed to Y\" value=\"".TRIGGER_RULE_FIELD_CHANGED_TO."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"When field is X\" value=\"".TRIGGER_RULE_FIELD_IS."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"When ticket is set to CLOSED state\" value=\"".TRIGGER_RULE_IS_CLOSED."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"Regular Expression on ALL\" value=\"".TRIGGER_RULE_REGEXP."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"Regular Expression on Short Description\" value=\"".TRIGGER_RULE_REGEXP_SHORTDESC."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"Regular Expression on Long Description\" value=\"".TRIGGER_RULE_REGEXP_LONGDESC."\">\n";
$triggerOptionList['RULE'] .= "<option name=\"Regular Expression on Modification\" value=\"".TRIGGER_RULE_REGEXP_MODIFICATION."\">\n";
/* Trigger Rule Type Definitions }}}2 */
/* Trigger Affect Bit Flags {{{2 */
define ("TRIGGER_ACTION_NOTIFY", 1); // Run Notification
define ("TRIGGER_ACTION_NOTIFY_PROJECT", 2); // Run Notification for project e-mail
define ("TRIGGER_ACTION_NOTIFY_OWNER", 3); // Run Notification for ticket owner
define ("TRIGGER_ACTION_NOTIFY_CREATOR", 4); // Run Notification for creator
define ("TRIGGER_ACTION_NOTIFY_ALSONOTIFY", 5); // Run Notification for other (specify)
define ("TRIGGER_ACTION_NOTIFY_OTHER", 6); // Run Notification for other (specify)
define ("TRIGGER_ACTION_UPDATE_FIELD", 7); // Update the ticket
define ("TRIGGER_ACTION_MODIFICATION", 8); // Add update text...
define ("TRIGGER_ACTION_DISABLE_TRIGGER", 128); // Disable the trigger (for one-time runs)
/* Trigger Affect Bit Flags }}}2 */
/* Trigger Functions {{{1 */
/* function getTriggerRuleDescription($rule) {{{2
This function returns the trigger rule type for the rule */
function getTriggerRuleDescription($rule) {
switch($rule['type']) {
case TRIGGER_RULE_AFTER_TIME:
$type = "Run rule on or after ".date("l dS of F Y h:i:s A", $rule['value']);
break;
case TRIGGER_RULE_AFTER_UNMODIFIED:
$type = "Run after unmodified for {$rule['value']} hours";
break;
case TRIGGER_RULE_FIELD_CHANGE:
$type = "Field: {$rule['value']} is modified";
break;
case TRIGGER_RULE_FIELD_CHANGED_TO:
if (isset($bugDatabase->lists[$rule['value']]))
$setTo = $bugDatabase->lists[$rule['value']][$rule['fid']]['name'];
else
$setTo = $rule['fid'];
$type = "Field: {$rule['value']} is changed to {$setTo}";
break;
case TRIGGER_RULE_FIELD_IS:
if (isset($bugDatabase->lists[$rule['value']]))
$setTo = $bugDatabase->lists[$rule['value']][$rule['fid']]['name'];
else
$setTo = $rule['fid'];
$type = "Field: {$rule['value']} is {$setTo}";
break;
case TRIGGER_RULE_IS_NOT_CLOSED:
$type = "Ticket is not closed";
break;
case TRIGGER_RULE_REGEXP:
$type = "Short or Long description regexp({$rule['value']})";
break;
case TRIGGER_RULE_REGEXP_SHORTDESC:
$type = "Short description regexp({$rule['value']})";
break;
case TRIGGER_RULE_REGEXP_LONGDESC:
$type = "Long description regexp({$rule['value']})";
break;
default:
$type = "Unknown Type {$rule['type']}";
break;
}
return $type;
}
/* }}}2 */
/* function runTriggers($type, $ticket, $mod) {{{2
This function makes a table from the requested info */
function runTriggers($type, $ticket, $mod = array()) {
global $bugDatabase;
global $options;
if (empty($mod))
$mod = $ticket;
$newTicket = $bugDatabase->getTicket($ticket['id']);
$notifyList = array();
$modifyList = array();
$triggers = array();
reset($bugDatabase->lists['trigger']);
while (list($key, $value) = each($bugDatabase->lists['trigger'])) {
if (!($value['flags'] & TRIGGER_FLAG_DISABLED) &&
($value['flags'] & $type) && (
// Affects this project OR
($value['type'] == 'p' && (($value['typeid'] == 0) || ($value['typeid'] == $ticket['project']))) ||
// Is a ticket trigger for this ticket
(($value['type'] == 't') && ($value['typeid'] == $ticket['id']))
)
) {
$triggers[$key] = $value;
}
}
if (!count($triggers)) {
buginError("No triggers to run", MESSAGE_DEBUG);
return;
}
else {
while (list($key, $trigger) = each($triggers)) {
$affectsToRun = array();
// Do we match any trigger, or match all?
if ($trigger['flags'] & TRIGGER_FLAG_MATCH_ANY)
$matchany = 1;
else
$matchany = 0;
$runAffects = 0;
$blocked = 0;
$disable = 0;
$isClosedRule = 0;
$ud = array();
$notify = array();
buginError ("+Testing Trigger {$trigger['id']}", MESSAGE_DEBUG);
if (count($trigger['rules'])) {
reset($trigger['rules']);
while (list($ruleKey, $rule) = each($trigger['rules'])) {
$break = 0;
switch ($rule['type']) {
case TRIGGER_RULE_AFTER_TIME:
if (!($rule['value'] >= time()))
$break = 1;
break;
case TRIGGER_RULE_AFTER_UNMODIFIED:
if ($ticket['age'] < ($rule['value'] * 3600))
$break = 1;
break;
case TRIGGER_RULE_FIELD_CHANGE:
if ($ticket[$rule['value']] != $newTicket[$rule['value']])
$break = 1;
break;
case TRIGGER_RULE_FIELD_CHANGED_TO:
if ($mod[$rule['value']] == $rule['fid'])
$break = 1;
break;
case TRIGGER_RULE_FIELD_IS:
if ($ticket[$rule['value']] != $rule['fid'])
$break = 1;
break;
case TRIGGER_RULE_IS_CLOSED:
$isClosedRule = 1;
if (!in_array($ticket['status'], explode(",", $options['closedNum'])))
$break = 1;
break;
case TRIGGER_RULE_REGEXP:
if (!eregi($rule['value'], $ticket['short_desc']) ||
!eregi($rule['value'], $ticket['long_desc']))
$break = 1;
break;
case TRIGGER_RULE_REGEXP_SHORTDESC:
if (!eregi($rule['value'], $ticket['short_desc']))
$break = 1;
break;
case TRIGGER_RULE_REGEXP_LONGDESC:
if (!eregi($rule['value'], $ticket['long_desc']))
$break = 1;
break;
default:
buginError("Unknown Type {$rule['type']} on rule {$ruleKey}", MESSAGE_ERROR);
exit();
break;
}
buginError("++Testing condition ".getTriggerRuleDescription($rule).": ".$break, MESSAGE_DEBUG);
// Have we got a match on a "match any"?
if ($matchany) {
// We're not blocked, because one of the rules passed.
if (!$break) {
$blocked = 0;
break;
}
else {
// Blocked, but keep processing...
$blocked = 1;
}
}
elseif ($break) {
// We're blocked on a match all set
$blocked = 1;
break;
}
}
if (!$blocked) {
buginError ("++ **Running Trigger {$trigger['id']}", MESSAGE_DEBUG);
$runAffects = 1;
}
}
else {
$runAffects = 1;
}
if ($runAffects &&
(($isClosedRule == 0) || in_array($ticket['status'], explode(",", $options['closedNum']))) ) {
// Go throgh all the affects and execute them.
while (list($affectKey, $affect) = each($trigger['affects'])) {
$affectsToRun[] = $affect;
}
}
}
}
// Check to see if we have any affects to run...
if (count($affectsToRun)) {
reset($affectsToRun);
buginError("+* Running Affects", MESSAGE_DEBUG);
while (list($affectKey, $affect) = each($affectsToRun)) {
switch ($affect['type']) {
case TRIGGER_ACTION_NOTIFY:
buginError("+Notify: Project, Owner, and Creator", MESSAGE_DEBUG);
if ($_REQUEST['alsoNotify']) {
$t = explode(",", str_replace(";", ",", $_REQUEST['alsoNotify']));
while (list($key, $name) = each($t)) {
$notify[$name] = "";
}
unset($t);
}
case TRIGGER_ACTION_NOTIFY_PROJECT:
buginError("+Notify: New Project List ({$bugDatabase->lists['project'][$ticket['project']]['name']})", MESSAGE_DEBUG);
$notify[$bugDatabase->lists['project'][$ticket['project']]['email']] = "";
if ($ticket['project'] != $newTicket['project']) {
buginError("Notify: Project ({$bugDatabase->lists['project'][$newTicket['project']]['name']})", MESSAGE_DEBUG);
$notify[$bugDatabase->lists['project'][$newTicket['project']]['email']] = "";
}
if ($affect['type'] != TRIGGER_ACTION_NOTIFY) {
break;
}
case TRIGGER_ACTION_NOTIFY_OWNER:
buginError("+Notify: Owner", MESSAGE_DEBUG);
if ($ticket['owner'] != 0)
$notify[$bugDatabase->lists['user'][$ticket['owner']]['email']] = $bugDatabase->lists['user'][$ticket['owner']]['name'];
if (($ticket['owner'] != $newTicket['owner']) && $newTicket['owner'] != 0) {
buginError("+Notify: New Owner ({$bugDatabase->lists['user'][$newTicket['owner']]['name']})", MESSAGE_DEBUG);
$notify[$bugDatabase->lists['user'][$newTicket['owner']]['email']] = $bugDatabase->lists['user'][$newTicket['owner']]['name'];
}
if ($affect['type'] != TRIGGER_ACTION_NOTIFY) {
break;
}
case TRIGGER_ACTION_NOTIFY_CREATOR:
buginError("+Notify: Creator ({$bugDatabase->lists['user'][$ticket['creator']]['email']})", MESSAGE_DEBUG);
if ($ticket['creator'] != 0)
$notify[$bugDatabase->lists['user'][$ticket['creator']]['email']] = $bugDatabase->lists['user'][$ticket['creator']]['name'];
break;
case TRIGGER_ACTION_NOTIFY_OTHER:
buginError(htmlentities("+Notify: User ({$bugDatabase->lists['user'][$affect['fid']]['name']})"), MESSAGE_DEBUG);
$notify[$bugDatabase->lists['user'][$affect['fid']]['email']] = $bugDatabase->lists['user'][$affect['fid']]['name'];
break;
case TRIGGER_ACTION_NOTIFY_ALSONOTIFY:
$mailReg = "(([\x21\x23-\x27\x2A-\x2B\x2D\w\x3D\x3F]+(?:\.[\x21\x23-\x27\x2A-\x2B\x2D\w\x3D\x3F]+)*)\@(\w[-\w]*(?:\.\w[-\w]*)*|\[\d{1,3}(?:\.\d{1,3}){3}\]))";
if (isset($_REQUEST['alsoNotify']) && $_REQUEST['alsoNotify'] != "") {
$l = split(",", split(str_replace(";", ",", $_REQUEST['alsoNotify'])));
while (list($junk, $emailaddy) = each($l)) {
buginError(htmlentities("+Notify: ({$_REQUEST['alsoNotify']})"), MESSAGE_DEBUG);
$emailaddy = strip($emailaddy);
$notify[ereg($mailReg,$emailaddy)] = $emailaddy;
}
}
break;
case TRIGGER_ACTION_UPDATE_FIELD:
buginError("+Update {$affect['value']} to {$bugDatabase->lists['project'][$affect['fid']]['name']}", MESSAGE_DEBUG);
$ud[$affect['value']] = $affect['fid'];
break;
case TRIGGER_ACTION_DISABLE_TRIGGER:
buginError("+Disable trigger after run", MESSAGE_DEBUG);
$disable = 1;
break;
case TRIGGER_ACTION_MODIFICATION:
buginError("+Add modification text...", MESSAGE_DEBUG);
if (!isset($mod['modification']))
$mod['modification'] = "";
$mod['modification'] .= $affect['value']."\n";
break;
default:
echo "Unknown Type {$affect['type']}<br />";
}
}
}
$result = array();
if (count($notify)) {
// Run Notification
$notifyList = array();
while (list($email, $name) = each($notify)) {
if (!empty($name)) {
// $notifyList[] = "\"{$name}\" <{$email}>";
// CLM Hack
// The above commmented code does not work on
// Win2K, IIS, with Win2K SMTP anyway
$notifyList[] = $email;
}
else {
$notifyList[] = $email;
}
}
$notifyList = implode(",", $notifyList);
$result['notifyList'] = $notifyList;
}
if(count($ud))
$result['ud'] = $ud;
$result['mod'] = $mod;
$result['newTicket'] = $newTicket;
return($result);
}
/* }}}2 */
/* function makeTriggerTable($type, $id) {{{2
This function makes a table from the requested info */
function makeTriggerTable($type, $id = 0) {
global $bugDatabase;
global $options;
$table = <<<EOT
<table class="list" border="1">
<tr class="list">
<td><b>ID</b></td>
<td><b>Flags</b></td>
<td><b>Rules</b></td>
<td><b>Actions</b></td>
<td><b>Delete</b></td>
</tr>
EOT;
$triggers = array();
switch($type) {
case 't':
case 'p':
while (list($key, $value) = each($bugDatabase->lists['trigger'])) {
if (($value['type'] == $type) && ($value['typeid'] == $id)) {
$triggers[$key] = $value;
}
}
break;
case 'a':
$triggers = $bugDatabase->lists['trigger'];
break;
}
if (count($triggers)) {
while (list($trigger_id, $trigger) = each($triggers)) {
$flags = array();
/* Trigger Flags {{{3 */
if ($trigger['flags'] & TRIGGER_FLAG_DISABLED) {
$flags[] = 'disabled';
}
else {
$flags[] = 'enabled';
}
if ($trigger['flags'] & TRIGGER_FLAG_MATCH_ANY) {
$flags[] = 'Match Any Rule';
}
else {
$flags[] = 'Match All Rules';
}
if ($trigger['flags'] & TRIGGER_FLAG_ADD) {
$flags[] = 'Check on ADD';
}
if ($trigger['flags'] & TRIGGER_FLAG_MODIFY) {
$flags[] = 'Check on MODIFY';
}
if ($trigger['flags'] & TRIGGER_FLAG_TIME) {
$flags[] = 'Check on SCHEDULE';
}
$flags = implode("\n", $flags);
$f = str_replace("\n", "<br />\n", htmlentities($flags));
$table .= <<<EOT
<tr>
<td><a href="{$options['baseURL']}?area=admin&action=trigger_edit&sub=trigger&num={$trigger['id']}">{$trigger['id']}</a></td>
<td><b>{$trigger['flags']}</b>:<br />
$f
</td>
EOT;
/* Trigger Flags }}}3 */
/* Trigger Rules Table {{{3 */
if (count($trigger['rules'])) {
// Assemble rule table
$table .= <<<EOT
<td valign="top">
<table class="list">
<tr>
<td>ID</td>
<td>Type</td>
</tr>
EOT;
while (list($ruleid, $rule) = each($trigger['rules'])) {
$type = getTriggerRuleDescription($rule);
$table .= <<< EOT
<tr>
<td><a href="{$options['baseURL']}?area=admin&action=trigger_edit&sub=rule&num={$trigger['id']}&rnum={$rule['id']}">{$rule['id']}</a></td>
<td><b>{$rule['type']}</b>: {$type}</td>
<td><a href="{$options['baseURL']}?area=admin&action=trigger_delete&sub=rule&num={$trigger['id']}&rnum={$rule['id']}">[Delete]</a></td>
</tr>
EOT;
}
$table .= "\t</table>\n</td>\n";
}
else {
$table .= "<td>NO RULES</td>\n";
}
/* Trigger Rules Table }}}3 */
/* Trigger Affect Table {{{3 */
// Assemble affect table...
$table .= <<<EOT
<td valign="top">
<table class="list">
<tr>
<td>ID</td>
<td>Action</td>
</tr>
EOT;
while (list($affectid, $affect) = each($trigger['affects'])) {
switch ($affect['type']) {
case TRIGGER_ACTION_NOTIFY:
$type = "Notify: Project, Owner, and Creator";
break;
case TRIGGER_ACTION_NOTIFY_PROJECT:
$type = "Notify: Project List ({$bugDatabase->lists['project'][$affect['fid']]['name']})";
break;
case TRIGGER_ACTION_NOTIFY_OWNER:
$type = "Notify: Owner";
break;
case TRIGGER_ACTION_NOTIFY_CREATOR:
$type = "Notify: Creator";
break;
case TRIGGER_ACTION_NOTIFY_OTHER:
$type = htmlentities("Notify: User ({$bugDatabase->lists['user'][$affect['fid']]['name']})");
break;
case TRIGGER_ACTION_UPDATE_FIELD:
$type = "Update {$affect['value']} to {$bugDatabase->lists['project'][$affect['fid']]['name']}";
break;
case TRIGGER_ACTION_DISABLE_TRIGGER:
$type = "Disable trigger after run";
break;
case TRIGGER_ACTION_MODIFICATION:
$type = "Modification Text: {$affect['value']}";
break;
default:
$type = "Unknown Type {$affect['type']}";
}
$table .= <<<EOT
<tr>
<td><a href="{$options['baseURL']}?area=admin&action=trigger_edit&sub=affect&num={$trigger['id']}&anum={$affect['id']}">{$affect['id']}</a></td>
<td><b>{$affect['type']}</b>: {$type}</td>
<td><a href="{$options['baseURL']}?area=admin&action=trigger_delete&sub=affect&num={$trigger['id']}&anum={$affect['id']}">[Delete]</a></td>
</tr>
EOT;
}
$table .= <<<EOT
</table></td>
<td><a href="{$options['baseURL']}?area=admin&action=trigger_delete&sub=trigger&num={$trigger['id']}">[Delete]</a></td>
EOT;
$table .= "</tr>\n";
}
return $table."</table>\n";
/* Trigger Affect Table }}}3 */
}
return "No Triggers";
}
/* }}}2 */
/* function makeTriggerTable($type, $id) {{{2
This function makes a table from the requested info */
/* }}}2 */
/* Trigger Functions }}}1 */
?>