# -- # 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::AdminDynamicFieldMasterSlave; use strict; use warnings; our $ObjectManagerDisabled = 1; use Kernel::System::VariableCheck qw(:all); use Kernel::Language qw(Translatable); sub new { my ( $Type, %Param ) = @_; 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 'Add' ) { return $Self->_Add( %Param, ); } elsif ( $Self->{Subaction} eq 'AddAction' ) { # challenge token check for write action $LayoutObject->ChallengeTokenCheck(); return $Self->_AddAction( %Param, ); } if ( $Self->{Subaction} eq 'Change' ) { return $Self->_Change( %Param, ); } elsif ( $Self->{Subaction} eq 'ChangeAction' ) { # challenge token check for write action $LayoutObject->ChallengeTokenCheck(); return $Self->_ChangeAction( %Param, ); } return $LayoutObject->ErrorScreen( Message => Translatable('Undefined subaction.'), ); } sub _Add { my ( $Self, %Param ) = @_; my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my %GetParam; for my $Needed (qw(ObjectType FieldType FieldOrder)) { $GetParam{$Needed} = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => $Needed ); if ( !$Needed ) { return $LayoutObject->ErrorScreen( Message => $LayoutObject->{LanguageObject}->Translate( 'Need %s', $Needed ), ); } } # get the object type and field type display name my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); my $ObjectTypeName = $ConfigObject->Get('DynamicFields::ObjectType')->{ $GetParam{ObjectType} }->{DisplayName} || ''; my $FieldTypeName = $ConfigObject->Get('DynamicFields::Driver')->{ $GetParam{FieldType} }->{DisplayName} || ''; return $Self->_ShowScreen( %Param, %GetParam, Mode => 'Add', ObjectTypeName => $ObjectTypeName, FieldTypeName => $FieldTypeName, ); } sub _AddAction { my ( $Self, %Param ) = @_; my %Errors; my %GetParam; my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(Name Label FieldOrder)) { $GetParam{$Needed} = $ParamObject->GetParam( Param => $Needed ); if ( !$GetParam{$Needed} ) { $Errors{ $Needed . 'ServerError' } = 'ServerError'; $Errors{ $Needed . 'ServerErrorMessage' } = Translatable('This field is required.'); } } my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField'); if ( $GetParam{Name} ) { # check if name is alphanumeric if ( $GetParam{Name} !~ m{\A (?: [a-zA-Z] | \d )+ \z}xms ) { # add server error error class $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = Translatable('The field does not contain only ASCII letters and numbers.'); } # check if name is duplicated my %DynamicFieldsList = %{ $DynamicFieldObject->DynamicFieldList( Valid => 0, ResultType => 'HASH', ) }; %DynamicFieldsList = reverse %DynamicFieldsList; if ( $DynamicFieldsList{ $GetParam{Name} } ) { # add server error error class $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = Translatable('There is another field with the same name.'); } } if ( $GetParam{FieldOrder} ) { # check if field order is numeric and positive if ( $GetParam{FieldOrder} !~ m{\A (?: \d )+ \z}xms ) { # add server error error class $Errors{FieldOrderServerError} = 'ServerError'; $Errors{FieldOrderServerErrorMessage} = Translatable('The field must be numeric.'); } } for my $ConfigParam (qw( ObjectType ObjectTypeName FieldType FieldTypeName ValidID )) { $GetParam{$ConfigParam} = $ParamObject->GetParam( Param => $ConfigParam ); } # uncorrectable errors if ( !$GetParam{ValidID} ) { return $LayoutObject->ErrorScreen( Message => Translatable('Need ValidID'), ); } # return to add screen if errors if (%Errors) { return $Self->_ShowScreen( %Param, %Errors, %GetParam, Mode => 'Add', ); } # set specific config my $FieldConfig = { DefaultValue => '', PossibleNone => 1, TranslatableValues => 1, }; # create a new field my $FieldID = $DynamicFieldObject->DynamicFieldAdd( Name => $GetParam{Name}, Label => $GetParam{Label}, FieldOrder => $GetParam{FieldOrder}, FieldType => $GetParam{FieldType}, ObjectType => $GetParam{ObjectType}, Config => $FieldConfig, ValidID => $GetParam{ValidID}, UserID => $Self->{UserID}, ); if ( !$FieldID ) { return $LayoutObject->ErrorScreen( Message => Translatable('Could not create the new field'), ); } return $LayoutObject->Redirect( OP => "Action=AdminDynamicField", ); } sub _Change { my ( $Self, %Param ) = @_; my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my %GetParam; for my $Needed (qw(ObjectType FieldType)) { $GetParam{$Needed} = $ParamObject->GetParam( Param => $Needed ); if ( !$Needed ) { return $LayoutObject->ErrorScreen( Message => $LayoutObject->{LanguageObject}->Translate( 'Need %s', $Needed ), ); } } # get the object type and field type display name my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); my $ObjectTypeName = $ConfigObject->Get('DynamicFields::ObjectType')->{ $GetParam{ObjectType} }->{DisplayName} || ''; my $FieldTypeName = $ConfigObject->Get('DynamicFields::Driver')->{ $GetParam{FieldType} }->{DisplayName} || ''; my $FieldID = $ParamObject->GetParam( Param => 'ID' ); if ( !$FieldID ) { return $LayoutObject->ErrorScreen( Message => Translatable('Need ID'), ); } # get dynamic field data my $DynamicFieldData = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldGet( ID => $FieldID, ); # check for valid dynamic field configuration if ( !IsHashRefWithData($DynamicFieldData) ) { return $LayoutObject->ErrorScreen( Message => $LayoutObject->{LanguageObject}->Translate( 'Could not get data for dynamic field %s', $FieldID ), ); } return $Self->_ShowScreen( %Param, %GetParam, %${DynamicFieldData}, ID => $FieldID, Mode => 'Change', ObjectTypeName => $ObjectTypeName, FieldTypeName => $FieldTypeName, ); } sub _ChangeAction { my ( $Self, %Param ) = @_; my %Errors; my %GetParam; my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); for my $Needed (qw(Name Label FieldOrder)) { $GetParam{$Needed} = $ParamObject->GetParam( Param => $Needed ); if ( !$GetParam{$Needed} ) { $Errors{ $Needed . 'ServerError' } = 'ServerError'; $Errors{ $Needed . 'ServerErrorMessage' } = Translatable('This field is required.'); } } my $FieldID = $ParamObject->GetParam( Param => 'ID' ); if ( !$FieldID ) { return $LayoutObject->ErrorScreen( Message => Translatable('Need ID'), ); } my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField'); # get dynamic field data my $DynamicFieldData = $DynamicFieldObject->DynamicFieldGet( ID => $FieldID, ); # check for valid dynamic field configuration if ( !IsHashRefWithData($DynamicFieldData) ) { return $LayoutObject->ErrorScreen( Message => $LayoutObject->{LanguageObject}->Translate( 'Could not get data for dynamic field %s', $FieldID ), ); } if ( $GetParam{Name} ) { # check if name is lowercase if ( $GetParam{Name} !~ m{\A (?: [a-zA-Z] | \d )+ \z}xms ) { # add server error error class $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = Translatable('The field does not contain only ASCII letters and numbers.'); } # check if name is duplicated my %DynamicFieldsList = %{ $DynamicFieldObject->DynamicFieldList( Valid => 0, ResultType => 'HASH', ) }; %DynamicFieldsList = reverse %DynamicFieldsList; if ( $DynamicFieldsList{ $GetParam{Name} } && $DynamicFieldsList{ $GetParam{Name} } ne $FieldID ) { # add server error class $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = Translatable('There is another field with the same name.'); } # if it's an internal field, it's name should not change if ( $DynamicFieldData->{InternalField} && $DynamicFieldsList{ $GetParam{Name} } ne $FieldID ) { # add server error class $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = Translatable('The name for this field should not change.'); $Param{InternalField} = $DynamicFieldData->{InternalField}; } } if ( $GetParam{FieldOrder} ) { # check if field order is numeric and positive if ( $GetParam{FieldOrder} !~ m{\A (?: \d )+ \z}xms ) { # add server error error class $Errors{FieldOrderServerError} = 'ServerError'; $Errors{FieldOrderServerErrorMessage} = Translatable('The field must be numeric.'); } } for my $ConfigParam (qw( ObjectType ObjectTypeName FieldType FieldTypeName ValidID )) { $GetParam{$ConfigParam} = $ParamObject->GetParam( Param => $ConfigParam ); } # uncorrectable errors if ( !$GetParam{ValidID} ) { return $LayoutObject->ErrorScreen( Message => Translatable('Need ValidID'), ); } # return to change screen if errors if (%Errors) { return $Self->_ShowScreen( %Param, %Errors, %GetParam, ID => $FieldID, Mode => 'Change', ); } # set specific config my $FieldConfig = { DefaultValue => '', PossibleNone => 1, TranslatableValues => 1, }; # update dynamic field (FieldType and ObjectType cannot be changed; use old values) my $UpdateSuccess = $DynamicFieldObject->DynamicFieldUpdate( ID => $FieldID, Name => $GetParam{Name}, Label => $GetParam{Label}, FieldOrder => $GetParam{FieldOrder}, FieldType => $DynamicFieldData->{FieldType}, ObjectType => $DynamicFieldData->{ObjectType}, Config => $FieldConfig, ValidID => $GetParam{ValidID}, UserID => $Self->{UserID}, ); if ( !$UpdateSuccess ) { return $LayoutObject->ErrorScreen( Message => $LayoutObject->{LanguageObject}->Translate( 'Could not update the field %s', $GetParam{Name} ), ); } return $LayoutObject->Redirect( OP => "Action=AdminDynamicField", ); } sub _ShowScreen { my ( $Self, %Param ) = @_; $Param{DisplayFieldName} = 'New'; if ( $Param{Mode} eq 'Change' ) { $Param{ShowWarning} = 'ShowWarning'; $Param{DisplayFieldName} = $Param{Name}; } my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); # header my $Output = $LayoutObject->Header(); $Output .= $LayoutObject->NavigationBar(); # get all fields my $DynamicFieldList = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet( Valid => 0, ); # get the list of order numbers (is already sorted). my @DynamicfieldOrderList; my %DynamicfieldNamesList; for my $Dynamicfield ( @{$DynamicFieldList} ) { push @DynamicfieldOrderList, $Dynamicfield->{FieldOrder}; $DynamicfieldNamesList{ $Dynamicfield->{FieldOrder} } = $Dynamicfield->{Label}; } # when adding we need to create an extra order number for the new field if ( $Param{Mode} eq 'Add' ) { # get the last element form the order list and add 1 my $LastOrderNumber = $DynamicfieldOrderList[-1]; $LastOrderNumber++; # add this new order number to the end of the list push @DynamicfieldOrderList, $LastOrderNumber; } # show the names of the other fields to ease ordering my %OrderNamesList; my $CurrentlyText = $LayoutObject->{LanguageObject}->Translate('Currently') . ': '; for my $OrderNumber ( sort @DynamicfieldOrderList ) { $OrderNamesList{$OrderNumber} = $OrderNumber; if ( $DynamicfieldNamesList{$OrderNumber} && $OrderNumber ne $Param{FieldOrder} ) { $OrderNamesList{$OrderNumber} = $OrderNumber . ' - ' . $CurrentlyText . $DynamicfieldNamesList{$OrderNumber}; } } my $DynamicFieldOrderStrg = $LayoutObject->BuildSelection( Data => \%OrderNamesList, Name => 'FieldOrder', SelectedValue => $Param{FieldOrder} || 1, PossibleNone => 0, Translation => 0, Sort => 'NumericKey', Class => 'W75pc Validate_Number Modernize', ); my %ValidList = $Kernel::OM->Get('Kernel::System::Valid')->ValidList(); # create the Validity select my $ValidityStrg = $LayoutObject->BuildSelection( Data => \%ValidList, Name => 'ValidID', SelectedID => $Param{ValidID} || 1, PossibleNone => 0, Translation => 1, Class => 'W50pc Modernize', ); # create the possible values template $LayoutObject->Block( Name => 'ValueTemplate', Data => { %Param, }, ); my $ReadonlyInternalField = ''; # Internal fields can not be deleted and name should not change. if ( $Param{InternalField} ) { $LayoutObject->Block( Name => 'InternalField', Data => {%Param}, ); $ReadonlyInternalField = 'readonly="readonly"'; } # generate output $Output .= $LayoutObject->Output( TemplateFile => 'AdminDynamicFieldMasterSlave', Data => { %Param, ValidityStrg => $ValidityStrg, DynamicFieldOrderStrg => $DynamicFieldOrderStrg, ReadonlyInternalField => $ReadonlyInternalField, }, ); $Output .= $LayoutObject->Footer(); return $Output; } 1;