2206 lines
80 KiB
Perl
2206 lines
80 KiB
Perl
# --
|
|
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
|
# --
|
|
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
# the enclosed file COPYING for license information (GPL). If you
|
|
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
|
# --
|
|
|
|
package Kernel::System::Ticket::TicketACL;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Kernel::System::VariableCheck qw(:all);
|
|
|
|
our $ObjectManagerDisabled = 1;
|
|
|
|
=head1 NAME
|
|
|
|
Kernel::System::Ticket::TicketACL - ticket ACL lib
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
All ticket ACL functions.
|
|
|
|
|
|
=head2 TicketAcl()
|
|
|
|
Restricts the Data parameter sent to a subset of it, depending on a group of user defied rules
|
|
called ACLs. The reduced subset can be access from TicketACLData() if ReturnType parameter is set
|
|
to: Ticket, Process or ActivityDialog, or in TicketACLActionData(), if ReturnType Action is used.
|
|
|
|
Each ACL can contain different restrictions for different objects the ReturnType parameter defines
|
|
which object is considered for this restrictions, in the case of the Ticket object a second
|
|
parameter called ReturnSubtype is needed, to specify the ticket attribute to be restricted, like:
|
|
Queue, State, Owner, etc. While for the rest of the objects a "-" value must be set. The ReturnType
|
|
and ReturnSubType must be set according to the Data parameter sent.
|
|
|
|
The rest of the attributes define the matching options for the ACL rules.
|
|
|
|
Example to restrict ticket actions:
|
|
|
|
my $Success = $TicketObject->TicketAcl(
|
|
Data => { # Values to restrict
|
|
1 => AgentTicketZoom,
|
|
# ...
|
|
},
|
|
|
|
Action => 'AgentTicketZoom', # Optional
|
|
TicketID => 123, # Optional
|
|
DynamicField => { # Optional
|
|
DynamicField_NameX => 123,
|
|
DynamicField_NameZ => 'some value',
|
|
},
|
|
|
|
QueueID => 123, # Optional
|
|
Queue => 'some queue name', # Optional
|
|
NewQueueID => 123, # Optional, QueueID or NewQueueID can be
|
|
# used and they both refers to QueueID
|
|
|
|
ServiceID => 123, # Optional
|
|
Service => 'some service name', # Optional
|
|
|
|
TypeID => 123,
|
|
Type => 'some ticket type name', # Optional
|
|
|
|
PriorityID => 123, # Optional
|
|
NewPriorityID => 123, # Optional, PriorityID or NewPriorityID can be
|
|
# used and they both refers to PriorityID
|
|
Priority => 'some priority name', # Optional
|
|
|
|
SLAID => 123,
|
|
SLA => 'some SLA name', # Optional
|
|
|
|
StateID => 123, # Optional
|
|
NextStateID => 123, # Optional, StateID or NextStateID can be
|
|
# used and they both refers to StateID
|
|
State => 'some ticket state name', # Optional
|
|
|
|
OwnerID => 123, # Optional
|
|
NewOwnerID => 123, # Optional, OwnerID or NewOwnerID can be
|
|
# used and they both refers to OwnerID
|
|
Owner => 'some user login' # Optional
|
|
|
|
ResponsibleID => 123, # Optional
|
|
NewResponsibleID => 123, # Optional, ResponsibleID or NewResposibleID
|
|
# can be used and they both refers to
|
|
# ResponsibleID
|
|
Responsible => 'some user login' # Optional
|
|
|
|
ReturnType => 'Action', # To match Possible, PossibleAdd or
|
|
# PossibleNot key in ACL
|
|
ReturnSubType => '-', # To match Possible, PossibleAdd or
|
|
# PossibleNot sub-key in ACL
|
|
|
|
UserID => 123, # UserID => 1 is not affected by this function
|
|
CustomerUserID => 'customer login', # UserID or CustomerUserID are mandatory
|
|
|
|
# Process Management Parameters
|
|
ProcessEntityID => 123, # Optional
|
|
ActivityEntityID => 123, # Optional
|
|
ActivityDialogEntityID => 123, # Optional
|
|
);
|
|
|
|
or to restrict ticket states:
|
|
|
|
$Success = $TicketObject->TicketAcl(
|
|
Data => {
|
|
1 => 'new',
|
|
2 => 'open',
|
|
# ...
|
|
},
|
|
ReturnType => 'Ticket',
|
|
ReturnSubType => 'State',
|
|
UserID => 123,
|
|
);
|
|
|
|
returns:
|
|
$Success = 1, # if an ACL matches, or false otherwise.
|
|
|
|
If ACL modules are configured in the C<Ticket::Acl::Module> config key, they are invoked
|
|
during the call to C<TicketAcl>. The configuration of a module looks like this:
|
|
|
|
$ConfigObject->{'Ticket::Acl::Module'}->{'TheName'} = {
|
|
Module => 'Kernel::System::Ticket::Acl::TheAclModule',
|
|
Checks => ['Owner', 'Queue', 'SLA', 'Ticket'],
|
|
ReturnType => 'Ticket',
|
|
ReturnSubType => ['State', 'Service'],
|
|
};
|
|
|
|
Each time the C<ReturnType> and one of the C<ReturnSubType> entries is identical to the same
|
|
arguments passed to C<TicketAcl>, the module of the name in C<Module> is loaded, the C<new> method
|
|
is called on it, and then the C<Run> method is called.
|
|
|
|
The C<Checks> array reference in the configuration controls what arguments are passed. to the
|
|
C<Run> method.
|
|
Valid keys are C<CustomerUser>, C<DynamicField>, C<Frontend>, C<Owner>, C<Priority>, C<Process>,
|
|
C<Queue>, C<Responsible>, C<Service>, C<SLA>, C<State>, C<Ticket> and C<Type>. If any of those are
|
|
present, the C<Checks> argument passed to C<Run> contains an entry with the same name, and as a
|
|
value the associated data.
|
|
|
|
The C<Run> method can add entries to the C<Acl> param hash, which are then evaluated along with all
|
|
other ACL. It should only add entries whose conditionals can be checked with the data specified in
|
|
the C<Checks> configuration entry.
|
|
|
|
The return value of the C<Run> method is ignored.
|
|
|
|
=cut
|
|
|
|
sub TicketAcl {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{UserID} && !$Param{CustomerUserID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need UserID or CustomerUserID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(ReturnSubType ReturnType Data)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# do not execute ACLs if UserID 1 is used
|
|
return if $Param{UserID} && $Param{UserID} == 1;
|
|
|
|
# get config object
|
|
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
|
|
|
my $ACLs = $ConfigObject->Get('TicketAcl');
|
|
my $AclModules = $ConfigObject->Get('Ticket::Acl::Module');
|
|
|
|
# only execute ACLs if ACL or ACL module is configured
|
|
if ( !$ACLs && !$AclModules ) {
|
|
return;
|
|
}
|
|
|
|
# find out which data we actually need
|
|
my %ApplicableAclModules;
|
|
my %RequiredChecks;
|
|
my $CheckAll = 0;
|
|
|
|
MODULENAME:
|
|
for my $ModuleName ( sort keys %{ $AclModules // {} } ) {
|
|
my $Module = $AclModules->{$ModuleName};
|
|
if ( $Module->{ReturnType} && $Module->{ReturnType} ne $Param{ReturnType} ) {
|
|
next MODULENAME;
|
|
}
|
|
if ( $Module->{ReturnSubType} ) {
|
|
if ( ref( $Module->{ReturnSubType} ) eq 'HASH' ) {
|
|
next MODULENAME if !grep { $Param{ReturnSubType} eq $_ }
|
|
@{ $Module->{ReturnSubType} };
|
|
}
|
|
else {
|
|
|
|
# a scalar, we hope
|
|
next MODULENAME if !$Module->{ReturnSubType} eq $Param{ReturnSubType};
|
|
}
|
|
}
|
|
|
|
# here only modules applicable to this ACL invocation remain
|
|
$ApplicableAclModules{$ModuleName} = $Module;
|
|
|
|
if ( $Module->{Checks} && ref( $Module->{Checks} ) eq 'ARRAY' ) {
|
|
$RequiredChecks{$_} = 1 for @{ $Module->{Checks} };
|
|
}
|
|
elsif ( $Module->{Checks} ) {
|
|
$RequiredChecks{ $Module->{Checks} } = 1;
|
|
}
|
|
else {
|
|
$CheckAll = 1;
|
|
}
|
|
}
|
|
|
|
return if !%ApplicableAclModules && !$ACLs && !$CheckAll;
|
|
|
|
for my $ACL ( values %{ $ACLs // {} } ) {
|
|
for my $Source (qw/ Properties PropertiesDatabase/) {
|
|
for my $Check ( sort keys %{ $ACL->{$Source} } ) {
|
|
my $CleanedUp = $Check;
|
|
$CleanedUp =~ s/(?:ID|Name|Login)$//;
|
|
$CleanedUp =~ s/^(?:Next|New|Old)//;
|
|
$RequiredChecks{$CleanedUp} = 1;
|
|
if ( $Check eq 'Ticket' ) {
|
|
if ( ref( $ACL->{Properties}{$Check} ) eq 'HASH' ) {
|
|
for my $InnerCheck ( sort keys %{ $ACL->{$Source}{$Check} } ) {
|
|
$InnerCheck =~ s/(?:ID|Name|Login)$//;
|
|
$InnerCheck =~ s/^(?:Next|New|Old)//;
|
|
$RequiredChecks{$InnerCheck} = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# gather all required data to be compared against the ACLs
|
|
my $CheckResult = $Self->_GetChecks(
|
|
%Param,
|
|
CheckAll => $CheckAll,
|
|
RequiredChecks => \%RequiredChecks,
|
|
);
|
|
my %Checks = %{ $CheckResult->{Checks} || {} };
|
|
my %ChecksDatabase = %{ $CheckResult->{ChecksDatabase} || {} };
|
|
|
|
# check ACL configuration
|
|
my %Acls;
|
|
if ( $ConfigObject->Get('TicketAcl') ) {
|
|
%Acls = %{ $ConfigObject->Get('TicketAcl') };
|
|
}
|
|
|
|
# check ACL module
|
|
MODULE:
|
|
for my $ModuleName ( sort keys %ApplicableAclModules ) {
|
|
|
|
my $Module = $ApplicableAclModules{$ModuleName};
|
|
|
|
next MODULE if !$Kernel::OM->Get('Kernel::System::Main')->Require( $Module->{Module} );
|
|
|
|
my $Generic = $Module->{Module}->new();
|
|
|
|
$Generic->Run(
|
|
%Param,
|
|
Acl => \%Acls,
|
|
Checks => \%Checks,
|
|
Config => $Module,
|
|
);
|
|
}
|
|
|
|
# get used data
|
|
my %Data;
|
|
if ( ref $Param{Data} ) {
|
|
%Data = %{ $Param{Data} };
|
|
}
|
|
|
|
my %NewData;
|
|
my $UseNewMasterParams = 0;
|
|
|
|
my %NewDefaultActionData;
|
|
|
|
if ( $Param{ReturnType} eq 'Action' ) {
|
|
|
|
if ( !IsHashRefWithData( $Param{Data} ) ) {
|
|
|
|
# use Data if is a string and it is not '-'
|
|
if ( IsStringWithData( $Param{Data} ) && $Param{Data} ne '-' ) {
|
|
%Data = ( 1 => $Param{Data} );
|
|
}
|
|
|
|
# otherwise use the param Action
|
|
elsif ( IsStringWithData( $Param{Action} ) ) {
|
|
%Data = ( 1 => $Param{Action} );
|
|
}
|
|
}
|
|
|
|
my %NewActionData = %Data;
|
|
|
|
# calculate default ticket action ACL data
|
|
my @ActionsToDelete;
|
|
my $DefaultActionData = $ConfigObject->Get('TicketACL::Default::Action') || {};
|
|
|
|
if ( IsHashRefWithData($DefaultActionData) ) {
|
|
|
|
for my $Index ( sort keys %NewActionData ) {
|
|
|
|
my $Action = $NewActionData{$Index};
|
|
if ( !$DefaultActionData->{$Index} ) {
|
|
push @ActionsToDelete, $Action;
|
|
}
|
|
}
|
|
}
|
|
|
|
$Self->{DefaultTicketAclActionData} = \%NewActionData;
|
|
|
|
for my $Action (@ActionsToDelete) {
|
|
delete $Self->{DefaultTicketAclActionData}->{$Action};
|
|
}
|
|
}
|
|
|
|
# set NewTmpData after Possible Data recalculation on ReturnType Action
|
|
my %NewTmpData = %Data;
|
|
|
|
# get the debug parameters
|
|
$Self->{ACLDebug} = $ConfigObject->Get('TicketACL::Debug::Enabled') || 0;
|
|
$Self->{ACLDebugLogPriority} = $ConfigObject->Get('TicketACL::Debug::LogPriority') || 'debug';
|
|
|
|
my $ACLDebugConfigFilters = $ConfigObject->Get('TicketACL::Debug::Filter') || {};
|
|
for my $FilterName ( sort keys %{$ACLDebugConfigFilters} ) {
|
|
my %Filter = %{ $ACLDebugConfigFilters->{$FilterName} };
|
|
for my $FilterItem ( sort keys %Filter ) {
|
|
$Self->{ACLDebugFilters}->{$FilterItem} = $Filter{$FilterItem};
|
|
}
|
|
}
|
|
|
|
# check if debug filters apply (ticket)
|
|
if ( $Self->{ACLDebug} ) {
|
|
|
|
DEBUGFILTER:
|
|
for my $DebugFilter ( sort keys %{ $Self->{ACLDebugFilters} } ) {
|
|
next DEBUGFILTER if $DebugFilter eq 'ACLName';
|
|
next DEBUGFILTER if !$Self->{ACLDebugFilters}->{$DebugFilter};
|
|
|
|
if ( $DebugFilter =~ m{<OTRS_TICKET_([^>]+)>}msx ) {
|
|
my $TicketParam = $1;
|
|
|
|
if (
|
|
defined $ChecksDatabase{Ticket}->{$TicketParam}
|
|
&& $ChecksDatabase{Ticket}->{$TicketParam}
|
|
&& $Self->{ACLDebugFilters}->{$DebugFilter} ne
|
|
$ChecksDatabase{Ticket}->{$TicketParam}
|
|
)
|
|
{
|
|
$Self->{ACLDebug} = 0;
|
|
last DEBUGFILTER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# remember last ACLDebug state (before ACLs loop)
|
|
$Self->{ACLDebugRecovery} = $Self->{ACLDebug};
|
|
|
|
ACLRULES:
|
|
for my $Acl ( sort keys %Acls ) {
|
|
|
|
# check if debug filters apply (ACL) (only if ACLDebug is active)
|
|
if (
|
|
$Self->{ACLDebugRecovery}
|
|
&& defined $Self->{ACLDebugFilters}->{'ACLName'}
|
|
&& $Self->{ACLDebugFilters}->{'ACLName'}
|
|
)
|
|
{
|
|
# if not match current ACL disable ACLDebug
|
|
if ( $Self->{ACLDebugFilters}->{'ACLName'} ne $Acl ) {
|
|
$Self->{ACLDebug} = 0;
|
|
}
|
|
|
|
# reenable otherwise (we are sure it was enabled before)
|
|
else {
|
|
$Self->{ACLDebug} = 1;
|
|
}
|
|
}
|
|
|
|
my %Step = %{ $Acls{$Acl} };
|
|
|
|
# check force match
|
|
my $ForceMatch;
|
|
if (
|
|
!IsHashRefWithData( $Step{Properties} )
|
|
&& !IsHashRefWithData( $Step{PropertiesDatabase} )
|
|
)
|
|
{
|
|
$ForceMatch = 1;
|
|
}
|
|
|
|
my $PropertiesMatch;
|
|
my $PropertiesMatchTry;
|
|
my $PropertiesDatabaseMatch;
|
|
my $PropertiesDatabaseMatchTry;
|
|
my $UseNewParams = 0;
|
|
|
|
for my $PropertiesHash (qw(Properties PropertiesDatabase)) {
|
|
|
|
my %UsedChecks = %Checks;
|
|
if ( $PropertiesHash eq 'PropertiesDatabase' ) {
|
|
%UsedChecks = %ChecksDatabase;
|
|
}
|
|
|
|
# set match params
|
|
my $Match = 1;
|
|
my $MatchTry = 0;
|
|
for my $Key ( sort keys %{ $Step{$PropertiesHash} } ) {
|
|
for my $Data ( sort keys %{ $Step{$PropertiesHash}->{$Key} } ) {
|
|
my $MatchProperty = 0;
|
|
for my $Item ( @{ $Step{$PropertiesHash}->{$Key}->{$Data} } ) {
|
|
if ( ref $UsedChecks{$Key}->{$Data} eq 'ARRAY' ) {
|
|
my $MatchItem = 0;
|
|
if ( substr( $Item, 0, length '[Not' ) eq '[Not' ) {
|
|
$MatchItem = 1;
|
|
}
|
|
my $MatchedArrayDataItem;
|
|
ARRAYDATAITEM:
|
|
for my $ArrayDataItem ( @{ $UsedChecks{$Key}->{$Data} } ) {
|
|
$MatchedArrayDataItem = $ArrayDataItem;
|
|
my $LoopMatchResult = $Self->_CompareMatchWithData(
|
|
Match => $Item,
|
|
Data => $ArrayDataItem,
|
|
SingleItem => 0,
|
|
);
|
|
if ( !$LoopMatchResult->{Skip} )
|
|
{
|
|
$MatchItem = $LoopMatchResult->{Match};
|
|
last ARRAYDATAITEM;
|
|
}
|
|
}
|
|
if ($MatchItem) {
|
|
$MatchProperty = 1;
|
|
|
|
# debug log
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' $PropertiesHash:'$Key->$Data' MatchedARRAY ($Item eq $MatchedArrayDataItem)",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
elsif ( defined $UsedChecks{$Key}->{$Data} ) {
|
|
|
|
my $DataItem = $UsedChecks{$Key}->{$Data};
|
|
my $MatchResult = $Self->_CompareMatchWithData(
|
|
Match => $Item,
|
|
Data => $DataItem,
|
|
SingleItem => 1
|
|
);
|
|
|
|
if ( $MatchResult->{Match} ) {
|
|
$MatchProperty = 1;
|
|
|
|
# debug
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' $PropertiesHash:'$Key->$Data' Matched ($Item eq $UsedChecks{$Key}->{$Data})",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( !$MatchProperty ) {
|
|
$Match = 0;
|
|
}
|
|
$MatchTry = 1;
|
|
}
|
|
}
|
|
|
|
# check force option
|
|
if ($ForceMatch) {
|
|
$Match = 1;
|
|
$MatchTry = 1;
|
|
}
|
|
|
|
if ( $PropertiesHash eq 'Properties' ) {
|
|
$PropertiesMatch = $Match;
|
|
$PropertiesMatchTry = $MatchTry;
|
|
}
|
|
else {
|
|
$PropertiesDatabaseMatch = $Match;
|
|
$PropertiesDatabaseMatchTry = $MatchTry;
|
|
}
|
|
|
|
# check if properties is missing
|
|
if ( !IsHashRefWithData( $Step{Properties} ) ) {
|
|
$PropertiesMatch = $PropertiesDatabaseMatch;
|
|
$PropertiesMatchTry = $PropertiesDatabaseMatchTry;
|
|
}
|
|
|
|
# check if properties database is missing
|
|
if ( !IsHashRefWithData( $Step{PropertiesDatabase} ) ) {
|
|
$PropertiesDatabaseMatch = $PropertiesMatch;
|
|
$PropertiesDatabaseMatchTry = $PropertiesMatchTry;
|
|
}
|
|
}
|
|
|
|
# the following logic should be applied to calculate if an ACL matches:
|
|
# if both Properties and PropertiesDatabase match => match
|
|
# if Properties matches, and PropertiesDatabase does not match => no match
|
|
# if PropertiesDatabase matches, but Properties does not match => no match
|
|
# if PropertiesDatabase matches, and Properties is missing => match
|
|
# if Properties matches, and PropertiesDatabase is missing => match.
|
|
my $Match;
|
|
if ( $PropertiesMatch && $PropertiesDatabaseMatch ) {
|
|
$Match = 1;
|
|
}
|
|
|
|
my $MatchTry;
|
|
if ( $PropertiesMatchTry && $PropertiesDatabaseMatchTry ) {
|
|
$MatchTry = 1;
|
|
}
|
|
|
|
# debug log
|
|
if ( $Match && $MatchTry ) {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Matched for return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
|
|
my %SpecialReturnTypes = (
|
|
Action => 1,
|
|
Process => 1,
|
|
ActivityDialog => 1,
|
|
);
|
|
|
|
if ( $SpecialReturnTypes{ $Param{ReturnType} } ) {
|
|
|
|
# build new Special ReturnType data hash (ProcessManagement)
|
|
# for Special ReturnType Step{Possible}
|
|
if (
|
|
( %Checks || %ChecksDatabase )
|
|
&& $Match
|
|
&& $MatchTry
|
|
&& $Step{Possible}->{ $Param{ReturnType} }
|
|
&& IsArrayRefWithData( $Step{Possible}->{ $Param{ReturnType} } )
|
|
)
|
|
{
|
|
$UseNewParams = 1;
|
|
|
|
# reset return data as it will be filled with just the Possible Items excluded the
|
|
# ones that are not in the possible section, this is the same as remove all
|
|
# missing items from the original data
|
|
%NewTmpData = ();
|
|
|
|
# debug log
|
|
if ( $Self->{ADLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Used with Possible:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Reset return data:'$Param{ReturnType}:$Param{ReturnSubType}''",
|
|
);
|
|
}
|
|
|
|
# possible list
|
|
for my $ID ( sort keys %Data ) {
|
|
|
|
for my $New ( @{ $Step{Possible}->{ $Param{ReturnType} } } ) {
|
|
my $MatchResult = $Self->_CompareMatchWithData(
|
|
Match => $New,
|
|
Data => $Data{$ID},
|
|
SingleItem => 1
|
|
);
|
|
if ( $MatchResult->{Match} ) {
|
|
$NewTmpData{$ID} = $Data{$ID};
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Possible param '$Data{$ID}' added to return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Possible param '$Data{$ID}' skipped from return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# for Special ReturnType Step{PossibleAdd}
|
|
if (
|
|
( %Checks || %ChecksDatabase )
|
|
&& $Match
|
|
&& $MatchTry
|
|
&& $Step{PossibleAdd}->{ $Param{ReturnType} }
|
|
&& IsArrayRefWithData( $Step{PossibleAdd}->{ $Param{ReturnType} } )
|
|
)
|
|
{
|
|
|
|
$UseNewParams = 1;
|
|
|
|
# debug log
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Used with PossibleAdd:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
|
|
# possible add list
|
|
for my $ID ( sort keys %Data ) {
|
|
|
|
for my $New ( @{ $Step{PossibleAdd}->{ $Param{ReturnType} } } ) {
|
|
my $MatchResult = $Self->_CompareMatchWithData(
|
|
Match => $New,
|
|
Data => $Data{$ID},
|
|
SingleItem => 1
|
|
);
|
|
if ( $MatchResult->{Match} ) {
|
|
$NewTmpData{$ID} = $Data{$ID};
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' PossibleAdd param '$Data{$ID}' added to return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' PossibleAdd param '$Data{$ID}' skipped from return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# for Special Step{PossibleNot}
|
|
if (
|
|
( %Checks || %ChecksDatabase )
|
|
&& $Match
|
|
&& $MatchTry
|
|
&& $Step{PossibleNot}->{ $Param{ReturnType} }
|
|
&& IsArrayRefWithData( $Step{PossibleNot}->{ $Param{ReturnType} } )
|
|
)
|
|
{
|
|
|
|
$UseNewParams = 1;
|
|
|
|
# debug log
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Used with PossibleNot:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
|
|
# not possible list
|
|
for my $ID ( sort keys %Data ) {
|
|
my $Match = 1;
|
|
for my $New ( @{ $Step{PossibleNot}->{ $Param{ReturnType} } } ) {
|
|
my $LoopMatchResult = $Self->_CompareMatchWithData(
|
|
Match => $New,
|
|
Data => $Data{$ID},
|
|
SingleItem => 1
|
|
);
|
|
if ( $LoopMatchResult->{Match} ) {
|
|
$Match = 0;
|
|
}
|
|
}
|
|
if ( !$Match ) {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' PossibleNot param '$Data{$ID}' removed from return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
if ( $NewTmpData{$ID} ) {
|
|
delete $NewTmpData{$ID};
|
|
}
|
|
}
|
|
else {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' PossibleNot param '$Data{$ID}' leaved for return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
elsif ( $Param{ReturnType} eq 'Ticket' ) {
|
|
|
|
# build new ticket data hash
|
|
# Step Ticket Possible (Resets White list)
|
|
if (
|
|
( %Checks || %ChecksDatabase )
|
|
&& $Match
|
|
&& $MatchTry
|
|
&& $Step{Possible}->{Ticket}->{ $Param{ReturnSubType} }
|
|
)
|
|
{
|
|
$UseNewParams = 1;
|
|
|
|
# reset return data as it will be filled with just the Possible Items excluded the ones
|
|
# that are not in the possible section, this is the same as remove all missing items from
|
|
# the original data
|
|
%NewTmpData = ();
|
|
|
|
# debug log
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Used with Possible:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Reset return data:'$Param{ReturnType}:$Param{ReturnSubType}''",
|
|
);
|
|
}
|
|
|
|
# possible list
|
|
for my $ID ( sort keys %Data ) {
|
|
|
|
for my $New ( @{ $Step{Possible}->{Ticket}->{ $Param{ReturnSubType} } } ) {
|
|
my $MatchResult = $Self->_CompareMatchWithData(
|
|
Match => $New,
|
|
Data => $Data{$ID},
|
|
SingleItem => 1
|
|
);
|
|
if ( $MatchResult->{Match} ) {
|
|
$NewTmpData{$ID} = $Data{$ID};
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Possible param '$Data{$ID}' added to return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Possible param '$Data{$ID}' skipped from return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Step Ticket PossibleAdd (Add new options to the white list)
|
|
if (
|
|
( %Checks || %ChecksDatabase )
|
|
&& $Match
|
|
&& $MatchTry
|
|
&& $Step{PossibleAdd}->{Ticket}->{ $Param{ReturnSubType} }
|
|
)
|
|
{
|
|
$UseNewParams = 1;
|
|
|
|
# debug log
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Used with PossibleAdd:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
|
|
# possible add list
|
|
for my $ID ( sort keys %Data ) {
|
|
|
|
for my $New ( @{ $Step{PossibleAdd}->{Ticket}->{ $Param{ReturnSubType} } } ) {
|
|
my $MatchResult = $Self->_CompareMatchWithData(
|
|
Match => $New,
|
|
Data => $Data{$ID},
|
|
SingleItem => 1
|
|
);
|
|
if ( $MatchResult->{Match} ) {
|
|
$NewTmpData{$ID} = $Data{$ID};
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' PossibleAdd param '$Data{$ID}' added to return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' PossibleAdd param '$Data{$ID}' skipped from return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Step Ticket PossibleNot (removes options from white list)
|
|
if (
|
|
( %Checks || %ChecksDatabase )
|
|
&& $Match
|
|
&& $MatchTry
|
|
&& $Step{PossibleNot}->{Ticket}->{ $Param{ReturnSubType} }
|
|
)
|
|
{
|
|
$UseNewParams = 1;
|
|
|
|
# debug log
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' Used with PossibleNot:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
|
|
# not possible list
|
|
for my $ID ( sort keys %Data ) {
|
|
my $Match = 1;
|
|
for my $New ( @{ $Step{PossibleNot}->{Ticket}->{ $Param{ReturnSubType} } } ) {
|
|
my $LoopMatchResult = $Self->_CompareMatchWithData(
|
|
Match => $New,
|
|
Data => $Data{$ID},
|
|
SingleItem => 1
|
|
);
|
|
if ( $LoopMatchResult->{Match} ) {
|
|
$Match = 0;
|
|
}
|
|
}
|
|
if ( !$Match ) {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' PossibleNot param '$Data{$ID}' removed from return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
if ( $NewTmpData{$ID} ) {
|
|
delete $NewTmpData{$ID};
|
|
}
|
|
}
|
|
else {
|
|
if ( $Self->{ACLDebug} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => $Self->{ACLDebugLogPriority},
|
|
Message =>
|
|
"TicketACL '$Acl' PossibleNot param '$Data{$ID}' leaved for return data:'$Param{ReturnType}:$Param{ReturnSubType}'",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# remember to new params if given
|
|
if ($UseNewParams) {
|
|
%NewData = %NewTmpData;
|
|
$UseNewMasterParams = 1;
|
|
}
|
|
|
|
# return new params if stop after this step
|
|
if ( $UseNewParams && $Step{StopAfterMatch} ) {
|
|
$Self->{TicketAclData} = \%NewData;
|
|
|
|
# if we stop after the first match
|
|
# exit the ACLRULES loop
|
|
last ACLRULES;
|
|
}
|
|
}
|
|
|
|
# return if no new param exists
|
|
return if !$UseNewMasterParams;
|
|
|
|
$Self->{TicketAclData} = \%NewData;
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 TicketAclData()
|
|
|
|
return the current ACL data hash after TicketAcl()
|
|
|
|
my %Acl = $TicketObject->TicketAclData();
|
|
|
|
=cut
|
|
|
|
sub TicketAclData {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
return %{ $Self->{TicketAclData} || {} };
|
|
}
|
|
|
|
=head2 TicketAclActionData()
|
|
|
|
return the current ACL action data hash after TicketAcl()
|
|
|
|
my %AclAction = $TicketObject->TicketAclActionData();
|
|
|
|
=cut
|
|
|
|
sub TicketAclActionData {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
if ( $Self->{TicketAclData} ) {
|
|
return %{ $Self->{TicketAclData} };
|
|
}
|
|
return %{ $Self->{DefaultTicketActionData} || {} };
|
|
}
|
|
|
|
=begin Internal:
|
|
|
|
=cut
|
|
|
|
=head2 _GetChecks()
|
|
|
|
creates two check hashes (one for current data updatable via AJAX refreshes and another for
|
|
static ticket data stored in the DB) with the required data to use as a basis to match the ACLs
|
|
|
|
my $ChecskResult = $TicketObject->_GetChecks(
|
|
CheckAll => '1', # Optional
|
|
RequiredChecks => $RequiredCheckHashRef, # Optional a hash reference with the
|
|
# attributes to gather:
|
|
# e. g. User => 1, will fetch all user
|
|
# information from the database, this data
|
|
# will be tried to match with current ACLs
|
|
Action => 'AgentTicketZoom', # Optional
|
|
TicketID => 123, # Optional
|
|
DynamicField => { # Optional
|
|
DynamicField_NameX => 123,
|
|
DynamicField_NameZ => 'some value',
|
|
},
|
|
|
|
QueueID => 123, # Optional
|
|
Queue => 'some queue name', # Optional
|
|
|
|
ServiceID => 123, # Optional
|
|
Service => 'some service name', # Optional
|
|
|
|
TypeID => 123,
|
|
Type => 'some ticket type name', # Optional
|
|
|
|
PriorityID => 123, # Optional
|
|
NewPriorityID => 123, # Optional, PriorityID or NewPriorityID can be
|
|
# used and they both refers to PriorityID
|
|
Priority => 'some priority name', # Optional
|
|
|
|
SLAID => 123,
|
|
SLA => 'some SLA name', # Optional
|
|
|
|
StateID => 123, # Optional
|
|
NextStateID => 123, # Optional, StateID or NextStateID can be
|
|
# used and they both refers to StateID
|
|
State => 'some ticket state name', # Optional
|
|
|
|
OwnerID => 123, # Optional
|
|
NewOwnerID => 123, # Optional, OwnerID or NewOwnerID can be
|
|
# used and they both refers to OwnerID
|
|
Owner => 'some user login' # Optional
|
|
|
|
ResponsibleID => 123, # Optional
|
|
NewResponsibleID => 123, # Optional, ResponsibleID or NewResposibleID
|
|
# can be used and they both refers to
|
|
# ResponsibleID
|
|
Responsible => 'some user login' # Optional
|
|
|
|
UserID => 123, # UserID => 1 is not affected by this function
|
|
CustomerUserID => 'customer login', # UserID or CustomerUserID are mandatory
|
|
|
|
# Process Management Parameters
|
|
ProcessEntityID => 123, # Optional
|
|
ActivityEntityID => 123, # Optional
|
|
ActivityDialogEntityID => 123, # Optional
|
|
);
|
|
|
|
returns:
|
|
$ChecksResult = {
|
|
Checks => {
|
|
# ...
|
|
Ticket => {
|
|
TicketID => 123,
|
|
# ...
|
|
Queue => 'some queue name',
|
|
QueueID => '123',
|
|
# ...
|
|
},
|
|
Queue => {
|
|
Name => 'some queue name',
|
|
# ...
|
|
},
|
|
# ...
|
|
},
|
|
ChecksDatabase =>
|
|
# ...
|
|
Ticket => {
|
|
TicketID => 123,
|
|
# ...
|
|
Queue => 'original queue name',
|
|
QueueID => '456',
|
|
# ...
|
|
},
|
|
Queue => {
|
|
Name => 'original queue name',
|
|
# ...
|
|
},
|
|
# ...
|
|
},
|
|
};
|
|
|
|
=cut
|
|
|
|
sub _GetChecks {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $CheckAll = $Param{CheckAll};
|
|
my %RequiredChecks = %{ $Param{RequiredChecks} };
|
|
|
|
# get used interface for process management checks
|
|
my $Interface = 'AgentInterface';
|
|
if ( !$Param{UserID} ) {
|
|
$Interface = 'CustomerInterface';
|
|
}
|
|
|
|
my %Checks;
|
|
my %ChecksDatabase;
|
|
|
|
if ( $Param{Action} ) {
|
|
$Checks{Frontend} = {
|
|
Action => $Param{Action},
|
|
};
|
|
$ChecksDatabase{Frontend} = {
|
|
Action => $Param{Action},
|
|
};
|
|
}
|
|
|
|
# get config object
|
|
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
|
|
|
# use ticket data if ticket id is given
|
|
# do that always, even if $RequiredChecks{Ticket} is not that
|
|
# (because too much stuff depends on it)
|
|
if ( $Param{TicketID} ) {
|
|
my %Ticket = $Self->TicketGet(
|
|
%Param,
|
|
DynamicFields => 1,
|
|
);
|
|
$Checks{Ticket} = \%Ticket;
|
|
|
|
# keep database ticket data separated since the reference is affected below
|
|
my %TicketDatabase = %Ticket;
|
|
$ChecksDatabase{Ticket} = \%TicketDatabase;
|
|
|
|
# get used dynamic fields where Activity and Process Entities IDs are Stored
|
|
# (ProcessManagement)
|
|
my $ActivityEntityIDField = $ConfigObject->Get("Process::DynamicFieldProcessManagementActivityID");
|
|
my $ProcessEntityIDField = $ConfigObject->Get("Process::DynamicFieldProcessManagementProcessID");
|
|
|
|
# check for ActivityEntityID
|
|
if ( $Ticket{ 'DynamicField_' . $ActivityEntityIDField } ) {
|
|
$ChecksDatabase{Process}->{ActivityEntityID} = $Ticket{ 'DynamicField_' . $ActivityEntityIDField };
|
|
}
|
|
|
|
# check for ProcessEntityID
|
|
if ( $Ticket{ 'DynamicField_' . $ProcessEntityIDField } ) {
|
|
$ChecksDatabase{Process}->{ProcessEntityID} = $Ticket{ 'DynamicField_' . $ProcessEntityIDField };
|
|
}
|
|
|
|
# take over the ChecksDatabase to the Checks hash as basis
|
|
if ( $ChecksDatabase{Process} && %{ $ChecksDatabase{Process} } ) {
|
|
my %ProcessDatabase = %{ $ChecksDatabase{Process} };
|
|
$Checks{Process} = \%ProcessDatabase;
|
|
}
|
|
}
|
|
|
|
# check for ProcessEntityID if set as parameter (ProcessManagement)
|
|
if ( ( $CheckAll || $RequiredChecks{Process} ) && $Param{ProcessEntityID} ) {
|
|
$Checks{Process}->{ProcessEntityID} = $Param{ProcessEntityID};
|
|
}
|
|
|
|
# check for ActivityDialogEntityID if set as parameter (ProcessManagement)
|
|
if ( ( $CheckAll || $RequiredChecks{Process} ) && $Param{ActivityDialogEntityID} ) {
|
|
|
|
my $ActivityDialog = $Kernel::OM->Get('Kernel::System::ProcessManagement::ActivityDialog')->ActivityDialogGet(
|
|
ActivityDialogEntityID => $Param{ActivityDialogEntityID},
|
|
Interface => $Interface,
|
|
);
|
|
|
|
if ( IsHashRefWithData($ActivityDialog) ) {
|
|
$Checks{Process}->{ActivityDialogEntityID} = $Param{ActivityDialogEntityID};
|
|
}
|
|
}
|
|
|
|
# check for dynamic fields
|
|
if ( IsHashRefWithData( $Param{DynamicField} ) ) {
|
|
$Checks{DynamicField} = $Param{DynamicField};
|
|
|
|
# update or add dynamic fields information to the ticket check
|
|
for my $DynamicFieldName ( sort keys %{ $Param{DynamicField} } ) {
|
|
$Checks{Ticket}->{$DynamicFieldName} = $Param{DynamicField}->{$DynamicFieldName};
|
|
}
|
|
}
|
|
|
|
# always get info from ticket too and set it to the Dynamic Field check hash if the info is
|
|
# different. this can be done because in the previous step ticket info was updated. but maybe
|
|
# ticket has more information stored than in the DynamicField parameter.
|
|
TICKETATTRIBUTE:
|
|
for my $TicketAttribute ( sort keys %{ $Checks{Ticket} // {} } ) {
|
|
next TICKETATTRIBUTE if !$TicketAttribute;
|
|
|
|
# check if is a dynamic field with data
|
|
next TICKETATTRIBUTE if $TicketAttribute !~ m{ \A DynamicField_ }smx;
|
|
next TICKETATTRIBUTE if !defined $Checks{Ticket}->{$TicketAttribute};
|
|
next TICKETATTRIBUTE if !length $Checks{Ticket}->{$TicketAttribute};
|
|
|
|
if (
|
|
ref $Checks{Ticket}->{$TicketAttribute} eq 'ARRAY'
|
|
&& !IsArrayRefWithData( $Checks{Ticket}->{$TicketAttribute} )
|
|
)
|
|
{
|
|
next TICKETATTRIBUTE;
|
|
}
|
|
|
|
# compare if data is different and skip on same data
|
|
if (
|
|
$Checks{DynamicField}->{$TicketAttribute}
|
|
&& !DataIsDifferent(
|
|
Data1 => $Checks{Ticket}->{$TicketAttribute},
|
|
Data2 => $Checks{DynamicField}->{$TicketAttribute},
|
|
)
|
|
)
|
|
{
|
|
next TICKETATTRIBUTE;
|
|
}
|
|
|
|
$Checks{DynamicField}->{$TicketAttribute} = $Checks{Ticket}->{$TicketAttribute};
|
|
}
|
|
|
|
# also copy the database information to the appropriate hash
|
|
TICKETATTRIBUTE:
|
|
for my $TicketAttribute ( sort keys %{ $ChecksDatabase{Ticket} } ) {
|
|
next TICKETATTRIBUTE if !$TicketAttribute;
|
|
|
|
# check if is a dynamic field with data
|
|
next TICKETATTRIBUTE if $TicketAttribute !~ m{ \A DynamicField_ }smx;
|
|
next TICKETATTRIBUTE if !defined $ChecksDatabase{Ticket}->{$TicketAttribute};
|
|
next TICKETATTRIBUTE if !length $ChecksDatabase{Ticket}->{$TicketAttribute};
|
|
|
|
if (
|
|
ref $ChecksDatabase{Ticket}->{$TicketAttribute} eq 'ARRAY'
|
|
&& !IsArrayRefWithData( $ChecksDatabase{Ticket}->{$TicketAttribute} )
|
|
)
|
|
{
|
|
next TICKETATTRIBUTE;
|
|
}
|
|
|
|
$ChecksDatabase{DynamicField}->{$TicketAttribute} = $ChecksDatabase{Ticket}->{$TicketAttribute};
|
|
}
|
|
|
|
# use user data
|
|
if ( ( $CheckAll || $RequiredChecks{User} ) && $Param{UserID} ) {
|
|
|
|
my %User = $Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
# get group object
|
|
my $GroupObject = $Kernel::OM->Get('Kernel::System::Group');
|
|
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $Param{UserID},
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$User{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$User{Role} = \@RoleNames;
|
|
$Checks{User} = \%User;
|
|
$ChecksDatabase{User} = \%User;
|
|
}
|
|
|
|
# get customer user objects
|
|
my $CustomerGroupObject = $Kernel::OM->Get('Kernel::System::CustomerGroup');
|
|
my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
|
|
|
|
# use customer user data
|
|
if ( ( $CheckAll || $RequiredChecks{CustomerUser} ) && $Param{CustomerUserID} ) {
|
|
|
|
my %CustomerUser = $CustomerUserObject->CustomerUserDataGet(
|
|
User => $Param{CustomerUserID},
|
|
);
|
|
|
|
for my $Type ( @{ $ConfigObject->Get('System::Customer::Permission') } ) {
|
|
|
|
my @Groups = $CustomerGroupObject->GroupMemberList(
|
|
UserID => $Param{CustomerUserID},
|
|
Result => 'Name',
|
|
Type => $Type,
|
|
);
|
|
|
|
$CustomerUser{"Group_$Type"} = \@Groups;
|
|
}
|
|
|
|
$Checks{CustomerUser} = \%CustomerUser;
|
|
|
|
# update or add customer information to the ticket check
|
|
$Checks{Ticket}->{CustomerUserID} = $Checks{CustomerUser}->{UserLogin};
|
|
$Checks{Ticket}->{CustomerID} = $Checks{CustomerUser}->{UserCustomerID};
|
|
}
|
|
else {
|
|
if ( IsStringWithData( $Checks{Ticket}->{CustomerUserID} ) ) {
|
|
|
|
# get customer data from the ticket
|
|
my %CustomerUser = $CustomerUserObject->CustomerUserDataGet(
|
|
User => $Checks{Ticket}->{CustomerUserID},
|
|
);
|
|
|
|
for my $Type ( @{ $ConfigObject->Get('System::Customer::Permission') } ) {
|
|
|
|
my @Groups = $CustomerGroupObject->GroupMemberList(
|
|
UserID => $Checks{Ticket}->{CustomerUserID},
|
|
Result => 'Name',
|
|
Type => $Type,
|
|
);
|
|
|
|
$CustomerUser{"Group_$Type"} = \@Groups;
|
|
}
|
|
|
|
$Checks{CustomerUser} = \%CustomerUser;
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if (
|
|
( $CheckAll || $RequiredChecks{CustomerUser} )
|
|
&& IsStringWithData( $ChecksDatabase{Ticket}->{CustomerUserID} )
|
|
)
|
|
{
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{CustomerUser}->{UserLogin}
|
|
&& $ChecksDatabase{Ticket}->{CustomerUserID} eq $Checks{CustomerUser}->{UserLogin}
|
|
)
|
|
{
|
|
$ChecksDatabase{CustomerUser} = $Checks{CustomerUser};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
|
|
my %CustomerUser = $CustomerUserObject->CustomerUserDataGet(
|
|
User => $ChecksDatabase{Ticket}->{CustomerUserID},
|
|
);
|
|
|
|
for my $Type ( @{ $ConfigObject->Get('System::Customer::Permission') } ) {
|
|
|
|
my @Groups = $CustomerGroupObject->GroupMemberList(
|
|
UserID => $ChecksDatabase{Ticket}->{CustomerUserID},
|
|
Result => 'Name',
|
|
Type => $Type,
|
|
);
|
|
|
|
$CustomerUser{"Group_$Type"} = \@Groups;
|
|
}
|
|
|
|
$ChecksDatabase{CustomerUser} = \%CustomerUser;
|
|
}
|
|
}
|
|
|
|
# use queue data (if given)
|
|
if ( $CheckAll || $RequiredChecks{Queue} ) {
|
|
|
|
# get queue object
|
|
my $QueueObject = $Kernel::OM->Get('Kernel::System::Queue');
|
|
|
|
if ( $Param{NewQueueID} && !$Param{QueueID} ) {
|
|
$Param{QueueID} = $Param{NewQueueID};
|
|
}
|
|
|
|
if ( $Param{QueueID} ) {
|
|
my %Queue = $QueueObject->QueueGet( ID => $Param{QueueID} );
|
|
$Checks{Queue} = \%Queue;
|
|
|
|
# update or add queue information to the ticket check
|
|
$Checks{Ticket}->{Queue} = $Checks{Queue}->{Name};
|
|
$Checks{Ticket}->{QueueID} = $Checks{Queue}->{QueueID};
|
|
}
|
|
elsif ( $Param{Queue} ) {
|
|
my %Queue = $QueueObject->QueueGet( Name => $Param{Queue} );
|
|
$Checks{Queue} = \%Queue;
|
|
|
|
# update or add queue information to the ticket check
|
|
$Checks{Ticket}->{Queue} = $Checks{Queue}->{Name};
|
|
$Checks{Ticket}->{QueueID} = $Checks{Queue}->{QueueID};
|
|
}
|
|
elsif ( !$Param{QueueID} && !$Param{Queue} ) {
|
|
if ( IsPositiveInteger( $Checks{Ticket}->{QueueID} ) ) {
|
|
|
|
# get queue data from the ticket
|
|
my %Queue = $QueueObject->QueueGet( ID => $Checks{Ticket}->{QueueID} );
|
|
$Checks{Queue} = \%Queue;
|
|
}
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if (
|
|
( $CheckAll || $RequiredChecks{Queue} )
|
|
&& IsPositiveInteger( $ChecksDatabase{Ticket}->{QueueID} )
|
|
)
|
|
{
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{Queue}->{QueueID}
|
|
&& $ChecksDatabase{Ticket}->{QueueID} eq $Checks{Queue}->{QueueID}
|
|
)
|
|
{
|
|
$ChecksDatabase{Queue} = $Checks{Queue};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
|
|
# get queue object
|
|
my $QueueObject = $Kernel::OM->Get('Kernel::System::Queue');
|
|
|
|
my %Queue = $QueueObject->QueueGet(
|
|
ID => $ChecksDatabase{Ticket}->{QueueID},
|
|
);
|
|
|
|
$ChecksDatabase{Queue} = \%Queue;
|
|
}
|
|
}
|
|
|
|
# use service data (if given)
|
|
if ( $CheckAll || $RequiredChecks{Service} ) {
|
|
|
|
# get service object
|
|
my $ServiceObject = $Kernel::OM->Get('Kernel::System::Service');
|
|
|
|
if ( $Param{ServiceID} ) {
|
|
my %Service = $ServiceObject->ServiceGet(
|
|
ServiceID => $Param{ServiceID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{Service} = \%Service;
|
|
|
|
# update or add service information to the ticket check
|
|
$Checks{Ticket}->{Service} = $Checks{Service}->{Name};
|
|
$Checks{Ticket}->{ServiceID} = $Checks{Service}->{ServiceID};
|
|
}
|
|
elsif ( $Param{Service} ) {
|
|
my %Service = $ServiceObject->ServiceGet(
|
|
Name => $Param{Service},
|
|
UserID => 1,
|
|
);
|
|
$Checks{Service} = \%Service;
|
|
|
|
# update or add service information to the ticket check
|
|
$Checks{Ticket}->{Service} = $Checks{Service}->{Name};
|
|
$Checks{Ticket}->{ServiceID} = $Checks{Service}->{ServiceID};
|
|
}
|
|
elsif ( !$Param{ServiceID} && !$Param{Service} ) {
|
|
if ( IsPositiveInteger( $Checks{Ticket}->{ServiceID} ) ) {
|
|
|
|
# get service data from the ticket
|
|
my %Service = $ServiceObject->ServiceGet(
|
|
ServiceID => $Checks{Ticket}->{ServiceID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{Service} = \%Service;
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if ( IsPositiveInteger( $ChecksDatabase{Ticket}->{ServiceID} ) ) {
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{Queue}->{QueueID}
|
|
&& $ChecksDatabase{Ticket}->{ServiceID} eq $Checks{Service}->{ServiceID}
|
|
)
|
|
{
|
|
$ChecksDatabase{Service} = $Checks{Service};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
my %Service = $ServiceObject->ServiceGet(
|
|
ServiceID => $ChecksDatabase{Ticket}->{ServiceID},
|
|
UserID => 1,
|
|
);
|
|
$ChecksDatabase{Service} = \%Service;
|
|
}
|
|
}
|
|
}
|
|
|
|
# use type data (if given)
|
|
if ( $CheckAll || $RequiredChecks{Type} ) {
|
|
|
|
# get type object
|
|
my $TypeObject = $Kernel::OM->Get('Kernel::System::Type');
|
|
|
|
if ( $Param{TypeID} ) {
|
|
my %Type = $TypeObject->TypeGet(
|
|
ID => $Param{TypeID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{Type} = \%Type;
|
|
|
|
# update or add ticket type information to the ticket check
|
|
$Checks{Ticket}->{Type} = $Checks{Type}->{Name};
|
|
$Checks{Ticket}->{TypeID} = $Checks{Type}->{ID};
|
|
}
|
|
elsif ( $Param{Type} ) {
|
|
|
|
# TODO Attention!
|
|
#
|
|
# The parameter type can contain not only the wanted ticket type, because also
|
|
# some other functions in Kernel/System/Ticket.pm use a type parameter, for example
|
|
# MoveList() etc... These functions could be rewritten to not
|
|
# use a Type parameter, or the functions that call TicketAcl() could be modified to
|
|
# not just pass the complete Param-Hash, but instead a new parameter, like FrontEndParameter.
|
|
#
|
|
# As a workaround we lookup the TypeList first, and compare if the type parameter
|
|
# is found in the list, so we can be more sure that it is the type that we want here.
|
|
|
|
# lookup the type list (workaround for described problem)
|
|
my %TypeList = reverse $TypeObject->TypeList();
|
|
|
|
# check if type is in the type list (workaround for described problem)
|
|
if ( $TypeList{ $Param{Type} } ) {
|
|
my %Type = $TypeObject->TypeGet(
|
|
Name => $Param{Type},
|
|
UserID => 1,
|
|
);
|
|
$Checks{Type} = \%Type;
|
|
|
|
# update or add ticket type information to the ticket check
|
|
$Checks{Ticket}->{Type} = $Checks{Type}->{Name};
|
|
$Checks{Ticket}->{TypeID} = $Checks{Type}->{ID};
|
|
}
|
|
}
|
|
elsif ( !$Param{TypeID} && !$Param{Type} ) {
|
|
if ( IsPositiveInteger( $Checks{Ticket}->{TypeID} ) ) {
|
|
|
|
# get type data from the ticket
|
|
my %Type = $TypeObject->TypeGet(
|
|
ID => $Checks{Ticket}->{TypeID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{Type} = \%Type;
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if ( IsPositiveInteger( $ChecksDatabase{Ticket}->{TypeID} ) ) {
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{Type}->{ID}
|
|
&& $ChecksDatabase{Ticket}->{TypeID} eq $Checks{Type}->{ID}
|
|
)
|
|
{
|
|
$ChecksDatabase{Type} = $Checks{Type};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
my %Type = $TypeObject->TypeGet(
|
|
ID => $ChecksDatabase{Ticket}->{TypeID},
|
|
UserID => 1,
|
|
);
|
|
$ChecksDatabase{Type} = \%Type;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $CheckAll || $RequiredChecks{Priority} ) {
|
|
|
|
# get priority object
|
|
my $PriorityObject = $Kernel::OM->Get('Kernel::System::Priority');
|
|
|
|
# use priority data (if given)
|
|
if ( $Param{NewPriorityID} && !$Param{PriorityID} ) {
|
|
$Param{PriorityID} = $Param{NewPriorityID};
|
|
}
|
|
|
|
if ( $Param{PriorityID} ) {
|
|
my %Priority = $PriorityObject->PriorityGet(
|
|
PriorityID => $Param{PriorityID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{Priority} = \%Priority;
|
|
|
|
# update or add priority information to the ticket check
|
|
$Checks{Ticket}->{Priority} = $Checks{Priority}->{Name};
|
|
$Checks{Ticket}->{PriorityID} = $Checks{Priority}->{ID};
|
|
}
|
|
elsif ( $Param{Priority} ) {
|
|
my $PriorityID = $PriorityObject->PriorityLookup(
|
|
Priority => $Param{Priority},
|
|
);
|
|
my %Priority = $PriorityObject->PriorityGet(
|
|
PriorityID => $PriorityID,
|
|
UserID => 1,
|
|
);
|
|
$Checks{Priority} = \%Priority;
|
|
|
|
# update or add priority information to the ticket check
|
|
$Checks{Ticket}->{Priority} = $Checks{Priority}->{Name};
|
|
$Checks{Ticket}->{PriorityID} = $Checks{Priority}->{ID};
|
|
}
|
|
elsif ( !$Param{PriorityID} && !$Param{Priority} ) {
|
|
if ( IsPositiveInteger( $Checks{Ticket}->{PriorityID} ) ) {
|
|
|
|
# get priority data from the ticket
|
|
my %Priority = $PriorityObject->PriorityGet(
|
|
PriorityID => $Checks{Ticket}->{PriorityID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{Priority} = \%Priority;
|
|
}
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if ( IsPositiveInteger( $ChecksDatabase{Ticket}->{PriorityID} ) ) {
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{Priority}->{ID}
|
|
&& $ChecksDatabase{Ticket}->{PriorityID} eq $Checks{Priority}->{ID}
|
|
)
|
|
{
|
|
$ChecksDatabase{Priority} = $Checks{Priority};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
|
|
# get priority object
|
|
my $PriorityObject = $Kernel::OM->Get('Kernel::System::Priority');
|
|
|
|
# get priority data from the ticket
|
|
my %Priority = $PriorityObject->PriorityGet(
|
|
PriorityID => $ChecksDatabase{Ticket}->{PriorityID},
|
|
UserID => 1,
|
|
);
|
|
$ChecksDatabase{Priority} = \%Priority;
|
|
}
|
|
}
|
|
|
|
# use SLA data (if given)
|
|
if ( $CheckAll || $RequiredChecks{SLA} ) {
|
|
|
|
# get sla object
|
|
my $SLAObject = $Kernel::OM->Get('Kernel::System::SLA');
|
|
|
|
if ( $Param{SLAID} ) {
|
|
my %SLA = $SLAObject->SLAGet(
|
|
SLAID => $Param{SLAID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{SLA} = \%SLA;
|
|
|
|
# update or add SLA information to the ticket check
|
|
$Checks{Ticket}->{SLA} = $Checks{SLA}->{Name};
|
|
$Checks{Ticket}->{SLAID} = $Checks{SLA}->{SLAID};
|
|
}
|
|
elsif ( $Param{SLA} ) {
|
|
my $SLAID = $SLAObject->SLALookup(
|
|
Name => $Param{SLA},
|
|
);
|
|
my %SLA = $SLAObject->SLAGet(
|
|
SLAID => $SLAID,
|
|
UserID => 1,
|
|
);
|
|
$Checks{SLA} = \%SLA;
|
|
|
|
# update or add SLA information to the ticket check
|
|
$Checks{Ticket}->{SLA} = $Checks{SLA}->{Name};
|
|
$Checks{Ticket}->{SLAID} = $Checks{SLA}->{SLAID};
|
|
}
|
|
elsif ( !$Param{SLAID} && !$Param{SLA} ) {
|
|
|
|
if ( IsPositiveInteger( $Checks{Ticket}->{SLAID} ) ) {
|
|
|
|
# get SLA data from the ticket
|
|
my %SLA = $SLAObject->SLAGet(
|
|
SLAID => $Checks{Ticket}->{SLAID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{SLA} = \%SLA;
|
|
}
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if ( IsPositiveInteger( $ChecksDatabase{Ticket}->{SLAID} ) ) {
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{SLA}->{SLAID}
|
|
&& $ChecksDatabase{Ticket}->{SLAID} eq $Checks{SLA}->{SLAID}
|
|
)
|
|
{
|
|
$ChecksDatabase{SLA} = $Checks{SLA};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
|
|
my %SLA = $Kernel::OM->Get('Kernel::System::SLA')->SLAGet(
|
|
SLAID => $ChecksDatabase{Ticket}->{SLAID},
|
|
UserID => 1,
|
|
);
|
|
$ChecksDatabase{SLA} = \%SLA;
|
|
}
|
|
}
|
|
|
|
# get state object
|
|
my $StateObject = $Kernel::OM->Get('Kernel::System::State');
|
|
|
|
# use state data (if given)
|
|
if ( $CheckAll || $RequiredChecks{State} ) {
|
|
if ( !$Param{StateID} ) {
|
|
$Param{StateID} = $Param{NextStateID} || $Param{NewStateID};
|
|
}
|
|
if ( $Param{StateID} ) {
|
|
my %State = $StateObject->StateGet(
|
|
ID => $Param{StateID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{State} = \%State;
|
|
|
|
# update or add state information to the ticket check
|
|
$Checks{Ticket}->{State} = $Checks{State}->{Name};
|
|
$Checks{Ticket}->{StateID} = $Checks{State}->{ID};
|
|
$Checks{Ticket}->{StateType} = $Checks{State}->{TypeName};
|
|
}
|
|
elsif ( $Param{State} ) {
|
|
my %State = $StateObject->StateGet(
|
|
Name => $Param{State},
|
|
UserID => 1,
|
|
);
|
|
$Checks{State} = \%State;
|
|
|
|
# update or add state information to the ticket check
|
|
$Checks{Ticket}->{State} = $Checks{State}->{Name};
|
|
$Checks{Ticket}->{StateID} = $Checks{State}->{ID};
|
|
$Checks{Ticket}->{StateType} = $Checks{State}->{TypeName};
|
|
}
|
|
elsif ( !$Param{StateID} && !$Param{State} ) {
|
|
if ( IsPositiveInteger( $Checks{Ticket}->{StateID} ) ) {
|
|
|
|
# get state data from the ticket
|
|
my %State = $StateObject->StateGet(
|
|
ID => $Checks{Ticket}->{StateID},
|
|
UserID => 1,
|
|
);
|
|
$Checks{State} = \%State;
|
|
}
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if ( IsPositiveInteger( $ChecksDatabase{Ticket}->{StateID} ) ) {
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{State}->{ID}
|
|
&& $ChecksDatabase{Ticket}->{StateID} eq $Checks{State}->{ID}
|
|
)
|
|
{
|
|
$ChecksDatabase{State} = $Checks{State};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
my %State = $StateObject->StateGet(
|
|
ID => $ChecksDatabase{Ticket}->{StateID},
|
|
UserID => 1,
|
|
);
|
|
$ChecksDatabase{State} = \%State;
|
|
}
|
|
}
|
|
|
|
# get needed objects
|
|
my $GroupObject = $Kernel::OM->Get('Kernel::System::Group');
|
|
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
|
|
|
|
# use owner data (if given)
|
|
if ( $CheckAll || $RequiredChecks{Owner} ) {
|
|
if (
|
|
$Param{NewOwnerID}
|
|
&& !$Param{OwnerID}
|
|
&& defined $Param{NewOwnerType}
|
|
&& $Param{NewOwnerType} eq 'New'
|
|
)
|
|
{
|
|
$Param{OwnerID} = $Param{NewOwnerID};
|
|
}
|
|
elsif (
|
|
$Param{OldOwnerID}
|
|
&& !$Param{OwnerID}
|
|
&& defined $Param{NewOwnerType}
|
|
&& $Param{NewOwnerType} eq 'Old'
|
|
)
|
|
{
|
|
$Param{OwnerID} = $Param{OldOwnerID};
|
|
}
|
|
|
|
if ( $Param{OwnerID} ) {
|
|
|
|
my %Owner = $UserObject->GetUserData(
|
|
UserID => $Param{OwnerID},
|
|
);
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $Param{OwnerID},
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$Owner{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $Param{OwnerID},
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$Owner{Role} = \@RoleNames;
|
|
$Checks{Owner} = \%Owner;
|
|
|
|
# update or add owner information to the ticket check
|
|
$Checks{Ticket}->{Owner} = $Checks{Owner}->{UserLogin};
|
|
$Checks{Ticket}->{OwnerID} = $Checks{Owner}->{UserID};
|
|
}
|
|
elsif ( $Param{Owner} ) {
|
|
my $OwnerID = $UserObject->UserLookup(
|
|
UserLogin => $Param{Owner},
|
|
);
|
|
my %Owner = $UserObject->GetUserData(
|
|
UserID => $OwnerID,
|
|
);
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $OwnerID,
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$Owner{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $OwnerID,
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$Owner{Role} = \@RoleNames;
|
|
$Checks{Owner} = \%Owner;
|
|
|
|
# update or add owner information to the ticket check
|
|
$Checks{Ticket}->{Owner} = $Checks{Owner}->{UserLogin};
|
|
$Checks{Ticket}->{OwnerID} = $Checks{Owner}->{UserID};
|
|
}
|
|
elsif ( !$Param{OwnerID} && !$Param{Owner} ) {
|
|
if ( IsPositiveInteger( $Checks{Ticket}->{OwnerID} ) ) {
|
|
|
|
# get responsible data from the ticket
|
|
my %Owner = $UserObject->GetUserData(
|
|
UserID => $Checks{Ticket}->{OwnerID},
|
|
);
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $Checks{Ticket}->{OwnerID},
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$Owner{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $Checks{Ticket}->{OwnerID},
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$Owner{Role} = \@RoleNames;
|
|
$Checks{Owner} = \%Owner;
|
|
}
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if ( IsPositiveInteger( $ChecksDatabase{Ticket}->{OwnerID} ) ) {
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{Owner}->{UserID}
|
|
&& $ChecksDatabase{Ticket}->{OwnerID} eq $Checks{Owner}->{UserID}
|
|
)
|
|
{
|
|
$ChecksDatabase{Owner} = $Checks{Owner};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
my %Owner = $UserObject->GetUserData(
|
|
UserID => $ChecksDatabase{Ticket}->{OwnerID},
|
|
);
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $ChecksDatabase{Ticket}->{OwnerID},
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$Owner{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $ChecksDatabase{Ticket}->{OwnerID},
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$Owner{Role} = \@RoleNames;
|
|
$ChecksDatabase{Owner} = \%Owner;
|
|
}
|
|
}
|
|
|
|
# use responsible data (if given)
|
|
$Param{ResponsibleID} ||= $Param{NewResponsibleID};
|
|
|
|
if ( $CheckAll || $RequiredChecks{Responsible} ) {
|
|
if ( $Param{ResponsibleID} ) {
|
|
my %Responsible = $UserObject->GetUserData(
|
|
UserID => $Param{ResponsibleID},
|
|
);
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $Param{ResponsibleID},
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$Responsible{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $Param{ResponsibleID},
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$Responsible{Role} = \@RoleNames;
|
|
$Checks{Responsible} = \%Responsible;
|
|
|
|
# update or add responsible information to the ticket check
|
|
$Checks{Ticket}->{Responsible} = $Checks{Responsible}->{UserLogin};
|
|
$Checks{Ticket}->{ResponsibleID} = $Checks{Responsible}->{UserID};
|
|
}
|
|
elsif ( $Param{Responsible} ) {
|
|
my $ResponsibleID = $UserObject->UserLookup(
|
|
UserLogin => $Param{Responsible},
|
|
);
|
|
my %Responsible = $UserObject->GetUserData(
|
|
UserID => $ResponsibleID,
|
|
);
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $ResponsibleID,
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$Responsible{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $ResponsibleID,
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$Responsible{Role} = \@RoleNames;
|
|
$Checks{Responsible} = \%Responsible;
|
|
|
|
# update or add responsible information to the ticket check
|
|
$Checks{Ticket}->{Responsible} = $Checks{Responsible}->{UserLogin};
|
|
$Checks{Ticket}->{ResponsibleID} = $Checks{Responsible}->{UserID};
|
|
}
|
|
elsif ( !$Param{ResponsibleID} && !$Param{Responsible} ) {
|
|
if ( IsPositiveInteger( $Checks{Ticket}->{ResponsibleID} ) ) {
|
|
|
|
# get responsible data from the ticket
|
|
my %Responsible = $UserObject->GetUserData(
|
|
UserID => $Checks{Ticket}->{ResponsibleID},
|
|
);
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $Checks{Ticket}->{ResponsibleID},
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$Responsible{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $Checks{Ticket}->{ResponsibleID},
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$Responsible{Role} = \@RoleNames;
|
|
$Checks{Responsible} = \%Responsible;
|
|
}
|
|
}
|
|
}
|
|
|
|
# create hash with the ticket information stored in the database
|
|
if ( IsPositiveInteger( $ChecksDatabase{Ticket}->{ResponsibleID} ) ) {
|
|
|
|
# check if database data matches current data (performance)
|
|
if (
|
|
defined $Checks{Owner}->{UserID}
|
|
&& defined $Checks{Responsible}->{UserID}
|
|
&& $ChecksDatabase{Ticket}->{ResponsibleID} eq $Checks{Responsible}->{UserID}
|
|
)
|
|
{
|
|
$ChecksDatabase{Responsible} = $Checks{Responsible};
|
|
}
|
|
|
|
# otherwise complete the data querying the database again
|
|
else {
|
|
|
|
my %Responsible = $UserObject->GetUserData(
|
|
UserID => $ChecksDatabase{Ticket}->{ResponsibleID},
|
|
);
|
|
|
|
for my $Type ( @{ $ConfigObject->Get('System::Permission') } ) {
|
|
|
|
my %Groups = $GroupObject->PermissionUserGet(
|
|
UserID => $ChecksDatabase{Ticket}->{ResponsibleID},
|
|
Type => $Type,
|
|
);
|
|
|
|
my @GroupNames = sort values %Groups;
|
|
|
|
$Responsible{"Group_$Type"} = \@GroupNames;
|
|
}
|
|
|
|
my %RoleIDs = $GroupObject->PermissionUserRoleGet(
|
|
UserID => $ChecksDatabase{Ticket}->{ResponsibleID},
|
|
);
|
|
|
|
my @RoleNames = sort values %RoleIDs;
|
|
|
|
$Responsible{Role} = \@RoleNames;
|
|
$ChecksDatabase{Responsible} = \%Responsible;
|
|
}
|
|
}
|
|
|
|
# within this function %Param is modified by replacements like:
|
|
# $Param{PriorityID} = $Param{NewPriorityID}
|
|
# apparently this changes are not longer needed outside this function and it is not necessary
|
|
# to return such replacements
|
|
|
|
return {
|
|
Checks => \%Checks,
|
|
ChecksDatabase => \%ChecksDatabase,
|
|
};
|
|
}
|
|
|
|
=head2 _CompareMatchWithData()
|
|
|
|
Compares a properties element with the data sent to the ACL, the compare results varies on how the
|
|
ACL properties where defined including normal, negated, regular expression and negated regular
|
|
expression comparisons.
|
|
|
|
my $Result = $TicketObject->_CompareMatchWithData(
|
|
Match => 'a value', # or '[Not]a value', or '[RegExp]val' or '[NotRegExp]val'
|
|
# or '[Notregexp]val' or '[Notregexp]'
|
|
Data => 'a value',
|
|
SingleItem => 1, # or 0, optional, default 0
|
|
);
|
|
|
|
Returns:
|
|
|
|
$Result = {
|
|
Success => 1, # or false
|
|
Match => 1, # or false
|
|
Skip => 1, # or false (in certain cases where SingleItem is set)
|
|
};
|
|
|
|
=cut
|
|
|
|
sub _CompareMatchWithData {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(Match Data)) {
|
|
if ( !defined $Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!",
|
|
);
|
|
return {
|
|
Success => 0,
|
|
};
|
|
}
|
|
}
|
|
|
|
my $Match = $Param{Match};
|
|
my $Data = $Param{Data};
|
|
|
|
# Negated matches requires a different logic.
|
|
if ( substr( $Match, 0, length '[Not' ) eq '[Not' ) {
|
|
|
|
# Not equal match
|
|
if ( substr( $Match, 0, length '[Not]' ) eq '[Not]' ) {
|
|
my $NotValue = substr $Match, length '[Not]';
|
|
if ( $NotValue eq $Data ) {
|
|
return {
|
|
Success => 1,
|
|
Match => 0,
|
|
};
|
|
}
|
|
}
|
|
|
|
# Not reg-exp match case-sensitive.
|
|
elsif ( substr( $Match, 0, length '[NotRegExp]' ) eq '[NotRegExp]' ) {
|
|
my $RegExp = substr $Match, length '[NotRegExp]';
|
|
if ( $Data =~ /$RegExp/ ) {
|
|
return {
|
|
Success => 1,
|
|
Match => 0,
|
|
};
|
|
}
|
|
}
|
|
|
|
# Not reg-exp match case-insensitive.
|
|
elsif ( substr( $Match, 0, length '[Notregexp]' ) eq '[Notregexp]' ) {
|
|
my $RegExp = substr $Match, length '[Notregexp]';
|
|
if ( $Data =~ /$RegExp/i ) {
|
|
return {
|
|
Success => 1,
|
|
Match => 0,
|
|
};
|
|
}
|
|
}
|
|
|
|
if ( $Param{SingleItem} ) {
|
|
return {
|
|
Success => 1,
|
|
Match => 1,
|
|
Skip => 0,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
Success => 1,
|
|
Match => 1,
|
|
Skip => 1,
|
|
};
|
|
}
|
|
}
|
|
else {
|
|
|
|
# Equal match.
|
|
if ( $Match eq $Data ) {
|
|
return {
|
|
Success => 1,
|
|
Match => 1,
|
|
};
|
|
}
|
|
|
|
# Reg-exp match case-sensitive.
|
|
elsif ( substr( $Match, 0, length '[RegExp]' ) eq '[RegExp]' ) {
|
|
my $RegExp = substr $Match, length '[RegExp]';
|
|
if ( $Data =~ /$RegExp/ ) {
|
|
return {
|
|
Success => 1,
|
|
Match => 1,
|
|
};
|
|
}
|
|
}
|
|
|
|
# Reg-exp match case-insensitive.
|
|
elsif ( substr( $Match, 0, length '[regexp]' ) eq '[regexp]' ) {
|
|
my $RegExp = substr $Match, length '[regexp]';
|
|
if ( $Data =~ /$RegExp/i ) {
|
|
return {
|
|
Success => 1,
|
|
Match => 1,
|
|
};
|
|
}
|
|
}
|
|
|
|
if ( $Param{SingleItem} ) {
|
|
return {
|
|
Success => 1,
|
|
Match => 0,
|
|
Skip => 0,
|
|
};
|
|
}
|
|
else {
|
|
return {
|
|
Success => 1,
|
|
Match => 0,
|
|
Skip => 1,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
1;
|
|
|
|
=end Internal:
|
|
|
|
=head1 TERMS AND CONDITIONS
|
|
|
|
This software is part of the OTRS project (L<https://otrs.org/>).
|
|
|
|
This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
the enclosed file COPYING for license information (GPL). If you
|
|
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
|
|
|
=cut
|