# -- # Kernel/System/TicketWizard.pm - core module - SeTIC - UFSC - http://setic.ufsc.br/ # Rodrigo Gonçalves - rodrigo.g@ufsc.br # # Version 01/12/2015 - Support for OTRS 4.0.3 # Version 2017-06-20 - Code refactoring # Version 2018-01-18 - Support for OTRS 6 # # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (AGPL). If you # did not receive this file, see http://www.gnu.org/licenses/agpl.txt. # -- package Kernel::System::TicketWizard; use strict; use warnings; use utf8; use Data::Dumper; use URI::Escape; use Encode qw( encode_utf8 decode_utf8 ); use JSON qw(encode_json decode_json); our @ObjectDependencies = ( "Kernel::System::Web::Request", "Kernel::System::DB", "KerneL::System::Log", "KerneL::System::Ticket", "KerneL::System::Type", "Kernel::System::YAM", "Kernel::Config", "Kernel::System::DynamicField", "Kernel::System::Service", "Kernel::System::ServiceForm", "Kernel::System::SystemAddress" ); sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {%Param}; bless( $Self, $Type ); return $Self; } =head Returns fields structure for new ticket form wizard public =cut sub GetBasicFieldsOptionsPublic { my ( $Self, %Param ) = @_; return $Kernel::OM->Get("Kernel::Config")->Get("Ticket::Frontend::Customer::NewTicketWizard")->{BasicFormPublic}; } =head Returns fields schema for new ticket wizard public =cut sub GetBasicFieldsSchemaPublic { my ( $Self, %Param ) = @_; return $Kernel::OM->Get("Kernel::Config")->Get("Ticket::Frontend::Customer::NewTicketWizard")->{BasicSchemaPublic}; } =head Returns fields structure for new ticket form wizard =cut sub GetBasicFieldsOptions { my ( $Self, %Param ) = @_; return $Kernel::OM->Get("Kernel::Config")->Get("Ticket::Frontend::Customer::NewTicketWizard")->{BasicForm}; } =head Returns fields schema for new ticket wizard =cut sub GetBasicFieldsSchema { my ( $Self, %Param ) = @_; return $Kernel::OM->Get("Kernel::Config")->Get("Ticket::Frontend::Customer::NewTicketWizard")->{BasicSchema}; } =head Replaces OTRS system field values (service and type) =cut sub ReplaceOTRSValues { my ( $Self, %Param ) = @_; my $schema = $Param{Schema}; my $options = $Param{Options}; my ( $serviceNames, $serviceIDs ) = $Self->GetOTRSServicesData(); $schema =~ s/OTRS_service_values/$serviceIDs/g; $options =~ s/OTRS_service_labels/$serviceNames/g; my ( $typeNames, $typeIDs ) = $Self->GetOTRSTypesData(UserID => $Param{UserID}); $schema =~ s/OTRS_type_values/$typeIDs/g; $options =~ s/OTRS_type_labels/$typeNames/g; return ( $schema, $options ); } =head Get OTRS services info (service and type) =cut sub GetOTRSServicesData { my ( $Self, %Param ) = @_; my $services = $Kernel::OM->Get("Kernel::System::Service"); my %serviceList = $services->ServiceList( Valid => 1, UserID => $Kernel::OM->Get("Kernel::Config")->Get('CustomerPanelUserID') ); my $serviceNames = ""; my $serviceIDs = ""; foreach ( sort { ( $serviceList{$a} cmp $serviceList{$b} ) } keys %serviceList ) { $serviceNames .= "\"$serviceList{$_}\","; $serviceIDs .= "$_,"; } $serviceNames = substr($serviceNames, 0, -1); $serviceIDs = substr($serviceIDs, 0, -1); return ( $serviceNames, $serviceIDs ); } =head Get OTRS ticket types =cut sub GetOTRSTypesData { my ( $Self, %Param ) = @_; my $ticketObject = $Kernel::OM->Get("Kernel::System::Ticket"); my %typeList = $ticketObject->TicketTypeList( UserID => $Param{UserID} ); my $typeNames = ""; my $typeIDs = ""; foreach ( sort { ( $typeList{$a} cmp $typeList{$b} ) } keys %typeList ) { if (index($typeList{$_}, '::') == -1) { $typeNames .= "\"$typeList{$_}\","; $typeIDs .= "$_,"; } } $typeNames = substr($typeNames, 0, -1); $typeIDs = substr($typeIDs, 0, -1); return ( $typeNames, $typeIDs ); } =head Replaces OTRS dynamic fields =cut sub ReplaceOTRSDynamicFields { my ( $Self, %Param ) = @_; my $schema = $Param{Schema}; my $options = $Param{Options}; my $dfields = $Kernel::OM->Get("Kernel::System::DynamicField"); my @dfieldList = @{ $dfields->DynamicFieldListGet( Valid => 1 ) }; foreach (@dfieldList) { my $campo = $_; my $name = $campo->{Name}; my $config = $campo->{Config}; my $type = $campo->{FieldType}; my $idFieldValues = "DF_" . $name . "_values"; my $idFieldLabels = "DF_" . $name . "_labels"; if ( $type eq "Dropdown" ) { my ( $dfValues, $dfLabels ) = $Self->GetDynamicFieldValues( ConfigDF => $config ); $schema =~ s/$idFieldValues/$dfValues/g; $options =~ s/$idFieldLabels/$dfLabels/g; } } return ( $schema, $options ); } =head Get OTRS dyanmic field values =cut sub GetDynamicFieldValues { my ( $Self, %Param ) = @_; my $config = $Param{ConfigDF}; my $values = $config->{PossibleValues}; my $dfValues = ""; my $dfLabels = ""; foreach ( sort { ( $values->{$a} cmp $values->{$b} ) } keys %{$values} ) { $dfValues .= "\"$_\","; $dfLabels .= "\"$values->{$_}\","; } $dfValues = substr($dfValues, 0, -1); $dfLabels = substr($dfLabels, 0, -1); return ( $dfValues, $dfLabels ); } =head Builds service choosing combo =cut sub BuildServices { my ( $Self, %Param ) = @_; my %Data = (); my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $QueueServiceObject = $Kernel::OM->Get("Kernel::System::QueueService"); my $ConfigObject = $Kernel::OM->Get("Kernel::Config"); my $ServiceObject = $Kernel::OM->Get("Kernel::System::Service"); my $RestrictedObject = $Kernel::OM->Get("Kernel::System::RestrictedService"); my $Public = $Param{Public}; # Build service chooser my %Services = (); if ( !$ParamObject->GetParam( Param => "QueueID" ) ) { %Services = $ServiceObject->ServiceList( UserID => $ConfigObject->Get('CustomerPanelUserID'), ); } else { %Services = $QueueServiceObject->GetServiceList( QueueID => $ParamObject->GetParam( Param => "QueueID" ), ); } my @ServicesCombo = (); my @restrictedServices = $RestrictedObject->GetRestrictedServices(); for my $serviceID ( keys %Services ) { if ( grep { index( $Services{$_}, $Services{$serviceID} . "::" ) >= 0 } ( keys %Services ) ) { if ((! $Public) || (! ( $serviceID ~~ @restrictedServices ))) { my %serv = (); $serv{Value} = $Services{$serviceID}; $serv{Key} = $serviceID; $serv{Disabled} = 1; push @ServicesCombo, \%serv; } } else { if ((! $Public) || (! ( $serviceID ~~ @restrictedServices ))) { my %serv = (); $serv{Value} = $Services{$serviceID}; $serv{Key} = $serviceID; push @ServicesCombo, \%serv; } } } @ServicesCombo = sort { $a->{Value} . "::" cmp $b->{Value} . "::" } @ServicesCombo; my $retorno = ""; my $servicePreDefined = $ParamObject->GetParam( Param => "ServiceID" ); $retorno = "\n"; return $retorno; } =head Returns service name without the parent services names =cut sub LastPart { my $Self = shift; my $queue = shift; my @parts = split( "::", $queue ); return $parts[-1]; } =head Handles jQueryFileUpload component in AlpacaJS =cut sub UploadFile { my ( $Self, %Param ) = @_; my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); if ($ParamObject->GetParam(Param => "UploadFileCmd") eq "UploadFile") { $Self->Debug("Upload file command received"); return $Self->UploadFileReceive(); } elsif ($ParamObject->GetParam(Param => "UploadFileCmd") eq "DeleteFile") { $Self->Debug("Delete uploaded file command received"); return $Self->UploadFileDelete(); } else { $Self->Debug("Unknown file command received"); return 1; } } =head Handles jQueryFileUpload component in AlpacaJS =cut sub UploadFileDelete() { my ( $Self, %Param ) = @_; my %Data = (); my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $WebUploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache'); my $LayoutObject = $Kernel::OM->Get("Kernel::Output::HTML::Layout"); my $fileName = $ParamObject->GetParam(Param => "Filename"); my $formId = $ParamObject->GetParam(Param => "FormID"); $Self->Debug("FileUpload: Delete file $fileName from form $formId"); my @filesUploaded = $WebUploadCacheObject->FormIDGetAllFilesData(FormID => $formId); my $fileDeleted = 0; for my $uploadedFile (@filesUploaded) { if ($uploadedFile->{Filename} eq $fileName) { $WebUploadCacheObject->FormIDRemoveFile(FormID => $formId, FileID => $uploadedFile->{FileID}); $Self->Debug("FileUpload: Deleted file " . $fileName); $fileDeleted = 1; } } if ($fileDeleted) { return $LayoutObject->Attachment( ContentType => 'application/json; charset=' . $LayoutObject->{Charset}, Content => "{ $fileName: true}", Type => 'inline', NoCache => 1, ); } else { return 1; } } =head Deletes all attachments from the form =cut sub ClearCache() { my ( $Self, %Param ) = @_; my %Data = (); my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $WebUploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache'); my $LayoutObject = $Kernel::OM->Get("Kernel::Output::HTML::Layout"); my $formId = $Param{FormID}; $Self->Debug("Clearing cache for form " . $formId); my @filesUploaded = $WebUploadCacheObject->FormIDGetAllFilesData(FormID => $formId); my $fileDeleted = 0; for my $uploadedFile (@filesUploaded) { $WebUploadCacheObject->FormIDRemoveFile(FormID => $formId, FileID => 1); $Self->Debug("FileUpload: Deleted file " . $uploadedFile->{Filename}); } } =head Handles jQueryFileUPload component in AlpacaJS =cut sub UploadFileReceive() { my ( $Self, %Param ) = @_; my %Data = (); my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $WebUploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache'); my $LayoutObject = $Kernel::OM->Get("Kernel::Output::HTML::Layout"); my $LanguageObject = $Kernel::OM->Get("Kernel::Language"); my %tmpFile = $ParamObject->GetUploadAll(Param => "attachment_files"); my $formId = $ParamObject->GetParam( Param => "FormID" ); if (! $tmpFile{Filename} || ! $formId) { my $msgError = $LanguageObject->Translate("Invalid file!"); return $LayoutObject->Attachment( ContentType => 'application/json; charset=' . $LayoutObject->{Charset}, Content => "{ \"error\": \"$msgError\", \"files\": [] }", Type => 'inline', NoCache => 1, ); } my $clearName = $tmpFile{Filename}; $clearName =~ tr/0-9a-zA-Z\.\-/\_/c; $tmpFile{Filename} = $clearName; $Self->Debug("FileUpload: Adding file to cache. FormID: " . $formId . " \t Filename: " . $tmpFile{Filename} . " \t ContentType: " . $tmpFile{ContentType} ); $WebUploadCacheObject->FormIDAddFile( FormID => $formId, Filename => $tmpFile{Filename}, Content => $tmpFile{Content}, ContentType => $tmpFile{ContentType} ); my %retorno = (); my @filesReturned = (); my %dados = (); $dados{name} = $tmpFile{Filename}; $dados{size} = length($tmpFile{Content}); $dados{deleteUrl} = "/otrs/public.pl?Action=NewTicketWizardPublic;UploadFileCmd=DeleteFile;Filename=" . uri_escape($tmpFile{Filename}) . ";FormID=" . $formId; push @filesReturned, \%dados; $retorno{"files"} = \@filesReturned; return $LayoutObject->Attachment( ContentType => 'application/json; charset=' . $LayoutObject->{Charset}, Content => encode_json(\%retorno), Type => 'inline', NoCache => 1, ); } =head Returns the custom script defined for a service, if it exists or just a comment-blank line if it doesn't =cut sub GetFormCustomProps { my ( $Self, %Param ) = @_; my %serviceForm; my $ServiceFormObject = $Kernel::OM->Get("Kernel::System::ServiceForm"); my $LayoutObject = $Kernel::OM->Get("Kernel::Output::HTML::Layout"); my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $QueueID = $ParamObject->GetParam( Param => "QueueID" ); if ( $Param{ServiceID} ) { %serviceForm = $ServiceFormObject->GetServiceFormForQueue( ServiceID => $Param{ServiceID}, QueueID => $QueueID ); if (! $serviceForm{ServiceID}) { %serviceForm = $ServiceFormObject->GetServiceForm( ServiceID => $Param{ServiceID} ); } } return $LayoutObject->Attachment( ContentType => 'text/plain; charset=' . $LayoutObject->{Charset}, Content => $serviceForm{CustomProps} || "/**/", Type => 'inline', NoCache => 1, ); } =head Returns the JSON form structure for a given service, if one is defined =cut sub GetFormJSON { my ( $Self, %Param ) = @_; my %serviceForm; my $ServiceFormObject = $Kernel::OM->Get("Kernel::System::ServiceForm"); my $LayoutObject = $Kernel::OM->Get("Kernel::Output::HTML::Layout"); my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $QueueID = $ParamObject->GetParam(Param => "QueueID"); my $FormID = $ParamObject->GetParam(Param => "FormID"); if ( $Param{ServiceID} ) { %serviceForm = $ServiceFormObject->GetServiceFormForQueue( ServiceID => $Param{ServiceID}, QueueID => $QueueID ); if (! $serviceForm{ServiceID}) { %serviceForm = $ServiceFormObject->GetServiceForm( ServiceID => $Param{ServiceID} ); } } $Self->ClearCache(FormID => $FormID); my ( $schema, $fields, $introduction ) = $Self->GetForm( Public => $Param{Public}, ServiceForm => \%serviceForm, QueueID => $QueueID ); return $LayoutObject->Attachment( ContentType => 'application/json; charset=' . $LayoutObject->{Charset}, Content => "[{" . $schema . "}, {" . $fields . "}, \"" . $introduction . "\"]", Type => 'inline', NoCache => 1, ); } =head Allows using a field in the form to select a target queue. If a queue was defined in request parameter, uses it. If there is a prefix defined for the queues to automatically forward tickets, and also a field was defined as handling the target queue, try to locate one. If none is found, uses the default queue. For example: QueueDefault = Primeiro Nivel QueuePrefix = Primeiro Nivel QueueField = Unidade AvailableQueues = Primeiro Nivel CCB, Primeiro Nivel CCE, Primeiro Nivel QueueDefault = Primeiro Nivel if QueueField value is CCB, then selects queue Primeiro Nivel CCB if QueueField value is CCJ (no queue by that suffix), then selects queue Primeiro Nivel if QueueField value is CCE, then selects queue Primeiro Nivel CCE =cut sub GetQueueID() { my ( $Self, %Param ) = @_; my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $QueueObject = $Kernel::OM->Get("Kernel::System::Queue"); my $ConfigObject = $Kernel::OM->Get("Kernel::Config"); # Check if queueID was sent my $QueueID = $ParamObject->GetParam(Param => "QueueID"); if ($QueueID) { $Self->Debug("Sent queue: $QueueID"); my %Queue = $QueueObject->QueueGet(ID => $QueueID); return ($Queue{"Name"}, $QueueID); } # Gets default Queue my $ConfigTicket = $ConfigObject->Get("Ticket::Frontend::CustomerTicketMessage"); my $ConfigTicketWizard = $ConfigObject->Get("Ticket::Frontend::Customer::NewTicketWizard"); my $QueueDefault = $ConfigTicket->{"QueueDefault"}; # Checks if there is a field for the queue my $QueuePrefix = $ConfigTicketWizard->{"QueuePrefix"}; my $QueueField = $ConfigTicketWizard->{"QueueField"}; my %QueueListID = $QueueObject->QueueList( Valid => 1 ); my %QueueList = reverse $QueueObject->QueueList( Valid => 1 ); $QueueID = $QueueList{$QueueDefault}; my $Queue = $QueueListID{$QueueID}; if ( $QueuePrefix && $QueueField ) { my $QueueSelected = $ParamObject->GetParam( Param => $QueueField ); my $QueueName = "$QueuePrefix $QueueSelected"; if ( $QueueList{$QueueName} ) { $QueueID = $QueueList{$QueueName}; $Queue = $QueueName; } } return ( $Queue, $QueueID ); } =head Returns the form code for a given service, if one is defined =cut sub GetForm { my ( $Self, %Param ) = @_; my $TicketWizard = $Kernel::OM->Get("Kernel::System::TicketWizard"); my $ConfigObject = $Kernel::OM->Get("Kernel::Config"); my $schema; my $fields; $Self->{ConfigNTW} = $ConfigObject->Get("Ticket::Frontend::Customer::NewTicketWizard"); $Self->{DefaultUserID} = $Self->{ConfigNTW}->{"DefaultUserID"}; $Self->{DefaultCustomerID} = $Self->{ConfigNTW}->{"DefaultCustomerID"}; $Self->{DefaultUserDomain} = $Self->{ConfigNTW}->{"DefaultUserDomain"}; if ($Param{Public}) { $Self->Debug("Getting public form schema"); $schema = $TicketWizard->GetBasicFieldsSchemaPublic(); $fields = $TicketWizard->GetBasicFieldsOptionsPublic(); } else { $Self->Debug("Getting authenticated form schema"); $schema = $TicketWizard->GetBasicFieldsSchema(); $fields = $TicketWizard->GetBasicFieldsOptions(); } my $introduction; ( $schema, $fields ) = $TicketWizard->ReplaceOTRSValues( Schema => $schema, Options => $fields, UserID => $Self->{DefaultUserID} ); if ( !$Param{ServiceForm} ) { $schema =~ s/CF_SCHEMA//g; $fields =~ s/CF_FORM//g; $introduction = ""; # Include dynamic fields in replace command ( $schema, $fields ) = $TicketWizard->ReplaceOTRSDynamicFields( Schema => $schema, Options => $fields ); } else { my %serviceForm = %{ $Param{ServiceForm} }; $introduction = $serviceForm{Introduction}; if ( !$Param{ServiceForm}{Schema} ) { $schema =~ s/CF_SCHEMA//g; $fields =~ s/CF_FORM//g; } else { my $schemaForm = "," . $serviceForm{Schema}; my $fieldsForm = "," . $serviceForm{Form}; $schema =~ s/CF_SCHEMA/$schemaForm/g; $fields =~ s/CF_FORM/$fieldsForm/g; } # Include dynamic fields in replace command ( $schema, $fields ) = $TicketWizard->ReplaceOTRSDynamicFields( Schema => $schema, Options => $fields ); # Set fixed field values, if defined if ($serviceForm{FixedValues}) { ($schema, $fields) = $Self->AdjustFixedFields(Schema => $schema, Fields => $fields, FixedValues => $serviceForm{FixedValues}); } } if ($Param{"QueueID"}) { $schema = $schema . ",\n\"QueueID\": {\n\"type\": \"string\",\n\"default\": \"" . $Param{"QueueID"} . "\"}"; $fields = $fields . ",\n\"QueueID\": {\n\"type\": \"hidden\"\n}"; } return ( $schema, $fields, $introduction ); } =head If some fields have fixed values in service definition, sets them =cut sub AdjustFixedFields { my ( $Self, %Param ) = @_; my $schema = $Param{Schema}; my $form = $Param{Fields}; my $fixedValues = $Param{FixedValues}; my @values = split(/\n/, $fixedValues); for my $value (@values) { $value =~ s/\r//g; my @data = split('=', $value); my $fieldKey = $data[0]; my $fixedValue = $data[1]; $Self->Debug("Adjusting fixed field { $fieldKey } with value [ $fixedValue ]"); my $key = '("' . $fieldKey . '"[\ ]?:[\ ]?{[^}]+})'; my $replace = '"' . $fieldKey . '"' . ': {"type": "string", "default": "' . $fixedValue . '"}'; $Self->Debug("Adjusting fixed fields in schema: \n " . $schema); $schema =~ s/$key/$replace/; $Self->Debug("Adjusting fixed fields in form: \n " . $form); $form = "{" . $form . "}"; $form = encode_utf8($form); my $formStruct = decode_json($form); my $hiddenStruct = {}; $hiddenStruct->{"type"} = "hidden"; $formStruct->{$fieldKey} = $hiddenStruct; print STDERR Dumper($formStruct); $form = encode_json($formStruct); $form = decode_utf8($form); substr($form, 0, 1, ""); substr($form, -1, 1, ""); } return ($schema, $form); } =head Creates a new ticket, given the input data and sent attachments/images =cut sub CreateTicket { my ( $Self, %Param ) = @_; my %Data = (); my $TicketObject = $Kernel::OM->Get("Kernel::System::Ticket"); my $ConfigObject = $Kernel::OM->Get("Kernel::Config"); my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $BackendObject = $Kernel::OM->Get("Kernel::System::DynamicField::Backend"); my $DynamicFieldObject = $Kernel::OM->Get("Kernel::System::DynamicField"); my $CustomerUserObject = $Kernel::OM->Get("Kernel::System::CustomerUser"); my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my $TicketWizard = $Kernel::OM->Get("Kernel::System::TicketWizard"); my $LanguageObject = $Kernel::OM->Get("Kernel::Language"); $Self->{ConfigNTW} = $ConfigObject->Get("Ticket::Frontend::Customer::NewTicketWizard"); $Self->{DefaultUserID} = $Self->{ConfigNTW}->{"DefaultUserID"}; $Self->{DefaultCustomerID} = $Self->{ConfigNTW}->{"DefaultCustomerID"}; $Self->{DefaultUserDomain} = $Self->{ConfigNTW}->{"DefaultUserDomain"}; # Check if queue was pre-defined my $queueFixed = 0; if ($Data{QueueID}) { $queueFixed = 1; } # Get queue name and id using rules, if no queue was predefined my ( $Queue, $QueueID ) = $TicketWizard->GetQueueID(%Param); $Data{QueueID} = $QueueID; $LayoutObject->AddJSData( Key => 'NewTicketWizard.QueueID', Value => $Data{QueueID}, ); # Module config $Self->{Config} = $ConfigObject->Get("Ticket::Frontend::CustomerTicketMessage"); # Ticket creation my $customerID; my $customerUser; if ($Param{Public}) { $customerID = $Self->GetUserIDFromEmail( $ParamObject->GetParam( Param => "email" ) ); $customerUser = $Self->GetUserIDFromEmail( $ParamObject->GetParam( Param => "email" ) ); } else { $customerID = $Param{CustomerID}; $customerUser = $Param{CustomerUser}; } $Self->Debug("Creating ticket"); my $TicketID = $TicketObject->TicketCreate( Title => $ParamObject->GetParam( Param => "subject" ), QueueID => $QueueID, Priority => $Self->{Config}->{PriorityDefault}, Lock => 'unlock', State => 'new', ServiceID => $ParamObject->GetParam( Param => "service" ), TypeID =>$ParamObject->GetParam( Param => "type" ), CustomerID => $customerID, CustomerUser => $customerUser, OwnerID => $Self->{DefaultUserID}, UserID => $Self->{DefaultUserID}, ); $Self->Debug("Created ticket ID $TicketID"); my $MimeType = 'text/html'; my %serviceFieldsValues = (); my $serviceFields = ""; my @serviceFieldsKeys = (); # Service Fields $Self->Debug("Retrieving service form values"); for ( $ParamObject->GetParamNames() ) { if (( substr( $_, 0, 3 ) eq "SF_" ) && ( substr( $_, 0, 5 ) ne "SF_T_" )) { if ($ParamObject->GetArray( Param => $_ )) { my @paramVals = $ParamObject->GetArray( Param => $_ ); for my $paramValue (@paramVals) { if (($paramValue) && (!($paramValue eq "-"))) { if (! $serviceFieldsValues{$_}) { $serviceFieldsValues{$_} = $paramValue; push @serviceFieldsKeys, $_; } else { $serviceFieldsValues{$_} .= ", " . $paramValue; } } } } else { my $paramValue = $ParamObject->GetParam( Param => $_ ); if (($paramValue) && (!($paramValue eq "-"))) { if (! $serviceFieldsValues{$_}) { $serviceFieldsValues{$_} = $paramValue; push @serviceFieldsKeys, $_; } else { $serviceFieldsValues{$_} .= ", " . $paramValue; } } } } } for (@serviceFieldsKeys) { $serviceFields .= "" . $Self->breakWords(Text => substr( $_, 3 )) . ": " . $serviceFieldsValues{$_} . "
"; } if (! $Param{Public}) { $serviceFields .= "" . $LanguageObject->Translate("Authenticated user") . ": " . $customerUser . "
"; } $serviceFields .= "IP: " . $ENV{'REMOTE_ADDR'} . "
"; $serviceFields .= "

