# -- # 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::AdminDynamicFieldCheckbox; 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 ) = @_; # Store last entity screen. $Kernel::OM->Get('Kernel::System::AuthSession')->UpdateSessionID( SessionID => $Self->{SessionID}, Key => 'LastScreenEntity', Value => $Self->{RequestedURL}, ); 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 ( !$GetParam{$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', BreadcrumbText => $LayoutObject->{LanguageObject} ->Translate( 'Add %s field', $LayoutObject->{LanguageObject}->Translate($FieldTypeName) ), ObjectTypeName => $ObjectTypeName, FieldTypeName => $FieldTypeName, ); } sub _AddAction { my ( $Self, %Param ) = @_; my %Errors; my %GetParam; my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); 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.'); } } 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 = %{ $Kernel::OM->Get('Kernel::System::DynamicField')->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 DefaultValue ValidID)) { $GetParam{$ConfigParam} = $ParamObject->GetParam( Param => $ConfigParam ); } my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); # 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 => $GetParam{DefaultValue}, }; # create a new field my $FieldID = $Kernel::OM->Get('Kernel::System::DynamicField')->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 $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my %GetParam; for my $Needed (qw(ObjectType FieldType)) { $GetParam{$Needed} = $Kernel::OM->Get('Kernel::System::Web::Request')->GetParam( Param => $Needed ); if ( !$GetParam{$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 = $Kernel::OM->Get('Kernel::System::Web::Request')->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 ), ); } my %Config = (); # extract configuration if ( IsHashRefWithData( $DynamicFieldData->{Config} ) ) { %Config = %{ $DynamicFieldData->{Config} }; } return $Self->_ShowScreen( %Param, %GetParam, %${DynamicFieldData}, %Config, ID => $FieldID, Mode => 'Change', BreadcrumbText => $LayoutObject->{LanguageObject} ->Translate( 'Change %s field', $LayoutObject->{LanguageObject}->Translate($FieldTypeName) ), ObjectTypeName => $ObjectTypeName, FieldTypeName => $FieldTypeName, ); } sub _ChangeAction { my ( $Self, %Param ) = @_; my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my %Errors; my %GetParam; 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 $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); my $FieldID = $ParamObject->GetParam( Param => 'ID' ); if ( !$FieldID ) { return $LayoutObject->ErrorScreen( Message => Translatable('Need ID'), ); } my $DynamicField = $Kernel::OM->Get('Kernel::System::DynamicField'); # get dynamic field data my $DynamicFieldData = $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 ), ); } 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 = %{ $DynamicField->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 DefaultValue ValidID)) { $GetParam{$ConfigParam} = $ParamObject->GetParam( Param => $ConfigParam ); } # uncorrectable errors if ( !$GetParam{ValidID} ) { return $LayoutObject->ErrorScreen( Message => Translatable('Need ValidID'), ); } # Check if dynamic field is present in SysConfig setting my $UpdateEntity = $ParamObject->GetParam( Param => 'UpdateEntity' ) || ''; my $SysConfigObject = $Kernel::OM->Get('Kernel::System::SysConfig'); my %DynamicFieldOldData = %{$DynamicFieldData}; my @IsDynamicFieldInSysConfig; @IsDynamicFieldInSysConfig = $SysConfigObject->ConfigurationEntityCheck( EntityType => 'DynamicField', EntityName => $DynamicFieldData->{Name}, ); if (@IsDynamicFieldInSysConfig) { # An entity present in SysConfig couldn't be invalidated. if ( $Kernel::OM->Get('Kernel::System::Valid')->ValidLookup( ValidID => $GetParam{ValidID} ) ne 'valid' ) { $Errors{ValidIDInvalid} = 'ServerError'; $Errors{ValidOptionServerError} = 'InSetting'; } # In case changing name an authorization (UpdateEntity) should be send elsif ( $DynamicFieldData->{Name} ne $GetParam{Name} && !$UpdateEntity ) { $Errors{NameInvalid} = 'ServerError'; $Errors{InSettingNameServerError} = 1; } } # return to change screen if errors if (%Errors) { return $Self->_ShowScreen( %Param, %Errors, %GetParam, ID => $FieldID, Mode => 'Change', ); } # set specific config my $FieldConfig = { DefaultValue => $GetParam{DefaultValue}, }; # update dynamic field (FieldType and ObjectType cannot be changed; use old values) my $UpdateSuccess = $DynamicField->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} ), ); } if ( @IsDynamicFieldInSysConfig && $DynamicFieldOldData{Name} ne $GetParam{Name} && $UpdateEntity ) { SETTING: for my $SettingName (@IsDynamicFieldInSysConfig) { my %Setting = $SysConfigObject->SettingGet( Name => $SettingName, ); next SETTING if !IsHashRefWithData( \%Setting ); $Setting{EffectiveValue} =~ s/$DynamicFieldOldData{Name}/$GetParam{Name}/g; my $ExclusiveLockGUID = $SysConfigObject->SettingLock( Name => $Setting{Name}, Force => 1, UserID => $Self->{UserID} ); $Setting{ExclusiveLockGUID} = $ExclusiveLockGUID; my %UpdateSuccess = $SysConfigObject->SettingUpdate( %Setting, UserID => $Self->{UserID}, ); } $SysConfigObject->ConfigurationDeploy( Comments => "DynamicField name change", DirtySettings => \@IsDynamicFieldInSysConfig, UserID => $Self->{UserID}, Force => 1, ); } # if the user would like to continue editing the dynamic field, just redirect to the change screen if ( defined $ParamObject->GetParam( Param => 'ContinueAfterSave' ) && ( $ParamObject->GetParam( Param => 'ContinueAfterSave' ) eq '1' ) ) { return $LayoutObject->Redirect( OP => "Action=$Self->{Action};Subaction=Change;ObjectType=$DynamicFieldData->{ObjectType};FieldType=$DynamicFieldData->{FieldType};ID=$FieldID" ); } else { # otherwise return to overview 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 from 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 => 'Modernize W75pc Validate_Number', ); 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 => 'Modernize W50pc', ); # define config field specific settings my $DefaultValue = $Param{DefaultValue} || ''; # create the default value select my $DefaultValueStrg = $LayoutObject->BuildSelection( Data => { 0 => Translatable('Unchecked'), 1 => Translatable('Checked'), }, Name => 'DefaultValue', SelectedID => $Param{DefaultValue} || 0, PossibleNone => 0, Translation => 1, Class => 'Modernize', ); 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"'; } my $DynamicFieldName = $Param{Name}; # Add warning in case the DynamicField belongs a SysConfig setting. my $SysConfigObject = $Kernel::OM->Get('Kernel::System::SysConfig'); # In case dirty setting disable form my $IsDirtyConfig = 0; my @IsDirtyResult = $SysConfigObject->ConfigurationDirtySettingsList(); my %IsDirtyList = map { $_ => 1 } @IsDirtyResult; my @IsDynamicFieldInSysConfig = $SysConfigObject->ConfigurationEntityCheck( EntityType => 'DynamicField', EntityName => $DynamicFieldName // '', ); if (@IsDynamicFieldInSysConfig) { $LayoutObject->Block( Name => 'DynamicFieldInSysConfig', Data => { OldName => $DynamicFieldName, }, ); for my $SettingName (@IsDynamicFieldInSysConfig) { $LayoutObject->Block( Name => 'DynamicFieldInSysConfigRow', Data => { SettingName => $SettingName, }, ); # Verify if dirty setting if ( $IsDirtyList{$SettingName} ) { $IsDirtyConfig = 1; } } } if ($IsDirtyConfig) { $LayoutObject->Block( Name => 'DynamicFieldInSysConfigDirty', , ); } # generate output $Output .= $LayoutObject->Output( TemplateFile => 'AdminDynamicFieldCheckbox', Data => { %Param, ValidityStrg => $ValidityStrg, DynamicFieldOrderStrg => $DynamicFieldOrderStrg, DefaultValueStrg => $DefaultValueStrg, ReadonlyInternalField => $ReadonlyInternalField, } ); $Output .= $LayoutObject->Footer(); return $Output; } 1;