Тема: Kayako регестрируем тикеты от лица робота из коммандной строки

Задача: все сообщения посылаемые пользователям завернуть на систему суппорта в лице Kayako. То есть чтобы все отправлялась от лица этой системы и была история. Так же это даем возможность ответить пользователю на полученное письмо и оно попадет не в общий пулл а туда куда нужно и с первоначальной информацией. То есть админу не надо будит пытать пользователя или раскапывать самому в сем дело.

По сути этот принцип можно использовать где угодно.

Средства: Для отправки выбран curl (он везде есть) для самого сообщения xml (с ним умеет работать perl, php и все что угодно). Возможно так де использовать API если такой есть, но было решено не от него отказаться, так как криворукие индусы его меняют периодически, а этот принцип более дуракоупорный, плюс позволяет расширить возможности до безграничных.

Понеслася:

1. Создаем пользователя в системе, который и будит рассылать сообщения, пусть будит Robot.
2. Анализируем поля, которые отправляются во время создания сообшения

From newticketfrom
Subject newticketsubject
OWNER newticketownerstaffid
TYPE newtickettickettypeid
STATUS newticketticketstatusid
PRIORITY newticketticketpriorityid
Send email optnewticket_sendemail
DEPARTMENT newticketdepartmentid
To taginput_newticketto
Recurrence ends recurrence_endtype
Do not recur recurrencetype
TEXT newticketcontents

3. делаем два xml'a, для короткого (по умолчанию) и для полного, с возможностью менять все.

Короткий

# cat test.xml 
<?xml version="1.0"?>
<message>
<date>
<newticketsubject>Command line autosubmit ticket script TEST!</newticketsubject>
<newticketcontents>
Test from command line
</newticketcontents>
<newticketdepartmentid>5</newticketdepartmentid>
<taginput_newticketto>[email protected]</taginput_newticketto>
</date>
</message>

Полный

# cat test_full.xml 
<?xml version="1.0"?>
<message>
<date>
<newticketfrom>0</newticketfrom>
<newticketsubject>Command line autosubmit ticket script TEST FULL!!!</newticketsubject>
<newticketownerstaffid>12</newticketownerstaffid>
<newtickettickettypeid>1</newtickettickettypeid>
<newticketticketstatusid>4</newticketticketstatusid>
<newticketticketpriorityid>1</newticketticketpriorityid>
<optnewticket_sendemail>1</optnewticket_sendemail>
<newticketdepartmentid>5</newticketdepartmentid>
<taginput_newticketto>[email protected]</taginput_newticketto>
<recurrence_endtype>1</recurrence_endtype>
<recurrencetype>1</recurrencetype>
<newticketcontents>
Test from command line
</newticketcontents>
</date>
</message>

4. Сам скрипт который принимает xml и передает его дальше, разумеется его надо защитить, basic авторизация или по IP, дело вкуса.

# cat autosubmit.php 
<pre>
<form enctype="multipart/form-data" action="autosubmit.php?send" method="POST">
    <input name="uploadedfile" type="file" />
    <input type="submit" value="go" />
