1376 lines
47 KiB
Perl
1376 lines
47 KiB
Perl
package TTXTicket;
|
|
#
|
|
# This module is a part of Trouble Ticket Express package
|
|
# http://www.troubleticketexpress.com
|
|
#
|
|
# COPYRIGHT: 2002-2006, United Web Coders
|
|
# http://www.unitedwebcoders.com
|
|
#
|
|
# $Revision: 287 $
|
|
# $Date: 2006-10-17 16:00:49 +0400 (Tue, 17 Oct 2006) $
|
|
#
|
|
|
|
$TTXTicket::VERSION='2.22';
|
|
BEGIN {
|
|
$TTXTicket::REVISION = '$Revision: 287 $';
|
|
if ($TTXTicket::REVISION =~ /(\d+)/) {
|
|
$TTXTicket::REVISION = $1;
|
|
}
|
|
};
|
|
|
|
use strict;
|
|
use TTXCommon;
|
|
require TTXUser;
|
|
use TTXTickets;
|
|
require TTXMail;
|
|
require TTXMarkup;
|
|
require TTXDictionary;
|
|
my $useGD;
|
|
|
|
# =================================================================== invenabled
|
|
|
|
my $_invenabled = undef;
|
|
|
|
sub invenabled {
|
|
if ($_invenabled eq undef) {
|
|
eval 'use TTXInvMod';
|
|
if ($@ eq undef) {
|
|
$_invenabled = 1;
|
|
} else {
|
|
$_invenabled = 0;
|
|
}
|
|
}
|
|
return $_invenabled;
|
|
}
|
|
# ====================================================================== company
|
|
|
|
sub company {
|
|
my ($cfg, $ticket) = @_;
|
|
my $cid = $cfg->get('customcompany');
|
|
my $title;
|
|
if ($cid ne undef && $cid =~ /(\d+)/) {
|
|
$cid = $1;
|
|
$title = $ticket->{"c$cid"};
|
|
}
|
|
if ($title eq undef) {
|
|
$title = $cfg->get('company');
|
|
}
|
|
return $title;
|
|
}
|
|
# =================================================================== usernotify
|
|
|
|
sub usernotify {
|
|
my $cfg = $_[0]->{cfg};
|
|
my $ticket = $_[0]->{ticket};
|
|
my $email = $ticket->{'email'};
|
|
my $name = $ticket->{'name'};
|
|
my %macros;
|
|
$name = '[%Customer%]' if $name eq undef;
|
|
my $subject;
|
|
my $messages = $ticket->{messages};
|
|
my $tmpl;
|
|
if (@{$messages} == 1) {
|
|
$tmpl = 'newticket';
|
|
if ($cfg->get('validate') ne undef) {
|
|
$tmpl .= 'validate';
|
|
$macros{ENV_HTTP_HOST} = $ENV{HTTP_HOST};
|
|
$macros{VALIDATIONCODE} = $_[0]->{validationcode};
|
|
} else {
|
|
return if $cfg->get('_USER') eq undef && $cfg->get('notikcfrm');
|
|
}
|
|
} else {
|
|
return if $cfg->get('_USER') eq undef && $cfg->get('nomsgcfrm');
|
|
$tmpl = 'newmessage';
|
|
}
|
|
if (open(TMPL, $cfg->get('basedir')."/templates/$tmpl.txt")) {
|
|
my @buff = <TMPL>;
|
|
close TMPL;
|
|
$tmpl = join('', @buff);
|
|
}
|
|
$macros{TICKETID} = $ticket->{id};
|
|
$macros{TICKETSTATE} = TTXDictionary::translate(TTXCommon::status($ticket->{status}));
|
|
$macros{UNAME} = $name;
|
|
$macros{COMPANYNAME} = company($cfg, $ticket);
|
|
$macros{UEMAIL} = $email;
|
|
$macros{OPERATORNAME} = '-';
|
|
$macros{FROM} = $_[0]->{from};
|
|
$macros{GROUP} = ($ticket->{grp} ne undef) ? $cfg->get($ticket->{grp}) : '-';
|
|
my $oper;
|
|
if ($cfg->get('_USER') ne undef) {
|
|
$oper = $cfg->get('_USER');
|
|
} elsif ($ticket->{oper} ne undef) {
|
|
$oper = TTXUser->new($ticket->{oper});
|
|
}
|
|
if ($oper ne undef) {
|
|
$macros{OPERATORNAME} = $oper->{fname}.' '.$oper->{lname};
|
|
}
|
|
my $respondername;
|
|
if ($cfg->get('askforname') ne undef) {
|
|
my $nm = $name;
|
|
$nm =~ s/[="'&><]//g;
|
|
$nm =~ s/\s/+/g;
|
|
$respondername = "&respondername=$nm";
|
|
}
|
|
$macros{TICKETURL} = '[url'." http://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}?cmd=ticket&key=".$ticket->{key}.$respondername.
|
|
'][b]Ticket '.$macros{TICKETID}.'[/b][/url]'."\n\nACCESS KEY: ".$ticket->{key};
|
|
my $msg = $messages->[@{$messages} - 1];
|
|
my @msgparts = split(/\n\n/, $msg);
|
|
shift @msgparts;
|
|
my $body = join("\n\n", @msgparts);
|
|
# $body =~s/\[b]//g;
|
|
# $body =~s/:\[\/b]/:/g;
|
|
$macros{MESSAGE} = $body;
|
|
my $cnt = TTXCommon::cfldcnt();
|
|
for (my $i = 0; $i < $cnt; ++$i) { $macros{"C$i"} = $ticket->{"c$i"}; }
|
|
my $tmplcc = $tmpl;
|
|
$tmpl =~ s/\(%\s*([A-Z0-9_]+)\s*%\)/$macros{$1}/g;
|
|
$tmpl =~ s/\[%%\]//g;
|
|
$tmpl =~ s/\[%([^]]+)%\]/TTXDictionary::translate($1)/ge;
|
|
$subject = TTXDictionary::translate('Ticket').' '.$ticket->{id};
|
|
$subject .= ", ".$ticket->{subject} if $ticket->{subject} ne undef;
|
|
TTXMail::sendmail(
|
|
{
|
|
to => $email,
|
|
from => "\"".company($cfg, $ticket)."\" <".$cfg->get('email').">",
|
|
# from => "\"".$cfg->get('company')."\" <" . (($cfg->get('_USER') ne undef && $cfg->get('_USER')->{email} ne undef)? $cfg->get('_USER')->{email}:$cfg->get('email')) . ">",
|
|
subject => $subject,
|
|
msg => $tmpl
|
|
}
|
|
);
|
|
if ($cfg->get('emaillist') ne undef) {
|
|
my $tmplname;
|
|
if (@{$messages} == 1) {
|
|
$tmplname = 'newticket';
|
|
$tmplname = 'newccticket' if -f $cfg->get('basedir')."/templates/newccticket.txt";
|
|
} else {
|
|
$tmplname = 'newmessage';
|
|
$tmplname = 'newccmessage' if -f $cfg->get('basedir')."/templates/newccmessage.txt";;
|
|
}
|
|
if (open(TMPL, $cfg->get('basedir')."/templates/$tmplname.txt")) {
|
|
my @buff = <TMPL>;
|
|
close TMPL;
|
|
$tmplcc = join('', @buff);
|
|
}
|
|
$macros{TICKETURL} = '[url '."http://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}?cmd=ticket&key=".$ticket->{key}.
|
|
'][b]Ticket '.$macros{TICKETID}.'[/b][/url]'."\n\nACCESS KEY: ".$ticket->{key};
|
|
my $n = $cfg->get('emaillist');
|
|
if ($n =~ /^\d\d?$/) {
|
|
my @addrlist = split(/,/, $ticket->{"c$n"});
|
|
$macros{UNAME} = '[%Customer%]';
|
|
foreach my $addr (@addrlist) {
|
|
$addr =~ s/\s//g;
|
|
$macros{UEMAIL} = $addr;
|
|
my $tmpltmp = $tmplcc;
|
|
$tmpltmp =~ s/\(%\s*([A-Z0-9_]+)\s*%\)/$macros{$1}/g;
|
|
$tmpltmp =~ s/\[%%\]//g;
|
|
$tmpltmp =~ s/\[%([^]]+)%\]/TTXDictionary::translate($1)/ge;
|
|
TTXMail::sendmail(
|
|
{
|
|
to => $addr,
|
|
from => "\"".company($cfg, $ticket)."\" <".$cfg->get('email').">",
|
|
subject => $subject,
|
|
msg => $tmpltmp
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# ================================================================= buildadrlist
|
|
|
|
sub buildadrlist {
|
|
my @adrlist;
|
|
foreach my $oper (@{$_[0]}) {
|
|
my $u = TTXUser->new($oper);
|
|
if ($u ne undef && $u->{email} ne undef) {
|
|
push @adrlist, $u->{email};
|
|
}
|
|
}
|
|
return @adrlist;
|
|
}
|
|
# =============================================================== transfernotice
|
|
|
|
sub transfernotice {
|
|
my $cfg = $_[0]->{cfg};
|
|
my $ticket = $_[0]->{ticket};
|
|
my $o = $cfg->get('_USER');
|
|
return if $o eq undef;
|
|
my $u = TTXUser->new($ticket->{oper});
|
|
return if $u eq undef || $u->{email} eq undef;
|
|
my $quicklink;
|
|
if ($cfg->get('quicklink')) {
|
|
$quicklink = '&o='.$ticket->{oper};
|
|
my $salt = $ticket->{id} % 100;
|
|
$salt = "0$salt" if $salt < 10;
|
|
my $p = crypt($u->{passwd}.$ticket->{id}, $salt);
|
|
$p =~ s/^\d\d//;
|
|
$quicklink .= "&p=$p";
|
|
}
|
|
TTXMail::sendmail(
|
|
{
|
|
to => $u->{email},
|
|
from => "\"".company($cfg, $ticket)."\" <".$cfg->get('email').">",
|
|
subject => TTXDictionary::translate('Ticket transfer notice'),
|
|
msg => '[b]'.TTXDictionary::translate('Ticket ID').':[/b] '.$ticket->{id}."\n".
|
|
'[b]'.TTXDictionary::translate('Subject').':[/b] '.$ticket->{subject}."\n".
|
|
'[b]'.TTXDictionary::translate('Transferred by').':[/b] '.$o->{fname}.' '.$o->{lname}.' ('.$o->{login}.") \n".
|
|
'[b]'.TTXDictionary::translate('Access link').':[/b] '.
|
|
'[url http://'.$ENV{HTTP_HOST}.$ENV{SCRIPT_NAME}.'?cmd=helpdesk&tk='.$ticket->{key}.$quicklink.']'.
|
|
TTXDictionary::translate('Ticket').' '.$ticket->{id}.'[/url]'."\n\n"
|
|
|
|
# msg => "Hello ".$u->{fname}.",\n\n".$o->{fname}." ".$o->{lname}." (".$o->{login}.") has transferred ".
|
|
# "trouble ticket #".$ticket->{id}." to you. In order to access the ticket use this link:\n\n".
|
|
# "http://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}?cmd=helpdesk&tk=".$ticket->{key}."$quicklink\n\n"
|
|
}
|
|
);
|
|
}
|
|
# =================================================================== opernotify
|
|
|
|
sub opernotify {
|
|
my $cfg = $_[0]->{cfg};
|
|
return if $cfg->get('silent');
|
|
my $ticket = $_[0]->{ticket};
|
|
my @adrlist;
|
|
if ($cfg->get('usegrpsel') && $ticket->{status} eq 'PND' && ! exists $_[0]->{notifylist}) {
|
|
my $grp;
|
|
if ($ticket->{grp} eq undef) {
|
|
$grp = $cfg->get('defaultgrp');
|
|
} else {
|
|
$grp = $ticket->{grp};
|
|
}
|
|
my @list = split(/;/, $cfg->get("mbr-$grp"));
|
|
$_[0]->{notifylist} = \@list;
|
|
}
|
|
if (exists $_[0]->{notifylist}) {
|
|
@adrlist = buildadrlist($_[0]->{notifylist});
|
|
} elsif ($ticket->{oper} ne undef) {
|
|
my @operlist = split(/,/, $ticket->{oper});
|
|
push @operlist, $cfg->get('supervisor') if $cfg->get('supervisor') ne undef;
|
|
@adrlist = buildadrlist(\@operlist);
|
|
} else {
|
|
@adrlist = TTXUser::listemail();
|
|
}
|
|
my $email = $ticket->{'email'};
|
|
my $name = $ticket->{'name'};
|
|
my %macros;
|
|
$name = '[%Customer%]' if $name eq undef;
|
|
my $messages = $ticket->{messages};
|
|
my $tmpl;
|
|
if (@{$messages} == 1) {
|
|
$tmpl = 'onewticket';
|
|
} else {
|
|
$tmpl = 'onewmessage';
|
|
}
|
|
if (open(TMPL, $cfg->get('basedir')."/templates/$tmpl.txt")) {
|
|
my @buff = <TMPL>;
|
|
close TMPL;
|
|
$tmpl = join('', @buff);
|
|
}
|
|
$macros{TICKETID} = $ticket->{id};
|
|
if (invenabled()) {
|
|
my $items = TTXInvMod::getitems($ticket->{item});
|
|
my $val = undef;
|
|
foreach my $item (@{$items}) {
|
|
$val .= ', ' if $val ne undef;
|
|
$val .= $item->{title};
|
|
}
|
|
$val = 'none' if $val eq undef;
|
|
$macros{ITEMLBL} = $cfg->get('inventory.label') || 'Item';
|
|
$macros{ITEM} = $val;
|
|
$macros{ITEMLINE} = "\n[b]$macros{ITEMLBL}:[/b] $macros{ITEM}";
|
|
}
|
|
$macros{GROUP} = ($ticket->{grp} ne undef) ? $cfg->get($ticket->{grp}) : '-';
|
|
$macros{TICKETSTATE} = TTXDictionary::translate(TTXCommon::status($ticket->{status}));
|
|
$macros{UNAME} = $name;
|
|
$macros{COMPANYNAME} = company($cfg, $ticket);
|
|
$macros{UEMAIL} = $email;
|
|
$macros{TICKETURL} = '[url '."http://$ENV{HTTP_HOST}".$cfg->get('scriptname')."?cmd=helpdesk&tk=".$ticket->{key}.
|
|
'][b]Ticket '.$macros{TICKETID}.'[/b][/url]';
|
|
my $msg = $messages->[@{$messages} - 1];
|
|
my @msgparts = split(/\n\n/, $msg);
|
|
shift @msgparts;
|
|
my $body = join("\n\n", @msgparts);
|
|
# $body =~s/\[b]//g;
|
|
# $body =~s/:\[\/b]/:/g;
|
|
$macros{MESSAGE} = $body;
|
|
my $cnt = TTXCommon::cfldcnt();
|
|
for (my $i = 0; $i < $cnt; ++$i) { $macros{"C$i"} = $ticket->{"c$i"}; }
|
|
my $tmplcpy;
|
|
if (!$cfg->get('quicklink')) {
|
|
$tmpl =~ s/\(%\s*([A-Z0-9_]+)\s*%\)/$macros{$1}/g;
|
|
$tmpl =~ s/\[%%\]//g;
|
|
$tmpl =~ s/\[%([^]]+)%\]/TTXDictionary::translate($1)/ge;
|
|
} else {
|
|
$tmplcpy = $tmpl;
|
|
}
|
|
my @oplist; # got to think about this...
|
|
if (exists $_[0]->{notifylist}) {
|
|
@oplist = @{$_[0]->{notifylist}};
|
|
} elsif ($ticket->{oper} ne undef) {
|
|
@oplist = split(/,/, $ticket->{oper});
|
|
push @oplist, $cfg->get('supervisor') if $cfg->get('supervisor') ne undef;
|
|
} else {
|
|
@oplist = TTXUser::list();
|
|
}
|
|
foreach my $adr (@adrlist) {
|
|
my $oper = shift @oplist;
|
|
if ($oper ne undef) { # just to make sure
|
|
my $u = TTXUser->new($oper);
|
|
if ($u ne undef && $u->{email} ne undef) {
|
|
if ($cfg->get('quicklink')) {
|
|
my $tmp = $macros{TICKETURL};
|
|
$macros{TICKETURL} .= '&o='.$oper;
|
|
my $salt = $ticket->{id} % 100;
|
|
$salt = "0$salt" if $salt < 10;
|
|
my $p = crypt($u->{passwd}.$ticket->{id}, $salt);
|
|
$p =~ s/^\d\d//;
|
|
$macros{TICKETURL} .= "&p=$p";
|
|
$tmpl = $tmplcpy;
|
|
$tmpl =~ s/\(%\s*([A-Z0-9_]+)\s*%\)/$macros{$1}/g;
|
|
$tmpl =~ s/\[%%\]//g;
|
|
$tmpl =~ s/\[%([^]]+)%\]/TTXDictionary::translate($1)/ge;
|
|
$macros{TICKETURL} = $tmp;
|
|
}
|
|
my $subject = TTXDictionary::translate('Ticket').' '.$ticket->{id};
|
|
if ($u->{usemail}) {
|
|
$ticket->{key} =~ /Z(\w\w\w\w)/;
|
|
$subject .= ' ('.$u->{snum}."-$1)";
|
|
}
|
|
$subject .= ", ".$ticket->{subject} if $ticket->{subject} ne undef;
|
|
TTXMail::sendmail(
|
|
{
|
|
to => $adr,
|
|
from => "\"".company($cfg, $ticket)."\" <".$cfg->get('email').">",
|
|
subject => $subject,
|
|
msg => $tmpl
|
|
}
|
|
);
|
|
} else {
|
|
next;
|
|
}
|
|
} else {
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
# ====================================================================== keyform
|
|
|
|
sub keyform {
|
|
my ($cfg, $query, $data) = @_;
|
|
$data->{PAGEHEADING} = '[%Access Key%]';
|
|
$data->{MESSAGE} = '[%Forgot the key? We will send it to your email address.%]';
|
|
return undef if !$query->param('do');
|
|
$query->param(-name => 'do', -value => '');
|
|
if ($query->param('cancel') ne undef) {
|
|
if ($cfg->get('_USER') ne undef) { return 'helpdesk'; }
|
|
else { return 'newticket'; }
|
|
}
|
|
if ($query->param('cmd') eq 'keyform') {
|
|
my $key = TTXCommon::cleanit($query, 'key');
|
|
if ($key eq undef) {
|
|
$data->{ERROR_MESSAGE} = '[%Missing access key%]';
|
|
return undef;
|
|
}
|
|
if ($cfg->get('shortkey')) {
|
|
if ($key !~ /^\d+$/) {
|
|
$data->{ERROR_MESSAGE} = '[%Invalid access key%]';
|
|
return undef;
|
|
}
|
|
} elsif ($key !~ /^\d+Z\d+$/) {
|
|
$data->{ERROR_MESSAGE} = '[%Invalid access key%]';
|
|
return undef;
|
|
}
|
|
return 'ticket';
|
|
}
|
|
# keyfinder code
|
|
my $email = TTXCommon::cleanit($query, 'email');
|
|
if ($email eq undef) {
|
|
$data->{ERROR_MESSAGE} = '[%Missing email address%]';
|
|
return undef;
|
|
}
|
|
if ($email !~ /^[0-9A-Za-z._-]+@[0-9A-Za-z_-]+\.[0-9A-Za-z._-]+$/) {
|
|
$data->{ERROR_MESSAGE} = '[%Invalid email address%]';
|
|
return undef;
|
|
}
|
|
my $tickets = TTXCommon::dbtik();
|
|
if ($tickets eq undef || $tickets->error() ne undef) {
|
|
$data->{ERROR_MESSAGE} = $tickets->errortext();
|
|
return undef;
|
|
}
|
|
my @filter;
|
|
my $f;
|
|
$f->{col} = 'email';
|
|
$f->{expr} = "^$email\$";
|
|
push @filter, $f;
|
|
my $browser = $tickets->list(0, 999, 'id', 'A', \@filter);
|
|
my $list = $browser->{list};
|
|
if (@{$list} < 1) {
|
|
$data->{ERROR_MESSAGE} = '[%No tickets found%]';
|
|
} else {
|
|
my $body;
|
|
foreach my $id (@{$list}) {
|
|
my $t = $tickets->ticket($id);
|
|
$body .= "#".$id." (".$t->{subject}.") KEY: ".$t->{key}."\n";
|
|
}
|
|
$tickets = undef;
|
|
$body = TTXDictionary::translate('Dear customer,')."\n\n".
|
|
TTXDictionary::translate('This is a list of all service tickets associated '.
|
|
'with your email address')."\n\n$body\n";
|
|
$body .= TTXDictionary::translate('Use the following link to access your tickets')."\n".
|
|
"[url http://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}?cmd=ticket]Show Ticket[/url]\n\n".
|
|
TTXDictionary::translate('Kind Regards')."\n".$cfg->get('company')."\n";
|
|
TTXMail::sendmail(
|
|
{
|
|
to => $email,
|
|
from => "\"".$cfg->get('company')."\" <".$cfg->get('email').">",
|
|
subject => TTXDictionary::translate('Access key(s)'),
|
|
msg => $body
|
|
}
|
|
);
|
|
$data->{MESSAGE} = '<b>[%Access keys were sent to your email address.%]</b>';
|
|
}
|
|
return undef;
|
|
}
|
|
# ================================================================== checkgroups
|
|
my $groupsenabled;
|
|
sub checkgroups {
|
|
if ($groupsenabled eq undef) {
|
|
eval "use TTXGroups";
|
|
if (!$@) {
|
|
$groupsenabled = 1;
|
|
} else {
|
|
$groupsenabled = 0;
|
|
if ($_[0]->get('usegrpsel')) {
|
|
$_[0]->set('usegrpsel', 0);
|
|
$_[0]->save();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# ========================================================================== kid
|
|
|
|
sub kid {
|
|
my ($cfg, $query, $data, $useold) = @_;
|
|
eval "use GD" if !$useGD;
|
|
if ($useGD || $@ eq undef) {
|
|
$useGD = 1;
|
|
my $datadir = $cfg->get('basedir');
|
|
my $keyid;
|
|
my $oldid = TTXCommon::cleanit($query, 'kid');
|
|
if ($oldid ne undef && $oldid !~ /^\d+-\d+$/) {
|
|
$oldid = undef;
|
|
$query->param(-name => 'kid', -value => '');
|
|
}
|
|
if ($oldid ne undef && $useold && (-f "$datadir/keys/$oldid.cgi")) {
|
|
$keyid = $oldid;
|
|
} else {
|
|
$query->param(-name => 'kid', -value => '');
|
|
if (-f "$datadir/keys/$oldid.cgi") {
|
|
unlink "$datadir/keys/$oldid.cgi";
|
|
}
|
|
$keyid = time(). "-$$";
|
|
$useold = 0;
|
|
}
|
|
if (! -d "$datadir/keys") {
|
|
mkdir("$datadir/keys", 0777);
|
|
}
|
|
if (-d "$datadir/keys") {
|
|
if (!$useold && open(KF, ">$datadir/keys/$keyid.cgi")) {
|
|
my $key = 999 + int rand(9000);
|
|
print KF "$key\n";
|
|
close KF;
|
|
}
|
|
$data->{KID} = $keyid;
|
|
my $keycode;
|
|
if ($useold && $oldid ne undef) {
|
|
$keycode = TTXCommon::cleanit($query, 'keycode');
|
|
$keycode =~ s/"/"/g;
|
|
}
|
|
$data->{KIDVAL} = <<EOT;
|
|
<input type=text name=keycode size=6 value="$keycode">
|
|
<input type=hidden name=kid value="$keyid">
|
|
EOT
|
|
|
|
$data->{KIDIMG} = "<img src=\"key.cgi?$keyid\" width=50 height=20 />";
|
|
$data->{KIDFORM} = <<EOT;
|
|
<tr>
|
|
<td align=right><b>[%Access code%]</b></td>
|
|
<td align=left>
|
|
<table>
|
|
<tr>
|
|
<td><img src="key.cgi?$keyid" width=50 height=20 /></td>
|
|
<td>[%Copy the code here%]: </td>
|
|
<td><input type=text name=keycode size=6 value="$keycode">
|
|
<input type=hidden name=kid value="$keyid"></td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
|
|
EOT
|
|
}
|
|
}
|
|
}
|
|
# ==================================================================== newticket
|
|
|
|
sub newticket {
|
|
my ($cfg, $query, $data) = @_;
|
|
my $cfn; # captcha code file name
|
|
$data->{PAGEHEADING} = '[%Contact Customer Service%]';
|
|
if (TTXData::get('ISPRO')) {
|
|
$data->{FILEFORMS} = TTXFile::fileforms();
|
|
}
|
|
if ($cfg->get('_USER') ne undef) {
|
|
$data->{INTERNALCHECKBOX} = '<input type=checkbox name=internal value=1' .
|
|
($query->param('internal') ? ' checked':''). '> <span class=lbl>[%Internal%]</span>';
|
|
} else {
|
|
$data->{INTERNALCHECKBOX} = ' ';
|
|
}
|
|
checkgroups($cfg);
|
|
if ($cfg->get('usegrpsel')) {
|
|
TTXGroups::selector($cfg, $query, $data);
|
|
}
|
|
if ($cfg->get('inventory.show') && invenabled()) {
|
|
TTXInvMod::selector($cfg, $query, $data);
|
|
}
|
|
if ($cfg->get('useopersel')) {
|
|
eval "use TTXOpers";
|
|
if (!$@) {
|
|
TTXOpers::selector($cfg, $query, $data);
|
|
} else {
|
|
$cfg->set('useopersel', 0);
|
|
}
|
|
}
|
|
eval "use TTXLayout";
|
|
if (!$@) {
|
|
my $ldver;
|
|
eval '$ldver = $TTXLayout::VERSION';
|
|
if ($ldver >= '2.22') {
|
|
my $cfldcnt = TTXCommon::cfldcnt();
|
|
for (my $i = 0; $i < $cfldcnt; ++$i) {
|
|
$data->{"CUSTOM$i"} = TTXLayout::cfld($query, $i);
|
|
$data->{"CUSTOMROW$i"} = TTXLayout::cfldrow($query, $i);
|
|
$data->{"CUSTOMVARS"} .= $data->{"CUSTOMROW$i"};
|
|
}
|
|
}
|
|
}
|
|
if (!$query->param('do')) {
|
|
foreach my $input ('email', 'name') {
|
|
if ($query->param($input) eq undef) {
|
|
$query->param(-name => $input, -value => $cfg->get("_GLOBAL_newticket_$input"));
|
|
}
|
|
}
|
|
kid($cfg, $query, $data, 0) if $cfg->get('useaccesscode');
|
|
return undef;
|
|
}
|
|
$query->param(-name => 'do', -value => '');
|
|
if ($query->param('cancel') ne undef) {
|
|
$query->param(-name => 'cancel', -value => '');
|
|
if ($cfg->get('_USER') ne undef) {
|
|
$query->param(-name => 'tid', -value=> '');
|
|
return 'helpdesk';
|
|
} else {
|
|
return undef;
|
|
}
|
|
}
|
|
my $ticket;
|
|
$ticket->{grp} = TTXCommon::cleanit($query, 'grp');
|
|
$ticket->{name} = TTXCommon::cleanit($query, 'name');
|
|
$ticket->{email} = TTXCommon::cleanit($query, 'email');
|
|
$ticket->{subject} = TTXCommon::cleanit($query, 'subject');
|
|
if (invenabled()) {
|
|
my @items = $query->param('item');
|
|
if (grep(/^-$/, @items) || !int(@items)) {
|
|
@items = ('-');
|
|
$ticket->{item} = '';
|
|
} else {
|
|
$ticket->{item} = ';'.join(';', @items).';';
|
|
}
|
|
}
|
|
my $error;
|
|
if ($ticket->{name} eq undef) {
|
|
$error .= '[%Missing Name%]<br>';
|
|
}
|
|
$ticket->{lname} = $ticket->{name};
|
|
$ticket->{name} =~ /\s(\w+)$/;
|
|
$ticket->{lname} = $1 if $1 ne undef;
|
|
if ($ticket->{email} eq undef) {
|
|
$error .= '[%Missing Email%]<br>'."\n";
|
|
} elsif ($ticket->{email} !~ /^[0-9A-Za-z'._-]+@[0-9A-Za-z_-]+\.[0-9A-Za-z._-]+$/) {
|
|
$error .= "Invalid Email<br>";
|
|
}
|
|
if ($ticket->{grp} eq undef && $cfg->get('usegrpsel')) {
|
|
$error .= TTXDictionary::translate('Missing').' '.($cfg->get('grpsellbl') || '[%Department%]')."<br>";
|
|
}
|
|
if ($ticket->{subject} eq undef) {
|
|
$error .= '[%Missing Subject%]<br>';
|
|
}
|
|
my $useold = 0;
|
|
if ($cfg->get('useaccesscode')) {
|
|
eval "use GD" if !$useGD;
|
|
if ($useGD || $@ eq undef) {
|
|
$useGD = 1;
|
|
my $kid = TTXCommon::cleanit($query, 'kid');
|
|
if ($kid !~ /^\d+-\d+$/) {
|
|
$error .= '[%Corrupted access code%]<br>';
|
|
} else {
|
|
$cfn = $cfg->get('basedir')."/keys/$kid.cgi";
|
|
my $key = TTXCommon::cleanit($query, 'keycode');
|
|
if ($key eq undef) {
|
|
$error .= '[%Missing access code%]<br>';
|
|
} else {
|
|
if (!open(KF, $cfn)) {
|
|
$error .= '[%Expired access code%]<br>';
|
|
} else {
|
|
my $k = <KF>;
|
|
close KF;
|
|
chomp $k;
|
|
if ($k ne $key) {
|
|
$error .= '[%Invalid access code%]<br>';
|
|
} else {
|
|
$useold = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($cfg->get('useopersel') && $query->param('oper') eq undef) {
|
|
$error .= '[%Missing Operator%] (<i>[%to assign the ticket to%]</i>)<br>';
|
|
}
|
|
my $custom;
|
|
my @inputs = sort $query->param();
|
|
my @mandatory = split(/\s*,\s*/,$query->param('mandatory'));
|
|
my $cfldcnt = TTXCommon::cfldcnt();
|
|
foreach my $input (@inputs) {
|
|
next if $input !~ /^x./;
|
|
next if $query->param($input) eq undef;
|
|
@mandatory = grep { $_ ne $input } @mandatory;
|
|
my $val = $query->param($input);
|
|
my $cidx;
|
|
if ($cfg->get($input) ne undef) {
|
|
$cidx = int ($cfg->get($input));
|
|
if ($cidx >= 0 && $cidx < $cfldcnt) {
|
|
if ($cfg->get("c$cidx.type") eq 'list') {
|
|
my @vals = $query->param($input);
|
|
my @allow = split(/;/, $cfg->get("dropdown$cidx"));
|
|
my @accept;
|
|
foreach my $v (@vals) {
|
|
push @accept, $v if grep(/^$v$/, @allow);
|
|
}
|
|
$val = join(';', @accept);
|
|
$ticket->{"c$cidx"} = ";$val;" if $val ne undef;
|
|
|
|
} else {
|
|
$ticket->{"c$cidx"} = $val;
|
|
}
|
|
}
|
|
}
|
|
$input =~ s/^x//;
|
|
$custom .= "[b]$input:[/b] $val\n";
|
|
}
|
|
$custom .= "\n" if $custom ne undef;
|
|
foreach my $mid (@mandatory) {
|
|
$mid =~ s/^x//;
|
|
$error .= '[%Missing%]'." $mid<br>\n";
|
|
}
|
|
if ($error ne undef) {
|
|
$error =~ s/<br>$//;
|
|
$data->{ERROR_MESSAGE} = $error;
|
|
kid($cfg, $query, $data, $useold) if $cfg->get('useaccesscode');
|
|
return undef;
|
|
}
|
|
foreach my $input ('email', 'name') {
|
|
$cfg->set("_GLOBAL_newticket_$input", $query->param($input));
|
|
}
|
|
TTXCommon::cleanit($query, 'problem');
|
|
my $tickets = TTXCommon::dbtik();
|
|
if ($tickets->error() ne undef || !$tickets->addticket($ticket)) {
|
|
$data->{ERROR_MESSAGE} = $tickets->errortext();
|
|
kid($cfg, $query, $data, $useold) if $cfg->get('useaccesscode');
|
|
return undef;
|
|
}
|
|
if ($cfg->get('validate') ne undef) {
|
|
my $n = $cfg->get('validate');
|
|
if ($n =~ /^\d\d?$/) {
|
|
$ticket->{"c$n"} = 'N';
|
|
srand($ticket->{open});
|
|
my $k = int (rand(999999));
|
|
$data->{VALIDATIONCODE} = $ticket->{id}."Z$k";
|
|
}
|
|
}
|
|
my @messages;
|
|
$messages[0] = "From: ".$ticket->{name}."\nDate: ".time()."\nIP: $ENV{REMOTE_ADDR}\n";
|
|
if ($query->param('internal')) {
|
|
$messages[0] .= "Operator: 1\nInternal: Yes\n";
|
|
}
|
|
if (TTXData::get('ISPRO')) {
|
|
for (my $i = 1; $i < 4; ++$i) {
|
|
next if $query->param("f$i") eq undef;
|
|
$messages[0] .= TTXFile::addfile($query, "f$i", "fname$i", $ticket->{id});
|
|
}
|
|
}
|
|
my $autoassignmsg;
|
|
if ($cfg->get('useopersel') && $query->param('oper') ne undef && $query->param('oper') ne '-') {
|
|
my $u = TTXUser->new($query->param('oper'));
|
|
if ($u ne undef) {
|
|
$ticket->{oper} = $u->{login};
|
|
$ticket->{status} = 'OPN';
|
|
$autoassignmsg = '[%The ticket is assigned to%] '.$u->{fname}.' '.$u->{lname}."\n\n";
|
|
}
|
|
}
|
|
$messages[0] .= "\n$custom$autoassignmsg".substr($query->param('problem'),0,32*1024);
|
|
$ticket->{messages} = \@messages;
|
|
if (!$tickets->save()) {
|
|
$data->{ERROR_MESSAGE} = $tickets->errortext();
|
|
kid($cfg, $query, $data, $useold) if $cfg->get('useaccesscode');
|
|
return undef;
|
|
}
|
|
unlink $cfn if $cfn ne undef && -f $cfn;
|
|
$tickets = undef;
|
|
$data->{TICKETID} = $ticket->{id};
|
|
$data->{TICKETKEY} = $ticket->{key};
|
|
usernotify({cfg => $cfg, ticket => $ticket, validationcode => $data->{VALIDATIONCODE}})
|
|
if !$query->param('internal');
|
|
if ($cfg->get('validate') eq undef) {
|
|
my $opernotifydata = {cfg => $cfg, ticket => $ticket};
|
|
if ($cfg->get('supervisor') ne undef) {
|
|
my @list = ($cfg->get('supervisor'));
|
|
$opernotifydata->{notifylist} = \@list;
|
|
} elsif ($cfg->get('usegrpsel')) {
|
|
my @list = split(/;/, $cfg->get("mbr-".$ticket->{grp}));
|
|
$opernotifydata->{notifylist} = \@list;
|
|
} elsif ($cfg->get('routex') ne undef) {
|
|
eval "use TTXCustomRoute";
|
|
if ($@ eq undef) {
|
|
my @list = TTXCustomRoute::routelist($cfg, $ticket);
|
|
$opernotifydata->{notifylist} = \@list;
|
|
}
|
|
}
|
|
opernotify($opernotifydata);
|
|
}
|
|
if ($cfg->get('report')) {
|
|
eval "use TTXEReport";
|
|
if ($@ eq undef) {
|
|
TTXEReport::reportopen($cfg, $ticket);
|
|
}
|
|
}
|
|
if ($cfg->get('internaldesk')) {
|
|
$query->param(-name => 'reset', -value => 1);
|
|
return 'helpdesk';
|
|
}
|
|
if ($query->param('noconfirmation')) {
|
|
$query->param(-name => 'reset', -value => 1);
|
|
return 'helpdesk';
|
|
}
|
|
return 'confirmnew';
|
|
}
|
|
# =================================================================== confirmnew
|
|
|
|
sub confirmnew {
|
|
my ($cfg, $query, $data) = @_;
|
|
return undef;
|
|
}
|
|
# ==================================================================== fid2title
|
|
my $_f2t;
|
|
sub fid2title {
|
|
if ($_f2t eq undef) {
|
|
eval 'use TTXData';
|
|
my $cfg;
|
|
eval '$cfg = TTXData::get'."('CONFIG')";
|
|
return $_[0] if $cfg eq undef;
|
|
my @xflds = grep(/^x/, $cfg->vars());
|
|
foreach my $xfld (@xflds) {
|
|
my $t = $xfld;
|
|
$t =~ s/^x//;
|
|
$_f2t->{'c'.$cfg->get($xfld)} = $t;
|
|
}
|
|
}
|
|
return $_f2t->{$_[0]} || $_[0];
|
|
}
|
|
# ======================================================================= wanted
|
|
|
|
sub wanted {
|
|
my ($cfg, $query, $ticket) = @_;
|
|
my $buff;
|
|
if ($cfg->get('mandatoryfields') ne undef) {
|
|
my @mflist = split(/;/, $cfg->get('mandatoryfields'));
|
|
foreach my $fid (@mflist) {
|
|
next if $fid !~ /^c\d+$/;
|
|
my $title = fid2title($fid);
|
|
$title =~ s/</</g;
|
|
$buff .= "<tr>\n<td align=left class=lbl>$title</td>\n<td align=left>";
|
|
my $id = $fid; $id =~ s/^c//;
|
|
if ($cfg->get("dropdown$id") ne undef) {
|
|
$buff .= "<select name=wanted$id>\n";
|
|
if ($ticket->{$fid} eq undef) {
|
|
if ($query->param("wanted$id") eq undef) {
|
|
$buff .= "<option></option>\n";
|
|
}
|
|
} elsif ($query->param("wanted$id") eq undef) {
|
|
$query->param(-name => "wanted$id", -value => $ticket->{$fid});
|
|
}
|
|
my @options = split(/;/, $cfg->get("dropdown$id"));
|
|
foreach my $option (@options) {
|
|
my $safeoption1 = $option;
|
|
my $safeoption2 = $option;
|
|
$safeoption1 =~ s/"/"/g;
|
|
$safeoption2 =~ s/</</g;
|
|
$buff .= "<option value=\"$safeoption1\"";
|
|
if ($option eq $query->param("wanted$id")) {
|
|
$buff .= ' selected';
|
|
}
|
|
$buff .= ">$safeoption2</option>\n";
|
|
}
|
|
$buff .= "</select>\n";
|
|
} else {
|
|
my $val = $query->param('do') ? $query->param("wanted$id") : $ticket->{$fid};
|
|
$val =~ s/"/"/g;
|
|
$buff .= "<input type=text size=25 name=wanted$id value=\"$val\">\n";
|
|
}
|
|
$buff .= "</td>\n</tr>\n";
|
|
}
|
|
if ($buff ne undef) {
|
|
$buff = "<table width=".$cfg->get('HTMLBASEWIDTH')."cellspacing=0 cellpadding=0 bgcolor=\"#CFDCE8\">\n".
|
|
"<tr>\n<td align=center>\n".
|
|
"<table cellpadding=3>$buff</table>\n".
|
|
"</td>\n</tr>\n".
|
|
"</table>\n";
|
|
}
|
|
}
|
|
return $buff;
|
|
}
|
|
# ======================================================================= lockdb
|
|
my $lockcnt;
|
|
sub lockdb {
|
|
return ++$lockcnt if $lockcnt;
|
|
my $cfg = TTXData::get('CONFIG');
|
|
return 1 if $cfg->get('dbmode') !~ /sql/;
|
|
my $lockfile = $cfg->get('basedir')."/lockdb.ttx";
|
|
if (! -f $lockfile) {
|
|
if (!open(LOCK, ">$lockfile")) {
|
|
return 0;
|
|
}
|
|
} elsif (!open(LOCK,"+<$lockfile")) {
|
|
return 0;
|
|
}
|
|
flock(LOCK, 2);
|
|
$lockcnt = 1;
|
|
return 1;
|
|
}
|
|
# ===================================================================== unlockdb
|
|
|
|
sub unlockdb {
|
|
return if !$lockcnt;
|
|
my $cfg = TTXData::get('CONFIG');
|
|
return if $cfg->get('dbmode') !~ /sql/;
|
|
--$lockcnt;
|
|
if (!$lockcnt) {
|
|
flock(LOCK, 8);
|
|
close LOCK;
|
|
}
|
|
}
|
|
# ======================================================================== claim
|
|
|
|
sub claim {
|
|
my ($cfg, $query, $data) = @_;
|
|
if ($query->param('cancel') ne undef) {
|
|
$query->param(-name => 'tid', -value=> '');
|
|
$query->param(-name => 'do', -value => '');
|
|
return 'helpdesk';
|
|
}
|
|
return undef if !$query->param('do');
|
|
$query->param(-name => 'do', -value => '');
|
|
lockdb();
|
|
my $tickets = TTXCommon::dbtik();
|
|
if ($tickets eq undef || $tickets->error() ne undef) {
|
|
$data->{ERROR_MESSAGE} = $tickets->errortext();
|
|
unlockdb();
|
|
return undef;
|
|
}
|
|
my $t = $tickets->ticketbykey(TTXCommon::cleanit($query, 'key'));
|
|
if ($t eq undef) {
|
|
$data->{ERROR_MESSAGE} = '[%Invalid access key%]';
|
|
$query->param(-name => 'tid', -value=> '');
|
|
unlockdb();
|
|
return 'helpdesk';
|
|
}
|
|
if ($t->{oper} ne undef) {
|
|
$data->{ERROR_MESSAGE} = '[%The ticket is already assigned to%] '.$t->{oper};
|
|
} else {
|
|
if ($cfg->get('mandatoryfields') ne undef && $query->param('delete') eq undef) {
|
|
my @mflist = split(/;/, $cfg->get('mandatoryfields'));
|
|
my $err;
|
|
foreach my $fid (@mflist) {
|
|
next if $fid !~ /^c\d+$/;
|
|
my $id = $fid; $id =~ s/^c//;
|
|
if ($query->param("wanted$id") ne undef) {
|
|
$t->{$fid} = $query->param("wanted$id");
|
|
} elsif ($t->{$fid} eq undef) {
|
|
$err .= '[%Missing%] '.fid2title($fid)."<br>";
|
|
}
|
|
}
|
|
if ($err ne undef) {
|
|
$data->{ERROR_MESSAGE} = $err;
|
|
$data->{WANTED} = wanted($cfg, $query, $t);
|
|
unlockdb();
|
|
return 'ticket';
|
|
}
|
|
}
|
|
$t->{oper} = $cfg->get('_USER')->get('login');
|
|
$t->{status} = 'OPN';
|
|
if ($cfg->get('claimtime') ne undef) {
|
|
my $totaltm = int ((time() - $t->{open})/60);
|
|
my $totaltmm = $totaltm % 60;
|
|
my $totaltmh = int(($totaltm - $totaltmm) / 60);
|
|
$totaltmm = "0$totaltmm" if $totaltmm < 10;
|
|
$totaltmh = "0$totaltmh" if $totaltmh < 10;
|
|
$t->{'c'.$cfg->get('claimtime')} = $totaltmh.':'.$totaltmm;
|
|
}
|
|
$tickets->save();
|
|
TTXCommon::logit("CLAIM|".$t->{oper}."|".$t->{id});
|
|
if ($query->param('delete') ne undef) {
|
|
my $oper = $cfg->get('_USER')->get('login');
|
|
if (!($cfg->get('demo') && $oper ne 'admin') &&
|
|
($cfg->get('grant.delete') eq undef || grep(/^$oper$/, split(/,/, $cfg->get('grant.delete'))))) {
|
|
$tickets->deltik($t->{id});
|
|
$tickets->save();
|
|
}
|
|
$query->param(-name => 'tid', -value=> '');
|
|
unlockdb();
|
|
return 'helpdesk';
|
|
}
|
|
}
|
|
unlockdb();
|
|
return 'ticket';
|
|
}
|
|
# ======================================================================= ticket
|
|
|
|
sub ticket {
|
|
my ($cfg, $query, $data) = @_;
|
|
checkgroups($cfg);
|
|
TTXCommon::tickedvars($cfg, $data);
|
|
if ($query->param('cancel') ne undef) {
|
|
if ($query->param('sid') ne undef) {
|
|
$query->param(-name => 'tid', -value=> '');
|
|
$query->param(-name => 'do', -value=> '');
|
|
return 'helpdesk';
|
|
} else {
|
|
if ($query->param('emailkey') ne undef) {
|
|
return 'mytickets';
|
|
} else {
|
|
return 'newticket';
|
|
}
|
|
}
|
|
}
|
|
if ($query->param('key') eq undef) {
|
|
return 'keyform';
|
|
}
|
|
my $tickets = TTXCommon::dbtik();
|
|
if ($tickets eq undef || $tickets->error() ne undef) {
|
|
$data->{ERROR_MESSAGE} = $tickets->errortext();
|
|
return undef;
|
|
}
|
|
my $t = $tickets->ticketbykey(TTXCommon::cleanit($query, 'key'));
|
|
if ($t eq undef) {
|
|
$data->{ERROR_MESSAGE} = $cfg->get('shortkey') ? '[%Ticket does not exist%]':'[%Invalid access key%]';
|
|
return 'keyform';
|
|
}
|
|
$query->param(-name => 'tid', -value=> $t->{id});
|
|
my $cmd;
|
|
my $isoper = 0;
|
|
my $readonly;
|
|
if ($cfg->get('_USER') ne undef) {
|
|
$readonly = $cfg->get('_USER')->get('ro') ? 1:0;
|
|
if (!$readonly) {
|
|
my $oper = $cfg->get('_USER')->get('login');
|
|
my $candel;
|
|
if (!($cfg->get('demo') && $oper ne 'admin') &&
|
|
($cfg->get('grant.delete') eq undef || grep(/^$oper$/, split(/,/, $cfg->get('grant.delete'))))) {
|
|
$candel = 1;
|
|
}
|
|
if ($t->{oper} eq undef) {
|
|
$cmd = 'claim';
|
|
$data->{WANTED} = wanted($cfg, $query, $t);
|
|
if ($candel) {
|
|
$data->{DELTICKET} = ' <input type=submit onsubmit name=delete onclick="return confirmdel()" value="[%Delete ticket%]">';
|
|
}
|
|
} else {
|
|
if ($candel) {
|
|
$data->{DELTICKET} = '<input type=submit onsubmit name=delete onclick="return confirmdel()" value="[%Delete ticket%]">';
|
|
}
|
|
}
|
|
$data->{TICKEDOPEN} = "<a href=# onClick=\"return ticked('".$query->param('tid')."')\">";
|
|
$data->{TICKEDCLOSE} = '</a>';
|
|
$data->{ANSWERLIB} = ' <a href=#teditor onClick="return answerlib()">[%Answer library%]</a>';
|
|
}
|
|
$isoper = 1;
|
|
}
|
|
if ($query->param('do') && $t->{status} eq 'CLS' && !$isoper) {
|
|
$query->param(-name => 'email', -value => $t->{email});
|
|
$query->param(-name => 'name', -value => $t->{name});
|
|
$query->param(-name => 'subject', -value => $t->{subject});
|
|
$query->param(-name => 'problem', -value => TTXDictionary::translate('Posted as a followup to the solved ticket').' #'.$t->{id}.
|
|
".\n\n".$query->param('problem'));
|
|
return 'newticket';
|
|
}
|
|
if ($t->{status} =~ /OPN|WFR/ && !$readonly) {
|
|
$data->{PREVIEW} .= ' <a href=#teditor onClick="return preview()">[%Preview%]</a>';
|
|
}
|
|
my $notify;
|
|
my $xupdate = 0;
|
|
my @inputs = $query->param();
|
|
@inputs = grep(/^x/, @inputs);
|
|
my $cfldcnt = TTXCommon::cfldcnt();
|
|
foreach my $input (@inputs) {
|
|
my $val = TTXCommon::cleanit($query, $input);
|
|
my $n = $cfg->get($input);
|
|
next if $n eq undef || $n =~ /[^0-9]/ || $n < 0 || $n >= $cfldcnt;
|
|
if ($val ne $t->{"c$n"}) {
|
|
$t->{"c$n"} = $val;
|
|
$xupdate = 1;
|
|
}
|
|
}
|
|
if ($cmd eq undef && $query->param('do')) {
|
|
if ($readonly) {
|
|
$query->param(-name => 'do', -value=> '');
|
|
$query->param(-name => 'tid', -value=> '');
|
|
return 'helpdesk';
|
|
}
|
|
if ($isoper && $query->param('delete') ne undef) {
|
|
my $oper = $cfg->get('_USER')->get('login');
|
|
if (!($cfg->get('demo') && $oper ne 'admin') &&
|
|
($cfg->get('grant.delete') eq undef || grep(/^$oper$/, split(/,/, $cfg->get('grant.delete'))))) {
|
|
$tickets->deltik($t->{id});
|
|
$tickets->save();
|
|
}
|
|
$query->param(-name => 'do', -value=> '');
|
|
$query->param(-name => 'tid', -value=> '');
|
|
return 'helpdesk';
|
|
}
|
|
my $attachment;
|
|
if (TTXData::get('ISPRO')) {
|
|
for (my $i = 1; $i < 4; ++$i) {
|
|
next if $query->param("f$i") eq undef;
|
|
$attachment .= TTXFile::addfile($query, "f$i", "fname$i", $t->{id});
|
|
}
|
|
}
|
|
if ($query->param('problem') eq undef && $attachment ne undef) {
|
|
$query->param(-name => 'problem', -value => 'See attachment');
|
|
}
|
|
if ($query->param('problem') eq undef && $query->param('newstatus') eq 'CLS') {
|
|
$query->param(-name => 'problem', -value => TTXDictionary::translate('Ticket closed'));
|
|
}
|
|
if ($query->param('problem') eq undef &&
|
|
($query->param('newstatus') eq undef || $t->{status} eq $query->param('newstatus')) &&
|
|
($query->param('transfer') eq undef || $t->{oper} eq $query->param('transfer')) &&
|
|
!$xupdate) {
|
|
$data->{ERROR_MESSAGE} = '[%Missing message%]';
|
|
} elsif (!$isoper && $cfg->get('askforname') && TTXCommon::cleanit($query, 'respondername') eq undef) {
|
|
$data->{ERROR_MESSAGE} = '[%Missing name%]';
|
|
} else {
|
|
if ($isoper && $cfg->get('tracktime') ne undef) {
|
|
my $ttx = $cfg->get('tracktime');
|
|
if ($ttx ne undef && $ttx !~ /[^0-9]/ && $ttx >= 0 && $ttx < $cfldcnt) {
|
|
my $tth = int(TTXCommon::cleanit($query, 'tracktimeh'));
|
|
my $ttm = int(TTXCommon::cleanit($query, 'tracktimem'));
|
|
$query->param(-name => 'tracktimeh', -value => '');
|
|
$query->param(-name => 'tracktimem', -value => '');
|
|
my ($totaltmh, $totaltmm) = split(/:/, $t->{"c$ttx"});
|
|
my $totaltm = $totaltmh * 60 + $totaltmm;
|
|
$totaltm += $tth * 60 + $ttm;
|
|
$totaltmm = $totaltm % 60;
|
|
$totaltmh = int(($totaltm - $totaltmm) / 60);
|
|
$totaltmm = "0$totaltmm" if $totaltmm < 10;
|
|
$totaltmh = "0$totaltmh" if $totaltmh < 10;
|
|
$t->{"c$ttx"} = $totaltmh.':'.$totaltmm;
|
|
}
|
|
}
|
|
if ($query->param('newstatus') ne undef) {
|
|
$t->{status} = $query->param('newstatus');
|
|
} else {
|
|
if ($t->{status} eq 'OPN' && $isoper && !$query->param('internal')) { $t->{status} = 'WFR'; }
|
|
if ($t->{status} eq 'WFR' && !$isoper) { $t->{status} = 'OPN'; }
|
|
}
|
|
if ($query->param('problem') ne undef || $attachment ne undef) {
|
|
my $unm = $t->{name};
|
|
if ($cfg->get('askforname')) {
|
|
$unm = $query->param('respondername');
|
|
}
|
|
my $msg = "From: ".($isoper ? $cfg->get('_USER')->get('login') : $unm)."\nDate: ".time()."\nOperator: $isoper\n";
|
|
if ($isoper && $query->param('internal')) {
|
|
$msg .= "Internal: Yes\n";
|
|
}
|
|
$msg .= "IP: $ENV{REMOTE_ADDR}\n";
|
|
$msg .= "$attachment\n".substr($query->param('problem'),0,32*1024);
|
|
push @{$t->{messages}}, $msg;
|
|
$query->param(-name => 'problem', -value => '');
|
|
$notify = 1;
|
|
if ($isoper) {
|
|
TTXCommon::logit("RESPOND|".$t->{oper}."|".$t->{id});
|
|
}
|
|
}
|
|
if ($isoper && $query->param('transfer') ne undef && $query->param('transfer') ne $t->{oper}) {
|
|
TTXCommon::logit("TRANSFER|".$t->{oper}."|".$t->{id}."|".$query->param('transfer'));
|
|
if ($query->param('transfer') !~ /^\+/) {
|
|
$t->{oper} = $query->param('transfer');
|
|
$t->{status} = 'OPN' if $cfg->get('transferopens');
|
|
transfernotice({cfg => $cfg, ticket => $t});
|
|
} elsif($cfg->get('usegrpsel')) {
|
|
$t->{grp} = $query->param('transfer');
|
|
TTXGroups::grptransfer({cfg => $cfg, ticket => $t});
|
|
}
|
|
}
|
|
$t->{updated} = time();
|
|
if ($t->{status} eq 'CLS') {
|
|
$t->{closed} = $t->{updated};
|
|
if ($isoper) {
|
|
TTXCommon::logit("CLOSE|".$t->{oper}."|".$t->{id});
|
|
if ($cfg->get('report') ne undef) {
|
|
eval "use TTXEReport";
|
|
if ($@ eq undef) {
|
|
TTXEReport::reportclose($cfg, $t);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$tickets->save();
|
|
if ($t->{status} eq 'PND' && $isoper) {
|
|
$query->param(-name => 'do', -value => '');
|
|
# $query->param(-name => 'tid', -value => $t->{id});
|
|
my $oper = $cfg->get('_USER')->get('login');
|
|
if (!($cfg->get('demo') && $oper ne 'admin') &&
|
|
($cfg->get('grant.delete') eq undef || grep(/^$oper$/, split(/,/, $cfg->get('grant.delete'))))) {
|
|
$data->{DELTICKET} = ' <input type=submit onsubmit name=delete onclick="return confirmdel()" value="[%Delete ticket%]">';
|
|
}
|
|
# usernotify({cfg => $cfg, ticket => $t}) if $notify && !($isoper && $query->param('internal'));
|
|
$cmd = 'claim';
|
|
}
|
|
}
|
|
}
|
|
$tickets = undef;
|
|
if ($isoper && invenabled()) {
|
|
$data->{INVENTORYROW} = TTXInvMod::invrow($cfg, $data, $t);
|
|
}
|
|
if (($t->{status} eq 'WFR' || $t->{status} eq 'CLS') && $isoper) {
|
|
$data->{NEWSTATUS} = "<input type=radio name=newstatus value=OPN";
|
|
if ($query->param('newstatus') eq 'OPN') { $data->{NEWSTATUS} .= ' checked'; }
|
|
$data->{NEWSTATUS} .= '> [%Open%]<br>'."\n";
|
|
}
|
|
if ($t->{status} eq 'OPN') {
|
|
$data->{NEWSTATUS} .= "<input type=radio name=newstatus value=WFR";
|
|
if ($query->param('newstatus') eq 'WFR') { $data->{NEWSTATUS} .= ' checked'; }
|
|
$data->{NEWSTATUS} .= '> [%Responded%]<br>'."\n";
|
|
}
|
|
if ($t->{status} ne 'CLS') {
|
|
$data->{NEWSTATUS} .= "<input type=radio name=newstatus value=CLS";
|
|
if ($query->param('newstatus') eq 'CLS') { $data->{NEWSTATUS} .= ' checked'; }
|
|
$data->{NEWSTATUS} .= '> [%Closed%]<br>'."\n";
|
|
}
|
|
if ($isoper) {
|
|
$data->{NEWSTATUS} .= '<br><input type=checkbox name=internal value=1';
|
|
if ($query->param('internal')) {
|
|
$data->{NEWSTATUS} .= ' checked';
|
|
}
|
|
$data->{NEWSTATUS} .= '> <span class=lbl>[%Internal%]</span><br>';
|
|
}
|
|
my $userid = $cfg->get('_USER')->{login} if $isoper;
|
|
if ($isoper && ($userid eq $t->{oper} || grep(/^$userid$/, split(/,/, $cfg->get('grant.assign'))))) {
|
|
my @operlist = TTXUser::list();
|
|
# if ($cfg->get('usegrpsel') && $cfg->get('accessctrl')) {
|
|
if ($cfg->get('usegrpsel')) {
|
|
my $rev;
|
|
eval '$rev = $TTXGroups::REVISION';
|
|
# if ($@ eq undef && $rev > 213) {
|
|
if ($@ eq undef && $rev > 231) {
|
|
TTXGroups::cleanoperlist($cfg, \@operlist, $t->{grp});
|
|
}
|
|
}
|
|
if (@operlist > 1) {
|
|
$data->{NEWSTATUS} .= '<br><table cellpadding=0 cellspacing=0><tr><td align=right><span class=lbl>[%Transfer to%]</span></td></tr>'."\n".
|
|
"<tr><td align=right><br class=tiny><select name=transfer>\n";
|
|
$data->{NEWSTATUS} .= "<option></option>\n";
|
|
foreach my $oper (sort @operlist) {
|
|
next if $oper eq $t->{oper};
|
|
$data->{NEWSTATUS} .= "<option value=$oper";
|
|
if ($query->param('transfer') eq $oper) {
|
|
$data->{NEWSTATUS} .= " selected";
|
|
}
|
|
$data->{NEWSTATUS} .= ">$oper</option>\n";
|
|
}
|
|
if ($cfg->get('usegrpsel')) {
|
|
TTXGroups::trselector($cfg, $data);
|
|
}
|
|
$data->{NEWSTATUS} .= "</select></td></tr></table>\n";
|
|
}
|
|
}
|
|
$data->{PAGEHEADING} = '[%Ticket%] #'.$t->{id};
|
|
$data->{TICKET_status} = TTXCommon::status($t->{status});
|
|
$data->{TICKET_subject} = $t->{subject};
|
|
$data->{TICKET_email} = $t->{email};
|
|
$data->{TICKET_name} = $t->{name};
|
|
$data->{TICKET_key} = $t->{key};
|
|
$data->{TICKET_open} = TTXCommon::tmtxt($t->{open});
|
|
$data->{TICKET_GROUP} = $cfg->get($t->{grp}) || '-';
|
|
$data->{TICKET_closed} = $t->{status} eq 'CLS' ? TTXCommon::tmtxt($t->{closed}):'-';
|
|
$data->{TICKET_oper} = $isoper ? $t->{oper}:(($t->{oper} eq undef) ? '[%not assigned%]':'[%assigned%]');
|
|
my @xvars = $cfg->vars();
|
|
@xvars = grep(/^x/, @xvars);
|
|
foreach my $xvar (@xvars) {
|
|
$data->{'TICKET_c'.$cfg->get($xvar)} = $t->{'c'.$cfg->get($xvar)};
|
|
if ($query->param('do') eq undef) {
|
|
$query->param(-name => $xvar, -value => $t->{'c'.$cfg->get($xvar)});
|
|
}
|
|
}
|
|
if ($cfg->get('tracktime') ne undef && $isoper) {
|
|
my $ttx = $cfg->get('tracktime');
|
|
if ($ttx !~ /[^0-9]/ && $ttx >= 0 && $ttx < $cfldcnt) {
|
|
my $tth = TTXCommon::cleanit($query, 'tracktimeh');
|
|
my $ttm = TTXCommon::cleanit($query, 'tracktimem');
|
|
$tth =~ s/"/"/g; $ttm =~ s/"/"/g;
|
|
$data->{TRACKTIME} = '<b>[%Time spent on preparing the response (hh:mm)%]</b>'."\n".
|
|
"<input type=text size=2 name=tracktimeh value=\"$tth\">:".
|
|
"<input type=text size=2 name=tracktimem value=\"$ttm\"><br><br class=tiny>";
|
|
}
|
|
}
|
|
if (!$isoper && $cfg->get('askforname')) {
|
|
if ($query->param('emailkey') ne undef && $query->param('emailkey') eq $t->{email}) {
|
|
if ($query->param('respondername') eq undef) {
|
|
$query->param(-name => 'respondername', -value => $t->{name});
|
|
}
|
|
}
|
|
my $nm = $query->param('respondername');
|
|
$nm =~ s/"/"/g;
|
|
$data->{TRACKTIME} .= '<b>[%Your name%]:</b> '.
|
|
"\n<input type=text size=25 name=respondername value=\"$nm\"><br><br class=tiny>";
|
|
}
|
|
my %images;
|
|
my %names;
|
|
my $editlink;
|
|
if ($isoper) {
|
|
my $uid = $cfg->get('_USER')->get('login');
|
|
if ($cfg->get('grand.edit') eq undef || grep(/^$uid$/, split(/,/, $cfg->get('grand.edit')))) {
|
|
eval 'use TTXMsgEdit';
|
|
if ($@ eq undef) {
|
|
$editlink = 1;
|
|
}
|
|
}
|
|
}
|
|
my $mid = 0;
|
|
foreach my $msg (@{$t->{messages}}) {
|
|
my @msgparts = split(/\n\n/, $msg);
|
|
my $rawheader = shift @msgparts;
|
|
my $body = join("\n\n", @msgparts);
|
|
my @headerlines = split(/\n/, $rawheader);
|
|
chomp @headerlines;
|
|
my %header;
|
|
foreach my $line (@headerlines) {
|
|
if ($line =~ /^([a-zA-Z][a-zA-Z0-9-]*):\s*(.*)$/) {
|
|
$header{uc $1} = $2;
|
|
}
|
|
}
|
|
next if $header{OPERATOR} && $header{INTERNAL} =~ /Yes/ && !$isoper;
|
|
my $style;
|
|
if ($header{OPERATOR}) {
|
|
if ($header{INTERNAL} =~ /Yes/) {
|
|
$style = 'imsg';
|
|
} else {
|
|
$style = 'omsg'
|
|
}
|
|
} else {
|
|
$style = 'cmsg';
|
|
}
|
|
my $imgtag;
|
|
my $fromtag;
|
|
if ($header{OPERATOR}) {
|
|
if (!exists $images{$header{FROM}}) {
|
|
my $u = TTXUser->new($header{FROM});
|
|
if ($u eq undef) {
|
|
$images{$header{FROM}} = undef;
|
|
$names{$header{FROM}} = undef;
|
|
} else {
|
|
$images{$header{FROM}} = $u->{image};
|
|
$names{$header{FROM}} = $u->{fname}.' '.$u->{lname};
|
|
}
|
|
}
|
|
if ($images{$header{FROM}} ne undef) {
|
|
$imgtag = "<br><br class=sm><center><nobr> <img src=\"$images{$header{FROM}}\"> </nobr></center><br class=sm>\n";
|
|
}
|
|
$fromtag = $names{$header{FROM}};
|
|
if ($isoper) { $fromtag .= " ($header{FROM})"; }
|
|
}
|
|
$fromtag = $header{FROM} if $fromtag eq undef;
|
|
$fromtag =~ s/</</g;
|
|
if ($isoper) {
|
|
if ($header{IP} ne undef) {
|
|
$fromtag .= "<br>[$header{IP}]";
|
|
}
|
|
}
|
|
if ($editlink ne undef) {
|
|
$editlink = "<br>".TTXMsgEdit::link($cfg, $t, $mid);
|
|
++$mid;
|
|
}
|
|
$data->{MESSAGES} .= "<tr>\n<td width=20% align=left valign=top class=$style>$fromtag<br>".TTXCommon::tmtxt($header{DATE})."$editlink$imgtag</td>\n";
|
|
$body =~ s/</</g;
|
|
$body = TTXMarkup::html($body);
|
|
$body =~ s/\n/<br>\n/g;
|
|
my $firstfile = 1;
|
|
for (my $i=1; $i < 4; ++$i) {
|
|
if ($header{"FILE$i"} ne undef) {
|
|
if ($firstfile) {
|
|
$body .= '<br class=sm><br class=sm>[%Attachments%]:<br>'."\n";
|
|
$firstfile = 0;
|
|
}
|
|
$header{"FILE$i"} =~ s/CGIURL/$ENV{SCRIPT_NAME}/;
|
|
$body .= $header{"FILE$i"} . "<br>\n";
|
|
}
|
|
}
|
|
$data->{MESSAGES} .= "<td align=left valign=top class=$style>$body</td>\n</tr>\n";
|
|
}
|
|
if (TTXData::get('ISPRO')) {
|
|
$data->{FILEFORMS} = TTXFile::fileforms();
|
|
}
|
|
if ($notify) {
|
|
if (!($isoper && $query->param('internal'))) {
|
|
usernotify({cfg => $cfg, ticket => $t,
|
|
from => $isoper ?
|
|
$cfg->get('_USER')->{fname}.' '.$cfg->get('_USER')->{lname} :
|
|
$query->param('respondername')});
|
|
if ($cfg->get('askforsurvey') && $t->{status} eq 'CLS') {
|
|
eval "use TTXSurvey";
|
|
TTXSurvey::ask($cfg, $t);
|
|
}
|
|
}
|
|
if (!$isoper) {
|
|
if ($t->{status} eq 'PND') {
|
|
if ($cfg->get('validate') eq undef || $t->{'c'.$cfg->get('validate')} eq 'Y') {
|
|
my $opernotifydata = {cfg => $cfg, ticket => $t};
|
|
if ($cfg->get('supervisor') ne undef) {
|
|
my @list = ($cfg->get('supervisor'));
|
|
$opernotifydata->{notifylist} = \@list;
|
|
} elsif ($cfg->get('usegrpsel')) {
|
|
my @list = split(/;/, $cfg->get("mbr-".$t->{grp}));
|
|
$opernotifydata->{notifylist} = \@list;
|
|
} elsif ($cfg->get('routex') ne undef) {
|
|
eval "use TTXCustomRoute";
|
|
if ($@ eq undef) {
|
|
my @list = TTXCustomRoute::routelist($cfg, $t);
|
|
$opernotifydata->{notifylist} = \@list;
|
|
}
|
|
}
|
|
opernotify($opernotifydata);
|
|
}
|
|
} else {
|
|
opernotify({cfg => $cfg, ticket => $t});
|
|
}
|
|
} elsif ($t->{oper} ne undef && $cfg->get('_USER')->{login} ne $t->{oper}) {
|
|
opernotify({cfg => $cfg, ticket => $t});
|
|
}
|
|
}
|
|
return $cmd;
|
|
}
|
|
|
|
|
|
1;
|
|
#
|