830 lines
27 KiB
Perl
830 lines
27 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::Modules::AgentLinkObject;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Kernel::Language qw(Translatable);
|
|
|
|
our $ObjectManagerDisabled = 1;
|
|
|
|
sub new {
|
|
my ( $Type, %Param ) = @_;
|
|
|
|
# allocate new hash for object
|
|
my $Self = {%Param};
|
|
bless( $Self, $Type );
|
|
|
|
return $Self;
|
|
}
|
|
|
|
sub Run {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
|
|
|
|
if ( $Self->{Subaction} eq 'UpdateComplextTablePreferences' ) {
|
|
|
|
# save user preferences (shown columns)
|
|
|
|
# Needed objects
|
|
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
|
|
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
|
my $JSONObject = $Kernel::OM->Get('Kernel::System::JSON');
|
|
|
|
# challenge token check for write action
|
|
$LayoutObject->ChallengeTokenCheck();
|
|
|
|
my $SourceObject = $ParamObject->GetParam( Param => 'SourceObject' ) || '';
|
|
my $SourceObjectID = $ParamObject->GetParam( Param => 'SourceObjectID' ) || '';
|
|
my $DestinationObject = $ParamObject->GetParam( Param => 'DestinationObject' ) || '';
|
|
my $AdditionalLinkListWithDataJSON = $ParamObject->GetParam( Param => 'AdditionalLinkListWithDataJSON' ) || '';
|
|
|
|
my $Success = $LayoutObject->ComplexTablePreferencesSet(
|
|
DestinationObject => $DestinationObject,
|
|
);
|
|
|
|
if ( !$Success ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "System was unable to update preferences!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# get linked objects
|
|
my $LinkListWithData = $Kernel::OM->Get('Kernel::System::LinkObject')->LinkListWithData(
|
|
Object => $SourceObject,
|
|
Object2 => $DestinationObject,
|
|
Key => $SourceObjectID,
|
|
State => 'Valid',
|
|
UserID => $Self->{UserID},
|
|
ObjectParameters => {
|
|
Ticket => {
|
|
IgnoreLinkedTicketStateTypes => 1,
|
|
},
|
|
},
|
|
);
|
|
|
|
if ($AdditionalLinkListWithDataJSON) {
|
|
|
|
# decode JSON string
|
|
my $AdditionalLinkListWithData = $Kernel::OM->Get('Kernel::System::JSON')->Decode(
|
|
Data => $AdditionalLinkListWithDataJSON,
|
|
);
|
|
|
|
$LinkListWithData = {
|
|
%{$LinkListWithData},
|
|
%{$AdditionalLinkListWithData},
|
|
};
|
|
}
|
|
|
|
# create the link table
|
|
my $LinkTableStrg = $LayoutObject->LinkObjectTableCreate(
|
|
LinkListWithData => $LinkListWithData,
|
|
ViewMode => 'Complex', # only make sense for complex
|
|
Object => $SourceObject,
|
|
Key => $SourceObjectID,
|
|
AJAX => 1,
|
|
AdditionalLinkListWithDataJSON => $AdditionalLinkListWithDataJSON,
|
|
);
|
|
|
|
return $LayoutObject->Attachment(
|
|
ContentType => 'text/html',
|
|
Content => $LinkTableStrg,
|
|
Type => 'inline',
|
|
NoCache => 1,
|
|
);
|
|
}
|
|
|
|
# ------------------------------------------------------------ #
|
|
# close
|
|
# ------------------------------------------------------------ #
|
|
if ( $Self->{Subaction} eq 'Close' ) {
|
|
return $LayoutObject->PopupClose(
|
|
Reload => 1,
|
|
);
|
|
}
|
|
|
|
# get params
|
|
my %Form;
|
|
my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
|
|
$Form{SourceObject} = $ParamObject->GetParam( Param => 'SourceObject' );
|
|
$Form{SourceKey} = $ParamObject->GetParam( Param => 'SourceKey' );
|
|
$Form{Mode} = $ParamObject->GetParam( Param => 'Mode' ) || 'Normal';
|
|
|
|
# check needed stuff
|
|
if ( !$Form{SourceObject} || !$Form{SourceKey} ) {
|
|
return $LayoutObject->ErrorScreen(
|
|
Message => Translatable('Need SourceObject and SourceKey!'),
|
|
Comment => Translatable('Please contact the administrator.'),
|
|
);
|
|
}
|
|
|
|
my $LinkObject = $Kernel::OM->Get('Kernel::System::LinkObject');
|
|
|
|
# check if this is a temporary ticket link used while creating a new ticket
|
|
my $TemporarySourceTicketLink;
|
|
if (
|
|
$Form{Mode} eq 'Temporary'
|
|
&& $Form{SourceObject} eq 'Ticket'
|
|
&& $Form{SourceKey} =~ m{ \A \d+ \. \d+ }xms
|
|
)
|
|
{
|
|
$TemporarySourceTicketLink = 1;
|
|
}
|
|
|
|
# do the permission check only if it is no temporary ticket link used while creating a new ticket
|
|
if ( !$TemporarySourceTicketLink ) {
|
|
|
|
# permission check
|
|
my $Permission = $LinkObject->ObjectPermission(
|
|
Object => $Form{SourceObject},
|
|
Key => $Form{SourceKey},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
if ( !$Permission ) {
|
|
return $LayoutObject->NoPermission(
|
|
Message => Translatable('You need ro permission!'),
|
|
WithHeader => 'yes',
|
|
);
|
|
}
|
|
}
|
|
|
|
# get form params
|
|
$Form{TargetIdentifier} = $ParamObject->GetParam( Param => 'TargetIdentifier' )
|
|
|| $Form{SourceObject};
|
|
|
|
# investigate the target object
|
|
if ( $Form{TargetIdentifier} =~ m{ \A ( .+? ) :: ( .+ ) \z }xms ) {
|
|
$Form{TargetObject} = $1;
|
|
$Form{TargetSubObject} = $2;
|
|
}
|
|
else {
|
|
$Form{TargetObject} = $Form{TargetIdentifier};
|
|
}
|
|
|
|
# get possible objects list
|
|
my %PossibleObjectsList = $LinkObject->PossibleObjectsList(
|
|
Object => $Form{SourceObject},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# check if target object is a possible object to link with the source object
|
|
if ( !$PossibleObjectsList{ $Form{TargetObject} } ) {
|
|
my @PossibleObjects = sort { lc $a cmp lc $b } keys %PossibleObjectsList;
|
|
$Form{TargetObject} = $PossibleObjects[0];
|
|
}
|
|
|
|
# set mode params
|
|
if ( $Form{Mode} eq 'Temporary' ) {
|
|
$Form{State} = 'Temporary';
|
|
}
|
|
else {
|
|
$Form{Mode} = 'Normal';
|
|
$Form{State} = 'Valid';
|
|
}
|
|
|
|
# get source object description
|
|
my %SourceObjectDescription = $LinkObject->ObjectDescriptionGet(
|
|
Object => $Form{SourceObject},
|
|
Key => $Form{SourceKey},
|
|
Mode => $Form{Mode},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# output header
|
|
my $Output = $LayoutObject->Header( Type => 'Small' );
|
|
my $ActiveTab;
|
|
|
|
# ------------------------------------------------------------ #
|
|
# link delete
|
|
# ------------------------------------------------------------ #
|
|
if ( $Self->{Subaction} eq 'LinkDelete' && $ParamObject->GetParam( Param => 'SubmitDelete' ) ) {
|
|
|
|
# challenge token check for write action
|
|
$LayoutObject->ChallengeTokenCheck();
|
|
|
|
# delete all temporary links older than one day
|
|
$LinkObject->LinkCleanup(
|
|
State => 'Temporary',
|
|
Age => ( 60 * 60 * 24 ),
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# get the link delete keys and target object
|
|
my @LinkDeleteIdentifier = $ParamObject->GetArray(
|
|
Param => 'LinkDeleteIdentifier',
|
|
);
|
|
|
|
my $SuccessCounter = 0;
|
|
|
|
# delete links from database
|
|
IDENTIFIER:
|
|
for my $Identifier (@LinkDeleteIdentifier) {
|
|
|
|
my @Target = $Identifier =~ m{^ ( [^:]+? ) :: (.+?) :: ( [^:]+? ) $}smx;
|
|
|
|
next IDENTIFIER if !$Target[0]; # TargetObject
|
|
next IDENTIFIER if !$Target[1]; # TargetKey
|
|
next IDENTIFIER if !$Target[2]; # LinkType
|
|
|
|
my $DeletePermission = $LinkObject->ObjectPermission(
|
|
Object => $Target[0],
|
|
Key => $Target[1],
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
next IDENTIFIER if !$DeletePermission;
|
|
|
|
# delete link from database
|
|
my $Success = $LinkObject->LinkDelete(
|
|
Object1 => $Form{SourceObject},
|
|
Key1 => $Form{SourceKey},
|
|
Object2 => $Target[0],
|
|
Key2 => $Target[1],
|
|
Type => $Target[2],
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
if ($Success) {
|
|
$SuccessCounter++;
|
|
next IDENTIFIER;
|
|
}
|
|
|
|
# get target object description
|
|
my %TargetObjectDescription = $LinkObject->ObjectDescriptionGet(
|
|
Object => $Target[0],
|
|
Key => $Target[1],
|
|
Mode => $Form{Mode},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# output an error notification
|
|
$Output .= $LayoutObject->Notify(
|
|
Priority => 'Error',
|
|
Data => $LayoutObject->{LanguageObject}->Translate(
|
|
"Can not delete link with %s!",
|
|
$TargetObjectDescription{Normal},
|
|
),
|
|
);
|
|
}
|
|
|
|
if ($SuccessCounter) {
|
|
$Output .= $LayoutObject->Notify(
|
|
Priority => 'Info',
|
|
Data =>
|
|
$LayoutObject->{LanguageObject}->Translate( "%s Link(s) deleted successfully.", $SuccessCounter ),
|
|
);
|
|
}
|
|
|
|
$ActiveTab = 'ManageLinks';
|
|
}
|
|
|
|
# ------------------------------------------------------------ #
|
|
# instant link delete (from the link table)
|
|
# ------------------------------------------------------------ #
|
|
elsif ( $Self->{Subaction} eq 'InstantLinkDelete' ) {
|
|
|
|
# challenge token check for write action
|
|
$LayoutObject->ChallengeTokenCheck();
|
|
|
|
# get target identifier and redirect URL
|
|
my $TargetIdentifier = $ParamObject->GetParam( Param => 'TargetIdentifier' );
|
|
my $Redirect = $ParamObject->GetParam( Param => 'Redirect' );
|
|
|
|
# get target components
|
|
my @Target = $TargetIdentifier =~ m{^ ( [^:]+? ) :: (.+?) :: ( [^:]+? ) $}smx;
|
|
|
|
if (
|
|
$Target[0] # TargetObject
|
|
&& $Target[1] # TargetKey
|
|
&& $Target[2] # LinkType
|
|
)
|
|
{
|
|
|
|
# check source permission
|
|
my $SourcePermission = $LinkObject->ObjectPermission(
|
|
Object => $Form{SourceObject},
|
|
Key => $Form{SourceKey},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# check target permission
|
|
my $TargetPermission = $LinkObject->ObjectPermission(
|
|
Object => $Target[0],
|
|
Key => $Target[1],
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
if ( !$SourcePermission || !$TargetPermission ) {
|
|
return $LayoutObject->NoPermission(
|
|
Message => Translatable('You need ro permission!'),
|
|
WithHeader => 'yes',
|
|
);
|
|
}
|
|
|
|
# delete link from database
|
|
my $Success = $LinkObject->LinkDelete(
|
|
Object1 => $Form{SourceObject},
|
|
Key1 => $Form{SourceKey},
|
|
Object2 => $Target[0],
|
|
Key2 => $Target[1],
|
|
Type => $Target[2],
|
|
UserID => $Self->{UserID},
|
|
);
|
|
}
|
|
|
|
# build empty JSON output
|
|
my $JSON = $LayoutObject->JSONEncode(
|
|
Data => {
|
|
Success => 1,
|
|
},
|
|
);
|
|
|
|
# send JSON response
|
|
return $LayoutObject->Attachment(
|
|
ContentType => 'application/json; charset=' . $LayoutObject->{Charset},
|
|
Content => $JSON,
|
|
Type => 'inline',
|
|
NoCache => 1,
|
|
);
|
|
}
|
|
|
|
# ------------------------------------------------------------ #
|
|
# overview
|
|
# ------------------------------------------------------------ #
|
|
|
|
# get the type
|
|
my $TypeIdentifier = $ParamObject->GetParam( Param => 'TypeIdentifier' );
|
|
|
|
# add new links
|
|
if ( $ParamObject->GetParam( Param => 'SubmitLink' ) ) {
|
|
|
|
# challenge token check for write action
|
|
$LayoutObject->ChallengeTokenCheck();
|
|
|
|
# get the link target keys
|
|
my @LinkTargetKeys = $ParamObject->GetArray( Param => 'LinkTargetKeys' );
|
|
|
|
# get all links that the source object already has
|
|
my $LinkList = $LinkObject->LinkList(
|
|
Object => $Form{SourceObject},
|
|
Key => $Form{SourceKey},
|
|
State => $Form{State},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# split the identifier
|
|
my @Type = split q{::}, $TypeIdentifier;
|
|
|
|
if ( $Type[0] && $Type[1] && ( $Type[1] eq 'Source' || $Type[1] eq 'Target' ) ) {
|
|
|
|
my $SuccessCounter = 0;
|
|
|
|
# add links
|
|
TARGETKEYORG:
|
|
for my $TargetKeyOrg (@LinkTargetKeys) {
|
|
|
|
TYPE:
|
|
for my $LType ( sort keys %{ $LinkList->{ $Form{TargetObject} } } ) {
|
|
|
|
# extract source and target
|
|
my $Source = $LinkList->{ $Form{TargetObject} }->{$LType}->{Source} ||= {};
|
|
my $Target = $LinkList->{ $Form{TargetObject} }->{$LType}->{Target} ||= {};
|
|
|
|
# check if source and target object are already linked
|
|
next TYPE
|
|
if !$Source->{$TargetKeyOrg} && !$Target->{$TargetKeyOrg};
|
|
|
|
# next type, if link already exists
|
|
if ( $LType eq $Type[0] ) {
|
|
next TYPE if $Type[1] eq 'Source' && $Source->{$TargetKeyOrg};
|
|
next TYPE if $Type[1] eq 'Target' && $Target->{$TargetKeyOrg};
|
|
}
|
|
|
|
# check the type groups
|
|
my $TypeGroupCheck = $LinkObject->PossibleType(
|
|
Type1 => $Type[0],
|
|
Type2 => $LType,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
next TYPE if $TypeGroupCheck && $Type[0] ne $LType;
|
|
|
|
# get target object description
|
|
my %TargetObjectDescription = $LinkObject->ObjectDescriptionGet(
|
|
Object => $Form{TargetObject},
|
|
Key => $TargetKeyOrg,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# lookup type id
|
|
my $TypeID = $LinkObject->TypeLookup(
|
|
Name => $LType,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# get type data
|
|
my %TypeData = $LinkObject->TypeGet(
|
|
TypeID => $TypeID,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# investigate type name
|
|
my $TypeName = $TypeData{SourceName};
|
|
if ( $Target->{$TargetKeyOrg} ) {
|
|
$TypeName = $TypeData{TargetName};
|
|
}
|
|
|
|
# translate the type name
|
|
$TypeName = $LayoutObject->{LanguageObject}->Translate($TypeName);
|
|
|
|
# output an error notification
|
|
$Output .= $LayoutObject->Notify(
|
|
Priority => 'Error',
|
|
Data => $LayoutObject->{LanguageObject}->Translate(
|
|
'Can not create link with %s! Object already linked as %s.',
|
|
$TargetObjectDescription{Normal},
|
|
$TypeName,
|
|
),
|
|
);
|
|
|
|
next TARGETKEYORG;
|
|
}
|
|
|
|
my $SourceObject = $Form{TargetObject};
|
|
my $SourceKey = $TargetKeyOrg;
|
|
my $TargetObject = $Form{SourceObject};
|
|
my $TargetKey = $Form{SourceKey};
|
|
|
|
if ( $Type[1] eq 'Target' ) {
|
|
$SourceObject = $Form{SourceObject};
|
|
$SourceKey = $Form{SourceKey};
|
|
$TargetObject = $Form{TargetObject};
|
|
$TargetKey = $TargetKeyOrg;
|
|
}
|
|
|
|
# check if this is a temporary ticket link used while creating a new ticket
|
|
my $TemporaryTargetTicketLink;
|
|
if (
|
|
$Form{Mode} eq 'Temporary'
|
|
&& $TargetObject eq 'Ticket'
|
|
&& $TargetKey =~ m{ \A \d+ \. \d+ }xms
|
|
)
|
|
{
|
|
$TemporaryTargetTicketLink = 1;
|
|
}
|
|
|
|
# do the permission check only if it is no temporary ticket link
|
|
# used while creating a new ticket
|
|
if ( !$TemporaryTargetTicketLink ) {
|
|
|
|
my $AddPermission = $LinkObject->ObjectPermission(
|
|
Object => $TargetObject,
|
|
Key => $TargetKey,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
next TARGETKEYORG if !$AddPermission;
|
|
}
|
|
|
|
# add links to database
|
|
my $Success = $LinkObject->LinkAdd(
|
|
SourceObject => $SourceObject,
|
|
SourceKey => $SourceKey,
|
|
TargetObject => $TargetObject,
|
|
TargetKey => $TargetKey,
|
|
Type => $Type[0],
|
|
State => $Form{State},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
if ($Success) {
|
|
$SuccessCounter++;
|
|
next TARGETKEYORG;
|
|
}
|
|
|
|
# get target object description
|
|
my %TargetObjectDescription = $LinkObject->ObjectDescriptionGet(
|
|
Object => $Form{TargetObject},
|
|
Key => $TargetKeyOrg,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# output an error notification
|
|
$Output .= $LayoutObject->Notify(
|
|
Priority => 'Error',
|
|
Data => $LayoutObject->{LanguageObject}->Translate(
|
|
"Can not create link with %s!",
|
|
$TargetObjectDescription{Normal}
|
|
),
|
|
);
|
|
}
|
|
|
|
if ($SuccessCounter) {
|
|
$Output .= $LayoutObject->Notify(
|
|
Priority => 'Info',
|
|
Data => $LayoutObject->{LanguageObject}->Translate(
|
|
"%s links added successfully.",
|
|
$SuccessCounter,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
# get the selectable object list
|
|
my $TargetObjectStrg = $LayoutObject->LinkObjectSelectableObjectList(
|
|
Object => $Form{SourceObject},
|
|
Selected => $Form{TargetIdentifier},
|
|
);
|
|
|
|
# check needed stuff
|
|
if ( !$TargetObjectStrg ) {
|
|
return $LayoutObject->ErrorScreen(
|
|
Message => $LayoutObject->{LanguageObject}
|
|
->Translate( 'The object %s cannot link with other object!', $Form{SourceObject} ),
|
|
Comment => Translatable('Please contact the administrator.'),
|
|
);
|
|
}
|
|
|
|
# output link block
|
|
$LayoutObject->Block(
|
|
Name => 'Link',
|
|
Data => {
|
|
%Form,
|
|
SourceObjectNormal => $SourceObjectDescription{Normal},
|
|
SourceObjectLong => $SourceObjectDescription{Long},
|
|
TargetObjectStrg => $TargetObjectStrg,
|
|
},
|
|
);
|
|
|
|
# output special block for temporary links
|
|
# to close the popup without reloading the parent window
|
|
if ( $Form{Mode} eq 'Temporary' ) {
|
|
|
|
$LayoutObject->AddJSData(
|
|
Key => 'TemporaryLink',
|
|
Value => 1,
|
|
);
|
|
}
|
|
|
|
# get search option list
|
|
my @SearchOptionList = $LayoutObject->LinkObjectSearchOptionList(
|
|
Object => $Form{TargetObject},
|
|
SubObject => $Form{TargetSubObject},
|
|
);
|
|
|
|
# output search option fields
|
|
for my $Option (@SearchOptionList) {
|
|
|
|
# output link search row block
|
|
$LayoutObject->Block(
|
|
Name => 'LinkSearchRow',
|
|
Data => $Option,
|
|
);
|
|
}
|
|
|
|
# create the search param hash
|
|
my %SearchParam;
|
|
OPTION:
|
|
for my $Option (@SearchOptionList) {
|
|
|
|
next OPTION if !$Option->{FormData};
|
|
next OPTION if $Option->{FormData}
|
|
&& ref $Option->{FormData} eq 'ARRAY' && !@{ $Option->{FormData} };
|
|
|
|
$SearchParam{ $Option->{Key} } = $Option->{FormData};
|
|
}
|
|
|
|
# start search
|
|
my $SearchList;
|
|
if (
|
|
%SearchParam
|
|
|| $Kernel::OM->Get('Kernel::Config')->Get('Frontend::AgentLinkObject::WildcardSearch')
|
|
)
|
|
{
|
|
|
|
$SearchList = $LinkObject->ObjectSearch(
|
|
Object => $Form{TargetObject},
|
|
SubObject => $Form{TargetSubObject},
|
|
SearchParams => \%SearchParam,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
}
|
|
|
|
# remove the source object from the search list
|
|
if ( $SearchList && $SearchList->{ $Form{SourceObject} } ) {
|
|
|
|
for my $LinkType ( sort keys %{ $SearchList->{ $Form{SourceObject} } } ) {
|
|
|
|
# extract link type List
|
|
my $LinkTypeList = $SearchList->{ $Form{SourceObject} }->{$LinkType};
|
|
|
|
for my $Direction ( sort keys %{$LinkTypeList} ) {
|
|
|
|
# remove the source key
|
|
delete $LinkTypeList->{$Direction}->{ $Form{SourceKey} };
|
|
}
|
|
}
|
|
}
|
|
|
|
# get already linked objects
|
|
my $LinkListWithData = $LinkObject->LinkListWithData(
|
|
Object => $Form{SourceObject},
|
|
Key => $Form{SourceKey},
|
|
State => $Form{State},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
if ( $LinkListWithData && $LinkListWithData->{ $Form{TargetObject} } ) {
|
|
|
|
# build object id lookup hash from search list
|
|
my %SearchListObjectKeys;
|
|
for my $Key (
|
|
sort keys %{ $SearchList->{ $Form{TargetObject} }->{NOTLINKED}->{Source} }
|
|
)
|
|
{
|
|
$SearchListObjectKeys{$Key} = 1;
|
|
}
|
|
|
|
# check if linked objects are part of the search list
|
|
for my $LinkType ( sort keys %{ $LinkListWithData->{ $Form{TargetObject} } } ) {
|
|
|
|
# extract link type List
|
|
my $LinkTypeList = $LinkListWithData->{ $Form{TargetObject} }->{$LinkType};
|
|
|
|
for my $Direction ( sort keys %{$LinkTypeList} ) {
|
|
|
|
# extract the keys
|
|
KEY:
|
|
for my $Key ( sort keys %{ $LinkTypeList->{$Direction} } ) {
|
|
|
|
next KEY if $SearchListObjectKeys{$Key};
|
|
|
|
# delete from linked objects list if key is not in search list
|
|
delete $LinkTypeList->{$Direction}->{$Key};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# add search result to link list
|
|
if ( $SearchList && $SearchList->{ $Form{TargetObject} } ) {
|
|
$LinkListWithData->{ $Form{TargetObject} }->{NOTLINKED} = $SearchList->{ $Form{TargetObject} }->{NOTLINKED};
|
|
}
|
|
|
|
# get possible types list
|
|
my %PossibleTypesList = $LinkObject->PossibleTypesList(
|
|
Object1 => $Form{SourceObject},
|
|
Object2 => $Form{TargetObject},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# define blank line entry
|
|
my %BlankLine = (
|
|
Key => '-',
|
|
Value => '-------------------------',
|
|
Disabled => 1,
|
|
);
|
|
|
|
# create the selectable type list
|
|
my $Counter = 0;
|
|
my @SelectableTypesList;
|
|
POSSIBLETYPE:
|
|
for my $PossibleType ( sort { lc $a cmp lc $b } keys %PossibleTypesList ) {
|
|
|
|
# lookup type id
|
|
my $TypeID = $LinkObject->TypeLookup(
|
|
Name => $PossibleType,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# get type
|
|
my %Type = $LinkObject->TypeGet(
|
|
TypeID => $TypeID,
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# create the source name
|
|
my %SourceName;
|
|
$SourceName{Key} = $PossibleType . '::Source';
|
|
$SourceName{Value} = $Type{SourceName};
|
|
|
|
push @SelectableTypesList, \%SourceName;
|
|
|
|
next POSSIBLETYPE if !$Type{Pointed};
|
|
|
|
# create the target name
|
|
my %TargetName;
|
|
$TargetName{Key} = $PossibleType . '::Target';
|
|
$TargetName{Value} = $Type{TargetName};
|
|
|
|
push @SelectableTypesList, \%TargetName;
|
|
}
|
|
continue {
|
|
|
|
# add blank line
|
|
push @SelectableTypesList, \%BlankLine;
|
|
|
|
$Counter++;
|
|
}
|
|
|
|
# removed last (empty) entry
|
|
pop @SelectableTypesList;
|
|
|
|
# add blank lines on top and bottom of the list if more then two linktypes
|
|
if ( $Counter > 2 ) {
|
|
unshift @SelectableTypesList, \%BlankLine;
|
|
push @SelectableTypesList, \%BlankLine;
|
|
}
|
|
|
|
# create link type string
|
|
my $LinkTypeStrg = $LayoutObject->BuildSelection(
|
|
Data => \@SelectableTypesList,
|
|
Name => 'TypeIdentifier',
|
|
SelectedID => $TypeIdentifier || 'Normal::Source',
|
|
Class => 'Modernize',
|
|
);
|
|
|
|
# create the link table
|
|
my $LinkTableStrg = $LayoutObject->LinkObjectTableCreateComplex(
|
|
LinkListWithData => {
|
|
$Form{TargetObject} => $LinkListWithData->{ $Form{TargetObject} },
|
|
},
|
|
ViewMode => 'ComplexAdd',
|
|
LinkTypeStrg => $LinkTypeStrg,
|
|
);
|
|
|
|
# output the link table
|
|
$LayoutObject->Block(
|
|
Name => 'LinkTableComplex',
|
|
Data => {
|
|
LinkTableStrg => $LinkTableStrg,
|
|
},
|
|
);
|
|
|
|
# get already linked objects
|
|
$LinkListWithData = $LinkObject->LinkListWithData(
|
|
Object => $Form{SourceObject},
|
|
Key => $Form{SourceKey},
|
|
State => $Form{State},
|
|
UserID => $Self->{UserID},
|
|
);
|
|
|
|
# create the link table
|
|
$LinkTableStrg = $LayoutObject->LinkObjectTableCreateComplex(
|
|
LinkListWithData => $LinkListWithData,
|
|
ViewMode => 'ComplexDelete',
|
|
);
|
|
|
|
my $ManageTabDisabled = 0;
|
|
if ( !$LinkTableStrg ) {
|
|
$ManageTabDisabled = 1;
|
|
}
|
|
|
|
# output link delete block
|
|
$LayoutObject->Block(
|
|
Name => 'Delete',
|
|
Data => {
|
|
%Form,
|
|
SourceObjectNormal => $SourceObjectDescription{Normal},
|
|
},
|
|
);
|
|
|
|
# output the link table
|
|
$LayoutObject->Block(
|
|
Name => 'DeleteTableComplex',
|
|
Data => {
|
|
LinkTableStrg => $LinkTableStrg,
|
|
},
|
|
);
|
|
|
|
# start template output
|
|
$Output .= $LayoutObject->Output(
|
|
TemplateFile => 'AgentLinkObject',
|
|
Data => {
|
|
SourceObjectNormal => $SourceObjectDescription{Normal},
|
|
SourceObjectLong => $SourceObjectDescription{Long},
|
|
TargetObjectStrg => $TargetObjectStrg,
|
|
ActiveTab => $ActiveTab,
|
|
ManageTabDisabled => $ManageTabDisabled,
|
|
}
|
|
);
|
|
|
|
$Output .= $LayoutObject->Footer( Type => 'Small' );
|
|
|
|
return $Output;
|
|
}
|
|
|
|
1;
|