"; # Dynamic Fields my $userIDDF; if ($Param{Public}) { $userIDDF = $Self->{DefaultUserID}; } else { $userIDDF = $ConfigObject->Get('CustomerPanelUserID'); } $Self->Debug("Retrieving dynamic fields values"); for ( $ParamObject->GetParamNames() ) { if ( substr( $_, 0, 3 ) eq "DF_" ) { my $Success = $BackendObject->ValueSet( DynamicFieldConfig => $DynamicFieldObject->DynamicFieldGet( Name => substr( $_, 3 ) ), ObjectID => $TicketID, Value => $ParamObject->GetParam( Param => $_ ), UserID => $userIDDF, ); } } # Service Fields - Table fields $Self->Debug("Retrieving service fields - table fields"); my $lastTab = ""; my %keysFound = (); my $newTab = 1; for ( $ParamObject->GetParamNames() ) { if ( substr( $_, 0, 5 ) eq "SF_T_" ) { my $paramName = $_; my @parts = split('_', $_); my $currTab = $parts[2]; my $currKey = $parts[4]; if ($currTab ne $lastTab) { if ($lastTab ne "") { $serviceFields .= "

"; } $serviceFields .= ""; $lastTab = $currTab; $newTab = 1; } else { $newTab = 0; } ## new line due to repetition or new table if ($keysFound{$currKey} || ($newTab) ) { %keysFound = (); $serviceFields .= ""; } $keysFound{$currKey} = 1; $serviceFields .= ""; } } if ($lastTab ne "") { $serviceFields .= "
" . $Self->breakWords(Text => $currTab) . "
" . $Self->breakWords(Text => $currKey) . "" . $ParamObject->GetParam( Param => $paramName ) . "