</form>
<?php
/*
    Alan Vezhbitskis
    www.alan.lt
*/
$var_path = '/var/www/html/autosubmit/';
$var_url = 'https://kayako.domain.tld/';
function echoStandOutText($txt) 
{
   echo "<br>\n$txt\n<br>";
}
// upload
if (@isset ($_GET['send'])) {
    $tme = time();
    $rnd = rand(111,999);
    $target_path = $var_path."tmp/send_".$tme."-".$rnd.".xml"; 
    if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
        echo "File ".basename( $_FILES['uploadedfile']['name'])." has been uploaded<br>\n";
    } else {
        echo "Error<br>\n";
    }
} else {
    die ("Error!<br>\n");
}
// xml parser
$data = implode("", file($target_path));
$parser = xml_parser_create();
xml_parse_into_struct($parser, $data, $values, $tags);
xml_parser_free($parser);
// data compact
foreach ($values as $k=>$v) {
    if ($v['type'] == 'complete' and $v['level'] == '3') {
    $t = strtolower($v['tag']);
    $xml_date[$t] = $v['value'];
    }
}
// data check
if (array_key_exists('newticketfrom', $xml_date)) {
    // OK
} else { $xml_date['newticketfrom'] = "0"; }
if (array_key_exists('newticketsubject', $xml_date)) {
    // OK
} else { die ("newticketfrom - no value<br>\n"); }
if (array_key_exists('newticketownerstaffid', $xml_date)) {
    // OK
} else { $xml_date['newticketownerstaffid'] = ""; }
if (array_key_exists('newtickettickettypeid', $xml_date)) {
    // OK
} else { $xml_date['newtickettickettypeid'] = "1"; }
if (array_key_exists('newticketticketstatusid', $xml_date)) {
    // OK
} else { $xml_date['newticketticketstatusid'] = "4"; }
if (array_key_exists('newticketticketpriorityid', $xml_date)) {
    // OK
} else { $xml_date['newticketticketpriorityid'] = "1"; }
if (array_key_exists('newticketcontents', $xml_date)) {
    // OK
} else { die ("newticketcontents - no value<br>\n"); }
if (array_key_exists('optnewticket_sendemail', $xml_date)) {
    // OK
} else { $xml_date['optnewticket_sendemail'] = "1"; }
if (array_key_exists('newticketdepartmentid', $xml_date)) {
    // OK
} else { die ("newticketdepartmentid - no value<br>\n"); }
if (array_key_exists('taginput_newticketto', $xml_date)) {
    // OK
} else { die ("taginput_newticketto - no value<br>\n"); }
if (array_key_exists('recurrence_endtype', $xml_date)) {
    // OK
} else { $xml_date['recurrence_endtype'] = "1"; }
if (array_key_exists('recurrencetype', $xml_date)) {
    // OK
} else { $xml_date['recurrencetype'] = "0"; }
// auth
$auth_cookies = $var_path."cookies.txt";
$auth_url = $var_url."staff/index.php?/Core/Default/Login";
$auth_fields_string = "";
$auth_fields = array(
    'username'=>urlencode("autosubmit_user"),
    'password'=>urlencode("autosubmit_user_password_@#$!@#$!@#$"),
    'remember'=>'',
    'languagecode'=>'',
    'submitbutton'=>urlencode("Login")
);
// message
$sender_cookies = $var_path."cookies.txt";
$sender_url = $var_url."staff/index.php?/Tickets/Ticket/NewTicketSubmit/sendmail";
$sender_fields_string = "";
$sender_fields = array(
    'newticketfrom'=>urlencode($xml_date['newticketfrom']),
    'newticketsubject'=>urlencode($xml_date['newticketsubject']),
    'newticketownerstaffid'=>urlencode($xml_date['newticketownerstaffid']),
    'newtickettickettypeid'=>urlencode($xml_date['newtickettickettypeid']),
    'newticketticketstatusid'=>urlencode($xml_date['newticketticketstatusid']),
    'newticketticketpriorityid'=>urlencode($xml_date['newticketticketpriorityid']),
    'newticketcontents'=>urlencode($xml_date['newticketcontents']),
    'optnewticket_sendemail'=>urlencode($xml_date['optnewticket_sendemail']),
    'newticketdepartmentid'=>urlencode($xml_date['newticketdepartmentid']),
    'taginput_newticketto'=>urlencode($xml_date['taginput_newticketto']),
    'recurrence_endtype'=>urlencode($xml_date['recurrence_endtype']),
    'recurrencetype'=>urlencode($xml_date['recurrencetype']),
    ''=>urlencode(" OK ")
);
foreach($auth_fields as $key=>$value) { $auth_fields_string .= $key.'='.$value.'&'; }
$auth_fields_string=rtrim($auth_fields_string,"&");
foreach($sender_fields as $key=>$value) { $sender_fields_string .= $key.'='.$value.'&'; }
$sender_fields_string=rtrim($sender_fields_string,"&");
$ch = curl_init();
// send auth
curl_setopt ($ch, CURLOPT_USERAGENT,'ToTo/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
curl_setopt ($ch, CURLOPT_URL,$auth_url);
curl_setopt ($ch, CURLOPT_POST,count($auth_fields));
curl_setopt ($ch, CURLOPT_POSTFIELDS,$auth_fields_string);
curl_setopt ($ch, CURLOPT_COOKIEJAR, $auth_cookies);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, false);
//$output = curl_exec ($ch);
if( ! $result = curl_exec($ch)) { trigger_error(curl_error($ch)); } 
// send message
curl_setopt ($ch, CURLOPT_USERAGENT,'ToTo/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
curl_setopt ($ch, CURLOPT_URL,$sender_url);
curl_setopt ($ch, CURLOPT_POST,count($sender_fields));
curl_setopt ($ch, CURLOPT_POSTFIELDS,$sender_fields_string);
curl_setopt ($ch, CURLOPT_COOKIEJAR, $sender_cookies);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, false);
//$output = curl_exec ($ch);
if( ! $result = curl_exec($ch)) { trigger_error(curl_error($ch)); } 
curl_close($ch);
?>

5. Теперь из любой системы можно слать сообщения, главное знать кону отправлять, но обычно эти данные доступны локально или могут быть легко взяты с глобальной системы пользователей

/usr/bin/curl -k -F [email protected] https://kayako.domain.tld/autosubmit/autosubmit.php?send

Я это написал в основном для того чтобы рассылать сообщения о вирусах на хостинг серверах, но в последствии этот механизм стал применяться и при невыполнении критических крон скриптов и при проблемах с серверами (если мониторинг не чинится долгое время и никто не реагирует у админов появляется тикит, а тогда работает SLA и все такое, во общем проигнорировать уже не получится) и еще много где...