"; } my $body = $ParamObject->GetParam( Param => "description" ); # Images $Self->Debug("Loading images from cache"); my $WebUploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache'); my $formId = $ParamObject->GetParam(Param => "FormID"); my @filesUploaded = $WebUploadCacheObject->FormIDGetAllFilesData(FormID => $formId); for my $uploadedFile (@filesUploaded) { my $ContentID = $uploadedFile->{ContentID}; if ($ContentID && ( $uploadedFile->{ContentType} =~ /image/i ) && ( $uploadedFile->{Disposition} eq 'inline' )) { $Self->Debug("NewTicketWizard: replacing image URL in body with attachment"); $Self->Debug("NewTicketWizard: Body: $body"); my $ContentIDHTMLQuote = $LayoutObject->Ascii2Html(Text => $ContentID,); # workaround for link encode of rich text editor, see bug#5053 my $ContentIDLinkEncode = $LayoutObject->LinkEncode($ContentID); $body =~ s/(ContentID=)$ContentIDLinkEncode/$1$ContentID/g; $Self->Debug("NewTicketWizard: new body: $body"); } } # Create article $Self->Debug("Creating article"); my $FullName; my $Email; if ($Param{Public}) { $FullName = $ParamObject->GetParam( Param => "name" ); $Email = $ParamObject->GetParam( Param => "email" ); } else { $FullName = $CustomerUserObject->CustomerName( UserLogin => $Param{UserLogin}); $Email = $Param{UserEmail}; } my $From = "\"$FullName\" <$Email>"; my $ArticleBackendObject = $Kernel::OM->Get('Kernel::System::Ticket::Article')->BackendForChannel(ChannelName => 'Email'); my $ArticleID = $ArticleBackendObject->ArticleCreate( TicketID => $TicketID, IsVisibleForCustomer => 1, ArticleType => $Self->{Config}->{ArticleType}, SenderType => $Self->{Config}->{SenderType}, From => $From, To => $Queue, Subject => $ParamObject->GetParam( Param => "subject" ), Body => $LayoutObject->RichTextDocumentComplete(String => $serviceFields . $body), MimeType => $MimeType, Charset => $LayoutObject->{UserCharset}, UserID => $userIDDF, HistoryType => $Self->{Config}->{HistoryType}, HistoryComment => $Self->{Config}->{HistoryComment} || '%%', AutoResponseType => ( $ConfigObject->Get('AutoResponseForWebTickets') ) ? 'auto reply' : '', OrigHeader => { From => $From, To => $Queue, Subject => $ParamObject->GetParam( Param => "subject" ), Body => $LayoutObject->RichTextDocumentComplete(String => $serviceFields . $body),, }, Queue => $Queue, ); # Attachments $Self->Debug("Including attachments"); for my $uploadedFile (@filesUploaded) { $ArticleBackendObject->ArticleWriteAttachment( Filename => $uploadedFile->{Filename}, Content => $uploadedFile->{Content}, ContentType => $uploadedFile->{ContentType}, ArticleID => $ArticleID, ContentID => $uploadedFile->{ContentID}, UserID => $userIDDF, ); } $Data{TicketNumber} = $TicketObject->TicketNumberLookup( TicketID => $TicketID ); $Self->{ConfigNTW} = $ConfigObject->Get("Ticket::Frontend::Customer::NewTicketWizard"); my $idCustomTemplate = "NTW" . $Self->{ConfigNTW}->{"CustomTemplate"}; # build output if ($Param{Public}) { $Data{PublicMode} = "Public"; $Data{Module} = "public"; } else { $Data{Module} = "customer"; } if (! $queueFixed) { delete $Data{QueueID}; } my $Output = $LayoutObject->CustomerHeader(Type => $idCustomTemplate, Title => "Ticket created" ); $Output .= $LayoutObject->Output( Data => \%Data, TemplateFile => 'NewTicketWizardTicketCreated', ); $Output .= $LayoutObject->CustomerFooter(Type => $idCustomTemplate); return $Output; } =head If public interface was used, try to guess the user from the informed e-mail =cut sub GetUserIDFromEmail { my $Self = shift; my $email = shift; my $result = $Self->{DefaultCustomerID}; my $domainList = $Self->{DefaultUserDomain}; my $CustomerUserObject = $Kernel::OM->Get("Kernel::System::CustomerUser"); if ($domainList) { my @domains = split( ",", $domainList ); for my $domain (@domains) { my @parts = split( "@", $email ); if ( $parts[1] eq $domain ) { my $id = $parts[0]; my %List = $CustomerUserObject->CustomerSearch( UserLogin => $id, Valid => 1, # not required, default 1 ); if ( keys %List ) { $result = $id; return $result; } } } } return $result; } =head Default action to open a new form (frontend method share by public and customer frontend modules) =cut sub OpenForm { my ( $Self, %Param ) = @_; my %Data = (); if ($Param{Public}) { $Self->Debug("Opening public form"); } else { $Self->Debug("Opening authenticated form"); } my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my $TicketObject = $Kernel::OM->Get("Kernel::System::Ticket"); my $ConfigObject = $Kernel::OM->Get("Kernel::Config"); my $ParamObject = $Kernel::OM->Get("Kernel::System::Web::Request"); my $BackendObject = $Kernel::OM->Get("Kernel::System::DynamicField::Backend"); my $DynamicFieldObject = $Kernel::OM->Get("Kernel::System::DynamicField"); my $CustomerUserObject = $Kernel::OM->Get("Kernel::System::CustomerUser"); my $TicketWizard = $Kernel::OM->Get("Kernel::System::TicketWizard"); my $QueueObject = $Kernel::OM->Get("Kernel::System::Queue"); my $QueueServiceObject = $Kernel::OM->Get("Kernel::System::QueueService"); my $ServiceObject = $Kernel::OM->Get("Kernel::System::Service"); my $MaintenanceObject = $Kernel::OM->Get("Kernel::System::Maintenance"); my $DateUtilsObject = $Kernel::OM->Get("Kernel::System::DateUtils"); my $LanguageObject = $Kernel::OM->Get("Kernel::Language"); if ($Param{Public}) { $Data{AuthenticateURL} = $ConfigObject->Get('Customer::AuthModule::CAS::CASUrl') . "/login?service=" . "https://" . $ENV{SERVER_NAME} . $ENV{SCRIPT_NAME} . "?Action=NewTicketWizard"; } # Check if queue parameter was received if ($ParamObject->GetParam(Param => "QueueID")) { $Data{QueueID} = $ParamObject->GetParam(Param => "QueueID"); $LayoutObject->AddJSData( Key => 'NewTicketWizard.QueueID', Value => $Data{QueueID}, ); $Self->Debug("Specific queue defined => " . $Data{QueueID}); } else { # Check if must show queue - if so, redirect user my $_ConfigTicketWizard = $ConfigObject->Get("Ticket::Frontend::Customer::NewTicketWizard"); my $_ShowQueue = $_ConfigTicketWizard->{"ShowQueue"}; if (! $_ShowQueue) { $Self->Debug("Queue selection must be shown - redirection to QueuePanelPublic action"); return $LayoutObject->Redirect( OP => "Action=QueuesPanelPublic" ); } } my ( $schema, $fields ) = $TicketWizard->GetForm(Public => $Param{Public}); $Data{SchemaForm} = $schema; $Data{FieldsForm} = $fields; # Common info $Self->{ConfigNTW} = $ConfigObject->Get("Ticket::Frontend::Customer::NewTicketWizard"); my $idCustomTemplate = "NTW" . $Self->{ConfigNTW}->{"CustomTemplate"}; my $msgChooseService; if ($Param{Public}) { $msgChooseService = $Self->{ConfigNTW}->{"MessageChooseServicePublic"}; } else { $msgChooseService = $Self->{ConfigNTW}->{"MessageChooseService"}; } if ($ParamObject->GetParam( Param => "QueueID" ) ) { my %queueData = $QueueObject->QueueGet(ID => $ParamObject->GetParam( Param => "QueueID" )); my $queueName = $queueData{Name}; $msgChooseService =~ s/PLACE\_NAME/$queueName/g; } $Data{MsgChooseService} = $msgChooseService; $Self->{DefaultUserID} = $Self->{ConfigNTW}->{"DefaultUserID"}; $Self->{DefaultCustomerID} = $Self->{ConfigNTW}->{"DefaultCustomerID"}; $Self->{DefaultUserDomain} = $Self->{ConfigNTW}->{"DefaultUserDomain"}; # Build service chooser $Data{ServiceStrg} = $TicketWizard->BuildServices(ServiceID => $ParamObject->GetParam( Param => "ServiceID" ), Public => $Param{Public}); # Build output my $Output = $LayoutObject->CustomerHeader(Type => $idCustomTemplate, Title => $LanguageObject->Translate("New ticket wizard") ); # Load current maintenances my @maintenances = $MaintenanceObject->ListMaintenances(Type => "current"); if (@maintenances) { $LayoutObject->Block( Name => 'MaintenancesPanel', ); for my $maintenanceHash (@maintenances) { my %maintenance = %{$maintenanceHash}; $LayoutObject->Block( Name => 'MaintenanceLine', Data => { Message => $maintenance{'Description'}, StartDate => $DateUtilsObject->BrazilianDate(Timestamp => $DateUtilsObject->FromSQL(StringDate => $maintenance{StartDate})), }); } } if ($Param{Public}) { $Self->Debug("Public view - unauthenticated message enabled"); $LayoutObject->Block( Name => 'UnauthenticatedMessage', ); $Self->Debug("Public view - public toolbar enabled"); $LayoutObject->Block( Name => 'ToolBarPublic', ); } else { $Self->Debug("Customer view - customer toolbar enabled"); $LayoutObject->Block( Name => 'ToolBarCustomer', ); } # Prepare cache for imagens and attachments my $WebUploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache'); $Data{FormID} = $WebUploadCacheObject->FormIDCreate(); $LayoutObject->AddJSData( Key => 'NewTicketWizard.FormID', Value => $Data{FormID}, ); if ($Param{Public}) { $Data{PublicMode} = "Public"; } $Output .= $LayoutObject->Output( Data => \%Data, TemplateFile => 'NewTicketWizard', ); $Output .= $LayoutObject->CustomerFooter(Type => $idCustomTemplate); return $Output; } =head Separate service-field label names, to make it human-readable (CapitalLikeLabels -> Capital like labels) =cut sub breakWords { my ( $Self, %Param ) = @_; my $return = $Param{Text}; $return =~ s/(.)([A-Z][^A-Z])/$1 $2/g; $return =~ s/([\w']+)/\u\L$1/g; return $return; } sub Debug { my $Self = shift; my $msg = shift; $Kernel::OM->Get("Kernel::System::Log")->Log( Priority => 'debug', Message => $msg ); } 1;