Files
scripts/Perl OTRS/Kernel/System/SysConfig/DB.pm
2024-10-14 00:08:40 +02:00

5653 lines
170 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::SysConfig::DB;
use strict;
use warnings;
use MIME::Base64;
use Time::HiRes();
use utf8;
use Kernel::System::VariableCheck qw( :all );
our @ObjectDependencies = (
'Kernel::Config',
'Kernel::System::Cache',
'Kernel::System::DB',
'Kernel::System::Encode',
'Kernel::System::Log',
'Kernel::System::Main',
'Kernel::System::YAML',
);
=head1 NAME
Kernel::System::SysConfig::DB - Functions to manage system configuration settings interactions with the database.
=head1 PUBLIC INTERFACE
=head2 new()
Create an object. Do not use it directly, instead use:
use Kernel::System::ObjectManager;
local $Kernel::OM = Kernel::System::ObjectManager->new();
my $SysConfigDBObject = $Kernel::OM->Get('Kernel::System::SysConfig::DB');
=cut
sub new {
my ( $Type, %Param ) = @_;
# allocate new hash for object
my $Self = {};
bless( $Self, $Type );
$Self->{CacheTTL} = 24 * 3600 * 30; # 1 month
return $Self;
}
=head2 DefaultSettingAdd()
Add a new SysConfig default entry.
my $DefaultID = $SysConfigDBObject->DefaultSettingAdd(
Name => "ProductName", # (required)
Description => "Setting description", # (required)
Navigation => "ASimple::Path::Structure", # (required)
IsInvisible => 1, # (optional) 1 or 0, default 0
IsReadonly => 0, # (optional) 1 or 0, default 0
IsRequired => 1, # (optional) 1 or 0, default 0
IsValid => 1, # (optional) 1 or 0, default 0
HasConfigLevel => 200, # (optional) default 0
UserModificationPossible => 0, # (optional) 1 or 0, default 0
UserModificationActive => 0, # (optional) 1 or 0, default 0
UserPreferencesGroup => 'Some Group' # (optional)
XMLContentRaw => $XMLString, # (required) the setting XML structure as it is on the config file
XMLContentParsed => $XMLParsedToPerl, # (required) the setting XML structure converted into a Perl structure
XMLFilename => 'Framework.xml' # (required) the name of the XML file
EffectiveValue => $SettingEffectiveValue, # (required) the value as will be stored in the Perl configuration file
ExclusiveLockExpiryTime => '2017-02-01 12:23:13', # (optional) If not provided, method will calculate it.
UserID => 123,
NoCleanup => 0, # (optional) Default 0. If enabled, system WILL NOT DELETE CACHE. In this case, it must be done manually.
# USE IT CAREFULLY.
);
Returns:
my $DefaultID = 123; # false in case of an error
=cut
sub DefaultSettingAdd {
my ( $Self, %Param ) = @_;
# Store params for further usage.
my %DefaultVersionParams = %Param;
for my $Key (
qw(Name Description Navigation XMLContentRaw XMLContentParsed XMLFilename EffectiveValue UserID)
)
{
if ( !defined $Param{$Key} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Key!",
);
return;
}
}
my @DefaultSettings = $Self->DefaultSettingList(
IncludeInvisible => 1,
);
# Check duplicate name
my ($SettingData) = grep { $_->{Name} eq $Param{Name} } @DefaultSettings;
return if IsHashRefWithData($SettingData);
# Check config level.
$Param{HasConfigLevel} //= 0;
# The value should be a positive integer if defined.
if ( !IsPositiveInteger( $Param{HasConfigLevel} ) && $Param{HasConfigLevel} ne '0' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "HasConfigLevel must be an integer!",
);
return;
}
# Check boolean parameters (0 as default value).
for my $Key (qw(IsInvisible IsReadonly IsRequired IsValid UserModificationPossible UserModificationActive)) {
$Param{$Key} = ( defined $Param{$Key} && $Param{$Key} ? 1 : 0 );
}
# Serialize data as string.
for my $Key (qw(XMLContentParsed EffectiveValue)) {
$Param{$Key} = $Kernel::OM->Get('Kernel::System::YAML')->Dump(
Data => $Param{$Key},
);
$DefaultVersionParams{$Key} = $Param{$Key};
}
# Set GuID.
$Param{ExclusiveLockGUID} //= 1;
# Set is dirty as enabled due it is a new setting.
$Param{IsDirty} = 1;
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Insert the default.
return if !$DBObject->Do(
SQL => '
INSERT INTO sysconfig_default
(name, description, navigation, is_invisible, is_readonly, is_required, is_valid, has_configlevel,
user_modification_possible, user_modification_active, user_preferences_group, xml_content_raw, xml_content_parsed, xml_filename, effective_value,
is_dirty, exclusive_lock_guid, create_time, create_by, change_time, change_by)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)',
Bind => [
\$Param{Name}, \$Param{Description}, \$Param{Navigation}, \$Param{IsInvisible},
\$Param{IsReadonly}, \$Param{IsRequired}, \$Param{IsValid}, \$Param{HasConfigLevel},
\$Param{UserModificationPossible}, \$Param{UserModificationActive}, \$Param{UserPreferencesGroup},
\$Param{XMLContentRaw}, \$Param{XMLContentParsed}, \$Param{XMLFilename}, \$Param{EffectiveValue},
\$Param{IsDirty}, \$Param{ExclusiveLockGUID}, \$Param{UserID}, \$Param{UserID},
],
);
# Get default ID.
$DBObject->Prepare(
SQL => 'SELECT id FROM sysconfig_default WHERE name = ?',
Bind => [ \$Param{Name} ],
Limit => 1,
);
my $DefaultID;
# Fetch the default setting ID.
ROW:
while ( my @Row = $DBObject->FetchrowArray() ) {
$DefaultID = $Row[0];
last ROW;
}
# Add default setting version.
my $DefaultVersionID = $Self->DefaultSettingVersionAdd(
DefaultID => $DefaultID,
%DefaultVersionParams,
NoVersionID => 1,
);
if ( !$Param{NoCleanup} ) {
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->Delete(
Type => 'SysConfigDefault',
Key => 'DefaultSettingGet::' . $Param{Name},
);
$CacheObject->CleanUp(
Type => 'SysConfigDefaultListGet',
);
$CacheObject->Delete(
Type => 'SysConfigDefaultList',
Key => 'DefaultSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigNavigation',
);
$CacheObject->CleanUp(
Type => 'SysConfigEntities',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
}
# Return if not version inserted.
return if !$DefaultVersionID;
return $DefaultID;
}
=head2 DefaultSettingBulkAdd()
Add new SysConfig default entries.
my $Success = $SysConfigDBObject->DefaultSettingBulkAdd(
Settings => { # (required) Hash of settings
"ACL::CacheTTL" => {
"EffectiveValue" => "--- '3600'\n",
"XMLContentParsed" => {
"Description" => [
{
"Content" => "Cache time in ...",
"Translatable" => 1
},
],
"Name" => "ACL::CacheTTL",
"Navigation" => [
{
"Content" => "Core::Ticket::ACL"
},
],
"Required" => 1,
"Valid" => 1,
"Value" => [
{
"Item" => [
{
"Content" => 3600,
"ValueRegex" => "^\\d+\$",
"ValueType" => "String"
},
],
},
],
},
"XMLContentParsedYAML" => "---\nDescription:\n- Content: Cache...",
"XMLContentRaw" => "<Setting Name=\"ACL::CacheTTL\" Required=\"1\" ...",
"XMLFilename" => "Ticket.xml"
},
...
},
SettingList => [ # list of current settings in DB
{
DefaultID => '123',
Name => 'SettingName1',
IsDirty => 1,
ExclusiveLockGUID => 0,
},
# ...
],
UserID => 1, # (required) UserID
);
=cut
sub DefaultSettingBulkAdd {
my ( $Self, %Param ) = @_;
for my $Needed (qw(Settings UserID)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!",
);
return;
}
}
if ( ref $Param{Settings} ne 'HASH' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Settings must be a hash!"
);
return;
}
$Param{SettingList} //= [];
if ( ref $Param{SettingList} ne 'ARRAY' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "SettingList must be an array",
);
}
my @Data;
SETTINGNAME:
for my $SettingName ( sort keys %{ $Param{Settings} } ) {
my ($BasicData) = grep { $_->{Name} eq $SettingName } @{ $Param{SettingList} };
if ($BasicData) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "$SettingName should not exist!"
);
next SETTINGNAME;
}
# Gather data for all records.
push @Data, [
$SettingName,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Description}->[0]->{Content} || '',
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Navigation}->[0]->{Content} || '',
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Invisible} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{ReadOnly} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Required} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Valid} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{ConfigLevel} || 100,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{UserModificationPossible} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{UserModificationActive} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{UserPreferencesGroup},
$Param{Settings}->{$SettingName}->{XMLContentRaw},
$Param{Settings}->{$SettingName}->{XMLContentParsedYAML},
$Param{Settings}->{$SettingName}->{XMLFilename},
$Param{Settings}->{$SettingName}->{EffectiveValue},
1,
1,
'current_timestamp',
$Param{UserID},
'current_timestamp',
$Param{UserID},
];
}
return if !$Self->_BulkInsert(
Table => 'sysconfig_default',
Columns => [
'name',
'description',
'navigation',
'is_invisible',
'is_readonly',
'is_required',
'is_valid',
'has_configlevel',
'user_modification_possible',
'user_modification_active',
'user_preferences_group',
'xml_content_raw',
'xml_content_parsed',
'xml_filename',
'effective_value',
'is_dirty',
'exclusive_lock_guid',
'create_time',
'create_by',
'change_time',
'change_by'
],
Data => \@Data,
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->CleanUp(
Type => 'SysConfigDefaultListGet',
);
$CacheObject->Delete(
Type => 'SysConfigDefaultList',
Key => 'DefaultSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigNavigation',
);
$CacheObject->CleanUp(
Type => 'SysConfigEntities',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
return 1;
}
=head2 DefaultSettingVersionBulkAdd()
my $Success = $SysConfigDBObject->DefaultSettingVersionBulkAdd(
Settings => { # (required) Hash of settings
"ACL::CacheTTL" => {
"EffectiveValue" => "--- '3600'\n",
"XMLContentParsed" => {
"Description" => [
{
"Content" => "Cache time in ...",
"Translatable" => 1
},
],
"Name" => "ACL::CacheTTL",
"Navigation" => [
{
"Content" => "Core::Ticket::ACL"
},
],
"Required" => 1,
"Valid" => 1,
"Value" => [
{
"Item" => [
{
"Content" => 3600,
"ValueRegex" => "^\\d+\$",
"ValueType" => "String"
},
],
},
],
},
"XMLContentParsedYAML" => "---\nDescription:\n- Content: Cache...",
"XMLContentRaw" => "<Setting Name=\"ACL::CacheTTL\" Required=\"1\" ...",
"XMLFilename" => "Ticket.xml"
},
...
},
SettingList => [ # list of current settings in DB
{
DefaultID => '123',
Name => 'SettingName1',
IsDirty => 1,
ExclusiveLockGUID => 0,
},
# ...
],
UserID => 1, # (required) UserID
);
=cut
sub DefaultSettingVersionBulkAdd {
my ( $Self, %Param ) = @_;
# Check needed stuff.
for my $Needed (qw(Settings SettingList UserID)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!",
);
return;
}
}
if ( ref $Param{Settings} ne 'HASH' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Settings must be a hash!"
);
return;
}
my @Data;
SETTINGNAME:
for my $SettingName ( sort keys %{ $Param{Settings} } ) {
my ($BasicData) = grep { $_->{Name} eq $SettingName } @{ $Param{SettingList} };
if ( !$BasicData || !$BasicData->{DefaultID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "DefaultID for $SettingName couldn't be determined, skipped!"
);
next SETTINGNAME;
}
# Gather data for all records.
push @Data, [
$BasicData->{DefaultID},
$SettingName,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Description}->[0]->{Content} || '',
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Navigation}->[0]->{Content} || '',
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Invisible} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{ReadOnly} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Required} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{Valid} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{ConfigLevel} || 100,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{UserModificationPossible} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{UserModificationActive} || 0,
$Param{Settings}->{$SettingName}->{XMLContentParsed}->{UserPreferencesGroup},
$Param{Settings}->{$SettingName}->{XMLContentRaw},
$Param{Settings}->{$SettingName}->{XMLContentParsedYAML},
$Param{Settings}->{$SettingName}->{XMLFilename},
$Param{Settings}->{$SettingName}->{EffectiveValue},
'current_timestamp',
$Param{UserID},
'current_timestamp',
$Param{UserID},
];
}
return if !$Self->_BulkInsert(
Table => 'sysconfig_default_version',
Columns => [
'sysconfig_default_id',
'name',
'description',
'navigation',
'is_invisible',
'is_readonly',
'is_required',
'is_valid',
'has_configlevel',
'user_modification_possible',
'user_modification_active',
'user_preferences_group',
'xml_content_raw',
'xml_content_parsed',
'xml_filename',
'effective_value',
'create_time',
'create_by',
'change_time',
'change_by',
],
Data => \@Data,
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->CleanUp(
Type => 'SysConfigDefaultVersion',
);
$CacheObject->CleanUp(
Type => 'SysConfigDefaultVersionList',
);
return 1;
}
=head2 DefaultSettingGet()
Get SysConfig default entry.
my %DefaultSetting = $SysConfigDBObject->DefaultSettingGet(
Name => "TheName", # (required) Setting name - prefered parameter.
# or
DefaultID => 4, # (required) DefaultID. Slightly slower execution.
NoCache => 0, # (optional) Default 0. If 1, cache will not be created.
);
Returns:
%DefaultSetting = (
DefaultID => "123",
Name => "ProductName",
Description => "Defines the name of the application ...",
Navigation => "ASimple::Path::Structure",
IsInvisible => 1, # 1 or 0
IsReadonly => 0, # 1 or 0
IsRequired => 1, # 1 or 0
IsValid => 1, # 1 or 0
HasConfigLevel => 200,
UserModificationPossible => 0, # 1 or 0
UserModificationActive => 0, # 1 or 0
UserPreferencesGroup => 'Some Group',
XMLContentRaw => "The XML structure as it is on the config file",
XMLContentParsed => "XML parsed to Perl",
XMLFilename => "Framework.xml",
EffectiveValue => "Product 6",
IsDirty => 1, # 1 or 0
ExclusiveLockGUID => 'A32CHARACTERLONGSTRINGFORLOCKING',
ExclusiveLockUserID => 1,
ExclusiveLockExpiryTime => '2016-05-29 11:09:04',
CreateTime => "2016-05-29 11:04:04",
CreateBy => 1,
ChangeTime => "2016-05-29 11:04:04",
ChangeBy => 1,
SettingUID => 'Default12320160529110404',
);
=cut
sub DefaultSettingGet {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need DefaultID or Name!',
);
return;
}
my $SettingName = $Param{Name};
if ( !$SettingName ) {
my %SettingData = $Self->DefaultSettingLookup(
DefaultID => $Param{DefaultID},
);
if ( !%SettingData || !$SettingData{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Setting with DefaultID = $Param{DefaultID} not found!",
);
return;
}
$SettingName = $SettingData{Name};
}
my $CacheType = "SysConfigDefault";
my $CacheKey = "DefaultSettingGet::$SettingName";
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return %{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Get default from database.
return if !$DBObject->Prepare(
SQL => '
SELECT id, name, description, navigation, is_invisible, is_readonly, is_required, is_valid, has_configlevel,
user_modification_possible, user_modification_active, user_preferences_group, xml_content_raw,
xml_content_parsed, xml_filename, effective_value, is_dirty, exclusive_lock_guid, exclusive_lock_user_id,
exclusive_lock_expiry_time, create_time, create_by, change_time, change_by
FROM sysconfig_default
WHERE name = ?',
Bind => [ \$SettingName ],
);
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
my %DefaultSetting;
while ( my @Data = $DBObject->FetchrowArray() ) {
# De-serialize default data.
my $XMLContentParsed = $YAMLObject->Load( Data => $Data[13] );
my $EffectiveValue = $YAMLObject->Load( Data => $Data[15] );
my $TimeStamp = $Data[22];
$TimeStamp =~ s{:|-|[ ]}{}gmsx;
%DefaultSetting = (
DefaultID => $Data[0],
Name => $Data[1],
Description => $Data[2],
Navigation => $Data[3],
IsInvisible => $Data[4],
IsReadonly => $Data[5],
IsRequired => $Data[6],
IsValid => $Data[7],
HasConfigLevel => $Data[8],
UserModificationPossible => $Data[9],
UserModificationActive => $Data[10],
UserPreferencesGroup => $Data[11] || '',
XMLContentRaw => $Data[12],
XMLContentParsed => $XMLContentParsed,
XMLFilename => $Data[14],
EffectiveValue => $EffectiveValue,
IsDirty => $Data[16] ? 1 : 0,
ExclusiveLockGUID => $Data[17],
ExclusiveLockUserID => $Data[18],
ExclusiveLockExpiryTime => $Data[19],
CreateTime => $Data[20],
CreateBy => $Data[21],
ChangeTime => $Data[22],
ChangeBy => $Data[23],
SettingUID => "Default$Data[0]$TimeStamp",
);
}
if ( !$Param{NoCache} ) {
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \%DefaultSetting,
TTL => $Self->{CacheTTL},
);
}
return %DefaultSetting;
}
=head2 DefaultSettingLookup()
Default setting lookup.
my %Result = $SysConfigDBObject->DefaultSettingLookup(
Name => "TheName", # (required)
# or
DefaultID => 4, # (required)
);
Returns:
%Result = (
DefaultID => 4,
Name => 'TheName',
);
=cut
sub DefaultSettingLookup {
my ( $Self, %Param ) = @_;
# Check needed stuff.
if ( !$Param{Name} && !$Param{DefaultID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need Name or DefaultID!",
);
return;
}
my @Bind;
my $SQL = '
SELECT id, name
FROM sysconfig_default
WHERE
';
if ( $Param{Name} ) {
$SQL .= 'name = ? ';
push @Bind, \$Param{Name};
}
else {
$SQL .= "id = ? ";
push @Bind, \$Param{DefaultID};
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# db query
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Bind,
Limit => 1,
);
my %Result;
ROW:
while ( my @Row = $DBObject->FetchrowArray() ) {
$Result{DefaultID} = $Row[0];
$Result{Name} = $Row[1];
last ROW;
}
return %Result;
}
=head2 DefaultSettingDelete()
Delete a default setting from the database.
my $Success = $SysConfigDBObject->DefaultSettingDelete(
DefaultID => 123,
);
my $Success = $SysConfigDBObject->DefaultSettingDelete(
Name => 'Name',
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub DefaultSettingDelete {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need DefaultID or Name!',
);
return;
}
my %DefaultSetting = $Self->DefaultSettingGet(
DefaultID => $Param{DefaultID} || undef,
Name => $Param{Name} || undef,
);
return 1 if !IsHashRefWithData( \%DefaultSetting );
my $DefaultID = $DefaultSetting{DefaultID};
# Delete the entries in SysConfig default version.
my $DeleteDefaultVersion = $Self->DefaultSettingVersionDelete(
DefaultID => $DefaultID,
);
# Return if not version deleted.
return if !$DeleteDefaultVersion;
# Delete default from the list.
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => 'DELETE FROM sysconfig_default WHERE id = ?',
Bind => [ \$DefaultID ],
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->Delete(
Type => 'SysConfigDefault',
Key => 'DefaultSettingGet::' . $DefaultSetting{Name},
);
$CacheObject->CleanUp(
Type => 'SysConfigDefaultListGet',
);
$CacheObject->Delete(
Type => 'SysConfigDefaultList',
Key => 'DefaultSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigNavigation',
);
$CacheObject->CleanUp(
Type => 'SysConfigEntities',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
# Clean cache for setting translations.
my %Languages = %{ $Kernel::OM->Get('Kernel::Config')->Get('DefaultUsedLanguages') };
for my $Language ( sort keys %Languages ) {
$CacheObject->Delete(
Type => 'SysConfig',
Key => "SettingTranslatedGet::$Language" . "::$DefaultSetting{Name}",
);
$CacheObject->Delete(
Type => 'SysConfig',
Key => "ConfigurationTranslatedGet::$Language",
);
}
return 1;
}
=head2 DefaultSettingUpdate()
Update SysConfig default entry.
my $Success = $SysConfigDBObject->DefaultSettingUpdate(
DefaultID => 123,
Name => "ProductName",
Description => "Defines the name of the application ...",
Navigation => "ASimple::Path::Structure",
IsInvisible => 1, # 1 or 0, optional, default 0
IsReadonly => 0, # 1 or 0, optional, default 0
IsRequired => 1, # 1 or 0, optional, default 0
IsValid => 1, # 1 or 0, optional, default 0
HasConfigLevel => 200, # optional, default 0
UserModificationPossible => 0, # 1 or 0, optional, default 0
UserModificationActive => 0, # 1 or 0, optional, default 0
UserPreferencesGroup => 'Some Group',
UserPreferencesGroup => 'Advanced', # optional
XMLContentRaw => $XMLString, # the XML structure as it is on the config file
XMLContentParsed => $XMLParsedToPerl,
XMLFilename => 'Framework.xml',
ExclusiveLockGUID => 1,
EffectiveValue => $SettingEffectiveValue,
UserID => 1,
);
Returns:
$Success = 1; # or false in case of an error.
=cut
sub DefaultSettingUpdate {
my ( $Self, %Param ) = @_;
# Store params for further usage.
my %DefaultVersionParams = %Param;
for my $Key (
qw(
DefaultID Name Description Navigation XMLContentRaw XMLContentParsed XMLFilename
ExclusiveLockGUID EffectiveValue UserID
)
)
{
if ( !defined $Param{$Key} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Key!",
);
return;
}
}
# Get default setting
my %DefaultSetting = $Self->DefaultSettingGet(
DefaultID => $Param{DefaultID},
);
# Check if setting exists.
return if !IsHashRefWithData( \%DefaultSetting );
# Don't allow name changes, due this is consider a NEW setting.
return if $DefaultSetting{Name} ne $Param{Name};
# Check if the setting is locked by the current user.
return if !$Self->DefaultSettingIsLockedByUser(
%Param,
ExclusiveLockUserID => $Param{UserID},
);
# Check config level, set 0 as default value.
$Param{HasConfigLevel} //= 0;
if ( !IsPositiveInteger( $Param{HasConfigLevel} ) && $Param{HasConfigLevel} ne '0' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "HasConfigLevel must be an integer!",
);
return;
}
# Check boolean parameters, set 0 as default value.
for my $Key (qw(IsInvisible IsReadonly IsRequired IsValid UserModificationPossible UserModificationActive)) {
$Param{$Key} = ( defined $Param{$Key} && $Param{$Key} ? 1 : 0 );
}
# Check if we really need to update.
my $IsDifferent = 0;
for my $Key (
qw(
DefaultID Description Navigation IsInvisible HasConfigLevel XMLContentRaw
XMLContentParsed XMLFilename ExclusiveLockGUID EffectiveValue HasConfigLevel IsInvisible
IsReadonly IsRequired IsValid UserModificationPossible UserModificationActive UserPreferencesGroup
)
)
{
my $DataIsDifferent = DataIsDifferent(
Data1 => $Param{$Key},
Data2 => $DefaultSetting{$Key},
);
if ($DataIsDifferent) {
$IsDifferent = 1;
}
}
return 1 if !$IsDifferent;
# Serialize data as string.
for my $Key (qw(XMLContentParsed EffectiveValue)) {
$Param{$Key} = $Kernel::OM->Get('Kernel::System::YAML')->Dump(
Data => $Param{$Key},
);
$DefaultVersionParams{$Key} = $Param{$Key};
}
# Set is dirty value.
$Param{IsDirty} = 1;
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Insert the default.
return if !$DBObject->Do(
SQL => '
UPDATE sysconfig_default
SET description = ?, navigation = ?, is_invisible = ?, is_readonly = ?,
is_required = ?, is_valid = ?, has_configlevel = ?, user_modification_possible = ?, user_modification_active = ?,
user_preferences_group = ?, xml_content_raw = ?, xml_content_parsed = ?, xml_filename =?, effective_value = ?,
is_dirty = ?, change_time = current_timestamp, change_by = ?
WHERE id = ?',
Bind => [
\$Param{Description}, \$Param{Navigation}, \$Param{IsInvisible}, \$Param{IsReadonly},
\$Param{IsRequired}, \$Param{IsValid}, \$Param{HasConfigLevel}, \$Param{UserModificationPossible},
\$Param{UserModificationActive}, \$Param{UserPreferencesGroup}, \$Param{XMLContentRaw},
\$Param{XMLContentParsed},
\$Param{XMLFilename}, \$Param{EffectiveValue}, \$Param{IsDirty}, \$Param{UserID}, \$Param{DefaultID},
],
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->Delete(
Type => 'SysConfigDefault',
Key => 'DefaultSettingGet::' . $DefaultSetting{Name},
);
$CacheObject->CleanUp(
Type => 'SysConfigDefaultListGet',
);
$CacheObject->Delete(
Type => 'SysConfigDefaultList',
Key => 'DefaultSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigNavigation',
);
$CacheObject->CleanUp(
Type => 'SysConfigEntities',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
# Clean cache for setting translations.
my %Languages = %{ $Kernel::OM->Get('Kernel::Config')->Get('DefaultUsedLanguages') };
for my $Language ( sort keys %Languages ) {
$CacheObject->Delete(
Type => 'SysConfig',
Key => "SettingTranslatedGet::$Language" . "::$DefaultSetting{Name}",
);
$CacheObject->Delete(
Type => 'SysConfig',
Key => "ConfigurationTranslatedGet::$Language",
);
}
# Add default setting version.
my $DefaultVersionID = $Self->DefaultSettingVersionAdd(
DefaultID => $Param{DefaultID},
%DefaultVersionParams,
NoVersionID => 1,
);
# Return if not version inserted.
return if !$DefaultVersionID;
# Unlock setting
my $IsUnlock = $Self->DefaultSettingUnlock(
DefaultID => $Param{DefaultID},
);
if ( !$IsUnlock ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Default setting with ID: $Param{DefaultID} was not possible to unlock!",
);
return;
}
return 1;
}
=head2 DefaultSettingSearch()
Search for settings which contains given term(Search) in the xml_content_raw column.
my @Result = $SysConfigDBObject->DefaultSettingSearch(
Search => 'Entity', # Search term
SearchType => 'XMLContent', # XMLContent or Metadata
CategoryFiles => ['Framework.xml', 'Ticket.xml', ], # (optional)
Valid => 0, # (optional) By default, system returns all Settings (valid and invalid)
# if set to 1, search only for valid,
# if set to 0, search also for invalid.
IncludeInvisible => 0, # (optional) Default 0
);
or
my @Result = $SysConfigDBObject->DefaultSettingSearch(
Search => ['Framework.xml' 'Ticket,xml'],
SearchType => 'Filename',
Valid => 1,
);
Returns:
@Result = (
'ACL::CacheTTL',
'ACLKeysLevel1Change',
...
);
=cut
sub DefaultSettingSearch {
my ( $Self, %Param ) = @_;
if ( !$Param{Search} && !$Param{CategoryFiles} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need Search or CategoryFiles!",
);
return;
}
if ( $Param{CategoryFiles} && !IsArrayRefWithData( $Param{CategoryFiles} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "CategoryFiles is invalid!",
);
return;
}
$Param{SearchType} //= 'XMLContent';
$Param{IncludeInvisible} //= 0;
my $Valid = 0;
if ( defined $Param{Valid} ) {
$Valid = $Param{Valid} ? 1 : 0;
}
my @Bind = ();
my $SQL = '
SELECT name
FROM sysconfig_default
WHERE 1 = 1';
if ($Valid) {
$SQL .= '
AND is_valid = ?';
push @Bind, \$Valid;
}
if ( !$Param{IncludeInvisible} ) {
$SQL .= '
AND is_invisible = ?';
push @Bind, \0;
}
my $Column = 'xml_content_raw';
if ( lc $Param{SearchType} eq 'metadata' ) {
$Column = [qw(name description navigation)];
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
if ( $Param{Search} ) {
my %QueryCondition = $DBObject->QueryCondition(
Key => $Column,
Value => $Param{Search},
SearchPrefix => "*",
SearchSuffix => "*",
BindMode => 1,
);
$SQL .= ' AND ' . $QueryCondition{SQL};
push @Bind, @{ $QueryCondition{Values} };
}
if ( $Param{CategoryFiles} ) {
@{ $Param{CategoryFiles} } = map {"($_)"} @{ $Param{CategoryFiles} };
$Param{CategoryFiles} = join 'OR', @{ $Param{CategoryFiles} };
my %QueryCondition = $DBObject->QueryCondition(
Key => 'xml_filename',
Value => $Param{CategoryFiles},
SearchPrefix => "",
SearchSuffix => "",
BindMode => 1,
);
$SQL .= ' AND ( ' . $QueryCondition{SQL} . ' )';
push @Bind, @{ $QueryCondition{Values} };
}
$SQL .= '
ORDER BY name asc';
# db query
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Bind,
);
my @Result;
ROW:
while ( my @Row = $DBObject->FetchrowArray() ) {
push @Result, $Row[0];
}
return @Result;
}
=head2 DefaultSettingListGet()
Get default setting list with complete data.
my @List = $SysConfigDBObject->DefaultSettingListGet(
IsInvisible => 1, # 1 or 0
IsReadonly => 0, # 1 or 0
IsRequired => 1, # 1 or 0
IsValid => 1, # 1 or 0
IsDirty => 1, # 1 or 0
HasConfigLevel => 0, # 1 or 0
UserModificationPossible => 0, # 1 or 0
UserModificationActive => 0, # 1 or 0
UserPreferencesGroup => 'Some Group',
Navigation => 'ASimple::Path::Structure',
Locked => 1, # check for locked settings
Category => 'OTRS', # optional (requires CategoryFiles)
CategoryFiles => ['Framework.xml', 'Ticket.xml', ], # optional (requires Category)
NoCache => 0, # (optional) Default 0. If set, system will not generate cache.
);
Returns:
@List = (
{
DefaultID => 123,
Name => "ProductName",
Description => "Defines the name of the application ...",
Navigation => "ASimple::Path::Structure",
IsInvisible => 1,
IsReadonly => 0,
IsRequired => 1,
IsValid => 1,
HasConfigLevel => 200,
UserModificationPossible => 0, # 1 or 0
UserModificationActive => 0, # 1 or 0
UserPreferencesGroup => 'Advanced', # optional
XMLContentRaw => "The XML structure as it is on the config file",
XMLContentParsed => "XML parsed to Perl",
XMLFilename => "Framework.xml",
EffectiveValue => "Product 6",
IsDirty => 1, # 1 or 0
ExclusiveLockGUID => 'A32CHARACTERLONGSTRINGFORLOCKING',
ExclusiveLockUserID => 1,
ExclusiveLockExpiryTime => '2016-05-29 11:09:04',
CreateTime => "2016-05-29 11:04:04",
CreateBy => 1,
ChangeTime => "2016-05-29 11:04:04",
ChangeBy => 1,
SettingUID => 'Default4717141789',
},
{
DefaultID => 321,
Name => 'FieldName',
# ...
ChangeTime => '2011-01-01 01:01:01',
ChangeBy => 1,
SettingUID => 'Default4717141781',
},
# ...
);
=cut
sub DefaultSettingListGet {
my ( $Self, %Param ) = @_;
if ( $Param{Category} ) {
if ( !IsArrayRefWithData( $Param{CategoryFiles} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "CategoryFiles are invalid!",
);
return;
}
}
if ( $Param{CategoryFiles} && !$Param{Category} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need Category!",
);
}
# Define SQL filters to be used in the queries.
my %FieldFilters = (
IsInvisible => 'is_invisible',
IsReadonly => 'is_readonly',
IsRequired => 'is_required',
IsValid => 'is_valid',
IsDirty => 'is_dirty',
HasConfigLevel => 'has_configlevel',
UserModificationPossible => 'user_modification_possible',
UserModificationActive => 'user_modification_active',
UserPreferencesGroup => 'user_preferences_group',
Navigation => 'navigation',
);
my @Filters;
my @Bind;
my $CacheType = 'SysConfigDefaultListGet';
my $CacheKey = 'DefaultSettingListGet'; # this cache key gets more elements
# Check params have a default value.
for my $Key ( sort keys %FieldFilters ) {
if ( defined $Param{$Key} ) {
push @Filters, " $FieldFilters{$Key} = ? ";
push @Bind, \$Param{$Key};
$CacheKey .= "::$FieldFilters{$Key} = $Param{$Key}";
}
}
# Check for locked settings.
if ( $Param{Locked} ) {
push @Filters, " exclusive_lock_guid != '0' ";
$CacheKey .= "::exclusive_lock_guid != '0'";
}
# Check for categories.
if ( $Param{Category} ) {
$CacheKey .= "::Category=$Param{Category}";
}
my $SQLFilter = '';
# Loop over filters and set them on SQL and cache key.
if ( IsArrayRefWithData( \@Filters ) ) {
$SQLFilter = ' WHERE ' . join ' AND ', @Filters;
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
if ( $Param{Category} ) {
@{ $Param{CategoryFiles} } = map {"($_)"} @{ $Param{CategoryFiles} };
$Param{CategoryFiles} = join 'OR', @{ $Param{CategoryFiles} };
my %QueryCondition = $DBObject->QueryCondition(
Key => 'xml_filename',
Value => $Param{CategoryFiles},
SearchPrefix => "",
SearchSuffix => "",
BindMode => 1,
);
if ($SQLFilter) {
$SQLFilter .= ' AND ( ' . $QueryCondition{SQL} . ' )';
}
else {
$SQLFilter = ' WHERE ' . $QueryCondition{SQL};
}
push @Bind, @{ $QueryCondition{Values} };
}
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return @{$Cache} if ref $Cache eq 'ARRAY';
my $SQL = '
SELECT id, name, description, navigation, is_invisible, is_readonly, is_required, is_valid, has_configlevel,
user_modification_possible, user_modification_active, user_preferences_group, xml_content_raw,
xml_content_parsed, xml_filename, effective_value, is_dirty, exclusive_lock_guid, exclusive_lock_user_id,
exclusive_lock_expiry_time, create_time, create_by, change_time, change_by
FROM sysconfig_default';
$SQLFilter //= '';
$SQL .= $SQLFilter . ' ORDER BY id';
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Bind,
);
my @Data;
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
while ( my @Row = $DBObject->FetchrowArray() ) {
# De-serialize default data.
my $XMLContentParsed = $YAMLObject->Load( Data => $Row[13] );
my $EffectiveValue = $YAMLObject->Load( Data => $Row[15] );
my $TimeStamp = $Row[22];
$TimeStamp =~ s{:|-|[ ]}{}gmsx;
my %DefaultSetting = (
DefaultID => $Row[0],
Name => $Row[1],
Description => $Row[2],
Navigation => $Row[3],
IsInvisible => $Row[4],
IsReadonly => $Row[5],
IsRequired => $Row[6],
IsValid => $Row[7],
HasConfigLevel => $Row[8],
UserModificationPossible => $Row[9],
UserModificationActive => $Row[10],
UserPreferencesGroup => $Row[11] || '',
XMLContentRaw => $Row[12],
XMLContentParsed => $XMLContentParsed,
XMLFilename => $Row[14],
EffectiveValue => $EffectiveValue,
IsDirty => $Row[16] ? 1 : 0,
ExclusiveLockGUID => $Row[17],
ExclusiveLockUserID => $Row[18],
ExclusiveLockExpiryTime => $Row[19],
CreateTime => $Row[20],
CreateBy => $Row[21],
ChangeTime => $Row[22],
ChangeBy => $Row[23],
SettingUID => "Default$Row[0]$TimeStamp",
);
push @Data, \%DefaultSetting;
}
if ( !$Param{NoCache} ) {
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \@Data,
TTL => $Self->{CacheTTL},
);
}
return @Data;
}
=head2 DefaultSettingList()
Get list of all settings.
my @DefaultSettings = $SysConfigDBObject->DefaultSettingList(
IncludeInvisible => 0, # (optional) Include invisible. Default 0.
IsDirty => 0, # (optional) Filter settings by IsDirty. If not provided, returns all settings.
Locked => 0, # (optional) Filter locked settings.
);
Returns:
@DefaultSettings = (
{
DefaultID => '123',
Name => 'SettingName1',
IsDirty => 1,
IsVisible => 1,
ExclusiveLockGUID => 0,
XMLFilename => 'Filename.xml',
},
{
DefaultID => '124',
Name => 'SettingName2',
IsDirty => 0,
IsVisible => 1,
ExclusiveLockGUID => 'fjewifjowj...',
XMLFilename => 'Filename.xml',
},
...
);
=cut
sub DefaultSettingList {
my ( $Self, %Param ) = @_;
my $CacheType = 'SysConfigDefaultList';
my $CacheKey = 'DefaultSettingList';
$Param{IncludeInvisible} //= 0;
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
my @DataRaw;
if ( ref $Cache eq 'ARRAY' ) {
@DataRaw = @{$Cache};
}
if ( !@DataRaw ) {
# Start SQL statement.
my $SQL = '
SELECT id, name, is_dirty, exclusive_lock_guid, xml_content_raw, xml_filename, is_invisible
FROM sysconfig_default
ORDER BY id';
return if !$DBObject->Prepare(
SQL => $SQL,
);
while ( my @Row = $DBObject->FetchrowArray() ) {
push @DataRaw, {
DefaultID => $Row[0],
Name => $Row[1],
IsDirty => $Row[2],
ExclusiveLockGUID => $Row[3],
XMLContentRaw => $Row[4],
XMLFilename => $Row[5],
IsInvisible => $Row[6],
};
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \@DataRaw,
TTL => $Self->{CacheTTL},
);
}
# Copy DataRaw to prevent modifications to in memory cache.
my @Data = @DataRaw;
# filter
if ( defined $Param{IsDirty} ) {
@Data = grep { $_->{IsDirty} == $Param{IsDirty} } @Data;
}
if ( defined $Param{Locked} ) {
if ( $Param{Locked} ) {
# Filter only locked settings
@Data = grep { $_->{ExclusiveLockGUID} } @Data;
}
else {
# Filter only unlocked settings
@Data = grep { !$_->{ExclusiveLockGUID} } @Data;
}
}
if ( !$Param{IncludeInvisible} ) {
# Filter only those settings that are visible.
@Data = grep { !$_->{IsInvisible} } @Data;
}
return @Data;
}
=head2 DefaultSettingLock()
Lock Default setting(s) to the particular user.
my $ExclusiveLockGUID = $SysConfigDBObject->DefaultSettingLock(
DefaultID => 1, # the ID of the setting that needs to be locked
# or
Name => 'SettingName', # the Name of the setting that needs to be locked
# or
LockAll => 1, # system locks all settings.
Force => 1, # (optional) Force locking (do not check if it's already locked by another user). Default: 0.
UserID => 1, # (required)
);
Returns:
$ExclusiveLockGUID = 'azzHab72wIlAXDrxHexsI5aENsESxAO7'; # Setting locked
or
$ExclusiveLockGUID = undef; # Not locked
=cut
sub DefaultSettingLock {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
if ( !$Param{DefaultID} && !$Param{Name} && !$Param{LockAll} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need DefaultID, Name or LockAll!",
);
return;
}
# Check if a deployment is locked, in that case it's not possible to lock a setting.
my $DeploymentLocked = $Self->DeploymentIsLocked();
if ($DeploymentLocked) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "It's not possible to lock a setting if a deployment is currently locked.",
);
return;
}
my $Locked;
if ( !$Param{LockAll} ) {
# Check if it's already locked (skip if force is used).
$Locked = $Self->DefaultSettingIsLocked(
DefaultID => $Param{DefaultID},
Name => $Param{Name},
);
}
return if ( !$Param{Force} && $Locked );
# Check if setting can be locked(IsReadonly).
my %DefaultSetting;
if ( !$Param{LockAll} ) {
%DefaultSetting = $Self->DefaultSettingGet(%Param);
if ( $DefaultSetting{IsReadonly} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "It's not possible to lock readonly setting $DefaultSetting{Name}"
. " (UserID=$Param{UserID}!",
);
return;
}
}
# Check correct length for ExclusiveLockGUID if defined.
if ( defined $Param{ExclusiveLockGUID} && length( $Param{ExclusiveLockGUID} ) != 32 ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "The ExclusiveLockGUID is invalid!",
);
return;
}
# Setting is not locked, generate or use a locking string.
my $ExclusiveLockGUID = $Param{ExclusiveLockGUID} || $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString(
Length => 32,
);
my $SettingExpireTimeMinutes = 5;
# Get current time.
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
$DateTimeObject->Add(
Minutes => $SettingExpireTimeMinutes,
);
my $SQL = '
UPDATE sysconfig_default
SET
exclusive_lock_guid = ?,
exclusive_lock_user_id = ?,
exclusive_lock_expiry_time = ?
';
my $ExpiryTime = $DateTimeObject->ToString();
my @Bind = (
\$ExclusiveLockGUID, \$Param{UserID},
\$ExpiryTime,
);
if ( $Param{DefaultID} ) {
$SQL .= '
WHERE id = ?';
push @Bind, \$Param{DefaultID};
}
elsif ( $Param{Name} ) {
$SQL .= '
WHERE name = ?';
push @Bind, \$Param{Name};
}
# Add locking data to the setting record
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => $SQL,
Bind => \@Bind,
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Check if there was cache for this type/key pair.
my $DefaultSettingListGet = $CacheObject->Get(
Type => 'SysConfigDefaultListGet',
Key => 'DefaultSettingListGet',
);
if ( $Param{LockAll} ) {
$CacheObject->CleanUp(
Type => 'SysConfigDefault',
);
}
else {
$CacheObject->Delete(
Type => 'SysConfigDefault',
Key => 'DefaultSettingGet::' . $DefaultSetting{Name},
);
}
$CacheObject->CleanUp(
Type => 'SysConfigDefaultListGet',
);
# Warm up the cache.
if ($DefaultSettingListGet) {
# Warm up existing cache.
if (%DefaultSetting) {
# Update one setting.
my $Index;
# Determine index of the element.
LOOPINDEX:
for my $LoopIndex ( 0 .. scalar @{$DefaultSettingListGet} - 1 ) {
next LOOPINDEX if $DefaultSettingListGet->[$LoopIndex]->{DefaultID} ne $DefaultSetting{DefaultID};
$Index = $LoopIndex;
last LOOPINDEX;
}
# Update value.
$DefaultSettingListGet->[$Index] = {
%{ $DefaultSettingListGet->[$Index] },
ExclusiveLockExpiryTime => $ExpiryTime,
ExclusiveLockGUID => $ExclusiveLockGUID,
ExclusiveLockUserID => $Param{UserID},
};
}
else {
# Update all settings.
for my $Index ( 0 .. scalar @{$DefaultSettingListGet} - 1 ) {
$DefaultSettingListGet->[$Index] = {
%{ $DefaultSettingListGet->[$Index] },
ExclusiveLockExpiryTime => $ExpiryTime,
ExclusiveLockGUID => $ExclusiveLockGUID,
ExclusiveLockUserID => $Param{UserID},
};
}
}
# Set new cache value.
$CacheObject->Set(
Type => 'SysConfigDefaultListGet',
Key => 'DefaultSettingListGet',
Value => $DefaultSettingListGet,
TTL => $Self->{CacheTTL},
CacheInBackend => 0,
);
}
$CacheObject->Delete(
Type => 'SysConfigDefaultList',
Key => 'DefaultSettingList',
);
return $ExclusiveLockGUID;
}
=head2 DefaultSettingIsLocked()
Check if particular Default Setting is locked.
my $Locked = $SysConfigDBObject->DefaultSettingIsLocked(
DefaultID => 1, # the ID of the setting that needs to be checked
# or
Name => 'SettingName', # the Name of the setting that needs to be checked
GetLockUserID => 1, # optional, it will return the ExclusiveLockUserID in case it exist
);
Returns:
$Locked = 1; # Locked
or
$Locked = 123 # The UserID
=cut
sub DefaultSettingIsLocked {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need DefaultID or Name!",
);
return;
}
my %DefaultSetting = $Self->DefaultSettingGet(
DefaultID => $Param{DefaultID},
Name => $Param{Name},
);
# The setting is not available, user can't update it anyways
return 0 if !%DefaultSetting;
# Check if it's locked.
return 0 if !$DefaultSetting{ExclusiveLockExpiryTime};
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
# Setting was locked, check if lock has expired.
my $LockedDateTimeObject = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
String => $DefaultSetting{ExclusiveLockExpiryTime},
},
);
my $Locked = $LockedDateTimeObject > $DateTimeObject ? 1 : 0;
# Remove locking if lock time is expired.
if ( !$Locked ) {
$Self->DefaultSettingUnlock( DefaultID => $Param{DefaultID} );
}
# Check if retrieve the ExclusiveLockUserID is needed
elsif ( $Param{GetLockUserID} ) {
$Locked = $DefaultSetting{ExclusiveLockUserID};
}
return $Locked;
}
=head2 DefaultSettingIsLockedByUser()
Check if particular Default Setting is locked.
my $LockedByUser = $SysConfigDBObject->DefaultSettingIsLockedByUser(
DefaultID => 1, # the ID of the setting that needs to be checked
# or
Name => 'SettingName', # the name of the setting that needs to be checked
ExclusiveLockUserID => 2, # the user should have locked the setting
ExclusiveLockGUID => 'AGUIDSTRING', # the GUID used to locking the setting
);
Returns:
$LockedByUser = 1;
=cut
sub DefaultSettingIsLockedByUser {
my ( $Self, %Param ) = @_;
for my $Needed (qw(ExclusiveLockUserID ExclusiveLockGUID)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!",
);
return;
}
}
if ( !$Param{DefaultID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need DefaultID or Name!",
);
return;
}
return if !IsStringWithData( $Param{ExclusiveLockGUID} );
# Get default setting.
my %DefaultSetting = $Self->DefaultSettingGet(
DefaultID => $Param{DefaultID},
Name => $Param{Name},
);
# Check if setting exists.
return if !IsHashRefWithData( \%DefaultSetting );
# Check ExclusiveLockUserID
return if !$DefaultSetting{ExclusiveLockUserID};
return if $DefaultSetting{ExclusiveLockUserID} ne $Param{ExclusiveLockUserID};
# Check ExclusiveLockGUID.
return if !$DefaultSetting{ExclusiveLockGUID};
return if $DefaultSetting{ExclusiveLockGUID} ne $Param{ExclusiveLockGUID};
my $ExclusiveLockGUID = $DefaultSetting{ExclusiveLockGUID};
# Setting was locked, check if lock has expired.
my $CurrentDateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
my $LockedDateTimeObject = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
String => $DefaultSetting{ExclusiveLockExpiryTime},
},
);
my $Locked = $LockedDateTimeObject > $CurrentDateTimeObject ? 1 : 0;
# Extend locking time if the settings was already locked for this user but the time was expired.
if ( !$Locked ) {
$ExclusiveLockGUID = $Self->DefaultSettingLock(
UserID => $Param{ExclusiveLockUserID},
DefaultID => $Param{DefaultID},
Name => $Param{Name},
ExclusiveLockGUID => $Param{ExclusiveLockGUID},
);
}
return 1 if $ExclusiveLockGUID;
return;
}
=head2 DefaultSettingUnlock()
Unlock particular or all Default Setting(s).
my $Success = $SysConfigDBObject->DefaultSettingUnlock(
DefaultID => 1, # the ID of the setting that needs to be unlocked
# or
Name => 'SettingName', # the name of the setting that needs to be locked
# or
UnlockAll => 1, # unlock all settings
);
Returns:
$Success = 1;
=cut
sub DefaultSettingUnlock {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultID} && !$Param{Name} && !$Param{UnlockAll} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need DefaultID, Name or UnlockAll!",
);
return;
}
my @SettingsLocked;
my %DefaultSetting;
if ( $Param{UnlockAll} ) {
# Get locked settings only.
@SettingsLocked = $Self->DefaultSettingList(
Locked => 1,
);
# all settings are unlocked already
return 1 if !@SettingsLocked;
}
else {
%DefaultSetting = $Self->DefaultSettingGet(
%Param,
NoCache => 1,
);
return if !%DefaultSetting;
push @SettingsLocked, \%DefaultSetting;
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my $SQL = '
UPDATE sysconfig_default
SET
exclusive_lock_guid = ?,
exclusive_lock_user_id = ?,
exclusive_lock_expiry_time = ?
WHERE
';
my @Bind = ( \0, \undef, \undef );
if ( $Param{DefaultID} ) {
$SQL .= '
id = ?';
push @Bind, \$Param{DefaultID};
}
elsif ( $Param{Name} ) {
$SQL .= '
name = ?';
push @Bind, \$Param{Name};
}
else {
# UnlockAll
$SQL .= '
exclusive_lock_guid != ? ';
push @Bind, \0;
}
# Remove locking from setting record.
return if !$DBObject->Do(
SQL => $SQL,
Bind => \@Bind,
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Check if there was cache for this type/key pair.
my $DefaultSettingListGet = $CacheObject->Get(
Type => 'SysConfigDefaultListGet',
Key => 'DefaultSettingListGet',
);
for my $Setting (@SettingsLocked) {
$CacheObject->Delete(
Type => 'SysConfigDefault',
Key => 'DefaultSettingGet::' . $Setting->{Name},
);
}
$CacheObject->CleanUp(
Type => 'SysConfigDefaultListGet',
);
# Warm up the cache.
if ($DefaultSettingListGet) {
# Warm up existing cache.
if (%DefaultSetting) {
# Update one setting.
my $Index;
# Determine index of the element.
LOOPINDEX:
for my $LoopIndex ( 0 .. scalar @{$DefaultSettingListGet} - 1 ) {
next LOOPINDEX if $DefaultSettingListGet->[$LoopIndex]->{DefaultID} ne $DefaultSetting{DefaultID};
$Index = $LoopIndex;
last LOOPINDEX;
}
# Update value.
$DefaultSettingListGet->[$Index] = {
%{ $DefaultSettingListGet->[$Index] },
ExclusiveLockExpiryTime => undef,
ExclusiveLockGUID => 0,
ExclusiveLockUserID => undef,
};
}
else {
# Update all settings.
for my $Index ( 0 .. scalar @{$DefaultSettingListGet} - 1 ) {
$DefaultSettingListGet->[$Index] = {
%{ $DefaultSettingListGet->[$Index] },
ExclusiveLockExpiryTime => undef,
ExclusiveLockGUID => 0,
ExclusiveLockUserID => undef,
};
}
}
# Set new cache value.
$CacheObject->Set(
Type => 'SysConfigDefaultListGet',
Key => 'DefaultSettingListGet',
Value => $DefaultSettingListGet,
TTL => $Self->{CacheTTL},
CacheInBackend => 0,
);
}
$CacheObject->Delete(
Type => 'SysConfigDefaultList',
Key => 'DefaultSettingList',
);
return 1;
}
=head2 DefaultSettingDirtyCleanUp()
Removes the IsDirty flag from default settings.
my $Success = $SysConfigDBObject->DefaultSettingDirtyCleanUp(
AllSettings => 0, # (default 0) Reset all dirty settings.
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub DefaultSettingDirtyCleanUp {
my ( $Self, %Param ) = @_;
my @DirtySettings;
if ( !$Param{AllSettings} ) {
@DirtySettings = $Self->DefaultSettingList(
IsDirty => 1,
);
}
# Remove is dirty flag for default settings.
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => '
UPDATE sysconfig_default
SET is_dirty = 0
WHERE is_dirty = 1',
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Check if there was cache for this type/key pair.
my $DefaultSettingListGet = $CacheObject->Get(
Type => 'SysConfigDefaultListGet',
Key => 'DefaultSettingListGet',
);
if ( $Param{AllSettings} ) {
$CacheObject->CleanUp(
Type => 'SysConfigDefault',
);
}
else {
for my $Setting (@DirtySettings) {
$CacheObject->Delete(
Type => 'SysConfigDefault',
Key => 'DefaultSettingGet::' . $Setting->{Name},
);
}
}
$CacheObject->CleanUp(
Type => 'SysConfigDefaultListGet',
);
# Warm up the cache.
if ($DefaultSettingListGet) {
# Warm up existing cache.
# Update all settings.
for my $Index ( 0 .. scalar @{$DefaultSettingListGet} - 1 ) {
$DefaultSettingListGet->[$Index]->{IsDirty} = 0;
}
# Set new cache value.
$CacheObject->Set(
Type => 'SysConfigDefaultListGet',
Key => 'DefaultSettingListGet',
Value => $DefaultSettingListGet,
TTL => $Self->{CacheTTL},
CacheInBackend => 0,
);
}
$CacheObject->Delete(
Type => 'SysConfigDefaultList',
Key => 'DefaultSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
return 1;
}
=head2 DefaultSettingVersionAdd()
Add a new SysConfig default version entry.
my $DefaultVersionID = $SysConfigDBObject->DefaultSettingVersionAdd(
DefaultID => 456,
Name => "ProductName",
Description => "Defines the name of the application ...",
Navigation => "ASimple::Path::Structure",
IsInvisible => 1, # 1 or 0, optional, default 0
IsReadonly => 0, # 1 or 0, optional, default 0
IsRequired => 1, # 1 or 0, optional, default 0
IsValid => 1, # 1 or 0, optional, default 0
HasConfigLevel => 200, # optional, default 0
UserModificationPossible => 0, # 1 or 0, optional, default 0
UserModificationActive => 0, # 1 or 0, optional, default 0
UserPreferencesGroup => 'Advanced', # optional
XMLContentRaw => $XMLString, # the XML structure as it is on the config file
XMLContentParsed => $XMLParsedToPerl, # the setting XML structure converted into YAML
XMLFilename => 'Framework.xml' # the name of the XML file
EffectiveValue => $YAMLEffectiveValue, # YAML EffectiveValue
UserID => 1,
NoCleanup => 0, # (optional) Default 0. If enabled, system WILL NOT DELETE CACHE. In this case, it must be done manually.
# USE IT CAREFULLY.
NoVersionID => 1, # 1 or 0, optional, default 0, prevents the return of DefaultVersionID and returns only 1 in case of success.
);
Returns:
my $DefaultVersionID = 123; # false in case of an error
=cut
sub DefaultSettingVersionAdd {
my ( $Self, %Param ) = @_;
for my $Key (
qw(DefaultID Name Description Navigation XMLContentRaw XMLContentParsed XMLFilename EffectiveValue UserID)
)
{
if ( !defined $Param{$Key} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Key!",
);
return;
}
}
# Check config level.
$Param{HasConfigLevel} //= 0;
if ( !IsPositiveInteger( $Param{HasConfigLevel} ) && $Param{HasConfigLevel} ne '0' ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "HasConfigLevel must be an integer!",
);
return;
}
# Check boolean parameters, set 0 as default value.
for my $Key (qw(IsInvisible IsReadonly IsRequired IsValid UserModificationPossible UserModificationActive)) {
$Param{$Key} = ( defined $Param{$Key} && $Param{$Key} ? 1 : 0 );
}
if ( $Param{EffectiveValue} eq "/usr/bin/gpg/mod" ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need!"
);
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Insert the default.
return if !$DBObject->Do(
SQL => '
INSERT INTO sysconfig_default_version
(sysconfig_default_id, name, description, navigation, is_invisible, is_readonly, is_required, is_valid,
has_configlevel, user_modification_possible, user_modification_active, user_preferences_group,
xml_content_raw, xml_content_parsed, xml_filename, effective_value, create_time, create_by,
change_time, change_by)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)',
Bind => [
\$Param{DefaultID}, \$Param{Name}, \$Param{Description}, \$Param{Navigation},
\$Param{IsInvisible}, \$Param{IsReadonly}, \$Param{IsRequired}, \$Param{IsValid}, \$Param{HasConfigLevel},
\$Param{UserModificationPossible}, \$Param{UserModificationActive}, \$Param{UserPreferencesGroup},
\$Param{XMLContentRaw}, \$Param{XMLContentParsed}, \$Param{XMLFilename}, \$Param{EffectiveValue},
\$Param{UserID}, \$Param{UserID},
],
);
# Get default version ID.
$DBObject->Prepare(
SQL => '
SELECT id
FROM sysconfig_default_version
WHERE sysconfig_default_id = ? AND name = ?
ORDER BY id DESC
',
Bind => [ \$Param{DefaultID}, \$Param{Name} ],
Limit => 1,
);
# Fetch the default setting ID
my $DefaultVersionID;
if ( $Param{NoVersionID} ) {
$DefaultVersionID = 1;
}
else {
while ( my @Row = $DBObject->FetchrowArray() ) {
$DefaultVersionID = $Row[0];
}
}
if ( !$Param{NoCleanup} ) {
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->CleanUp(
Type => 'SysConfigDefaultVersion',
);
$CacheObject->CleanUp(
Type => 'SysConfigDefaultVersionList',
);
}
return $DefaultVersionID;
}
=head2 DefaultSettingVersionGet()
Get SysConfig default version entry.
my %DefaultSettingVersion = $SysConfigDBObject->DefaultSettingVersionGet(
DefaultVersionID => 123,
);
Returns:
%DefaultSettingVersion = (
DefaultVersionID => 123,
DefaultID => 456,
Name => "ProductName",
Description => "Defines the name of the application ...",
Navigation => "ASimple::Path::Structure",
IsInvisible => 1, # 1 or 0
IsReadonly => 0, # 1 or 0
IsRequired => 1, # 1 or 0
IsValid => 1, # 1 or 0
HasConfigLevel => 200,
UserModificationPossible => 0, # 1 or 0
UserModificationActive => 0, # 1 or 0
UsePreferencesGroup => 'Advanced', # optional
XMLContentRaw => "The XML structure as it is on the config file",
XMLContentParsed => "XML parsed to Perl",
XMLFilename => 'Framework.xml',
EffectiveValue => "Product 6",
CreateTime => "2016-05-29 11:04:04",
CreateBy => 44,
ChangeTime => "2016-05-29 11:04:04",
ChangeBy => 88,
);
=cut
sub DefaultSettingVersionGet {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultVersionID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need DefaultVersionID!',
);
return;
}
my $FieldName;
my $FieldValue;
if ( $Param{DefaultVersionID} ) {
# Set DefaultID as filter.
$FieldName = 'id';
$FieldValue = $Param{DefaultVersionID};
}
elsif ( $Param{Name} ) {
# Set Name as filter
$FieldName = 'name';
$FieldValue = $Param{Name};
}
my $CacheType = "SysConfigDefaultVersion";
my $CacheKey = 'DefaultSettingVersionGet::' . $FieldName . '::' . $FieldValue;
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return %{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Get default from database.
return if !$DBObject->Prepare(
SQL => '
SELECT id, sysconfig_default_id, name, description, navigation, is_invisible, is_readonly, is_required,
is_valid, has_configlevel, user_modification_possible, user_modification_active, user_preferences_group,
xml_content_raw, xml_content_parsed, xml_filename, effective_value, create_time, create_by,
change_time, change_by
FROM sysconfig_default_version
WHERE ' . $FieldName . ' = ?',
Bind => [ \$FieldValue ],
);
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
my %DefaultSettingVersion;
while ( my @Data = $DBObject->FetchrowArray() ) {
# De-serialize default data.
my $XMLContentParsed = $YAMLObject->Load( Data => $Data[14] );
my $EffectiveValue = $YAMLObject->Load( Data => $Data[16] );
%DefaultSettingVersion = (
DefaultVersionID => $Data[0],
DefaultID => $Data[1],
Name => $Data[2],
Description => $Data[3],
Navigation => $Data[4],
IsInvisible => $Data[5],
IsReadonly => $Data[6],
IsRequired => $Data[7],
IsValid => $Data[8],
HasConfigLevel => $Data[9],
UserModificationPossible => $Data[10],
UserModificationActive => $Data[11],
UserPreferencesGroup => $Data[12] || '',
XMLContentRaw => $Data[13],
XMLContentParsed => $XMLContentParsed,
XMLFilename => $Data[15],
EffectiveValue => $EffectiveValue,
CreateTime => $Data[17],
CreateBy => $Data[18],
ChangeTime => $Data[19],
ChangeBy => $Data[20],
);
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \%DefaultSettingVersion,
TTL => $Self->{CacheTTL},
);
return %DefaultSettingVersion;
}
=head2 DefaultSettingVersionDelete()
Delete a default setting version from list based on default version ID or default ID.
my $Success = $SysConfigDBObject->DefaultSettingVersionDelete(
DefaultVersionID => 123,
);
or
my $Success = $SysConfigDBObject->DefaultSettingVersionDelete(
DefaultID => 45,
);
or
my $Success = $SysConfigDBObject->DefaultSettingVersionDelete(
Name => 'AnyName',
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub DefaultSettingVersionDelete {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultVersionID} && !$Param{DefaultID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need ID, DefaultID or Name!',
);
return;
}
my $FieldName;
my $FieldValue;
if ( $Param{DefaultVersionID} ) {
# Set conditions for id.
$FieldName = 'id';
$FieldValue = $Param{DefaultVersionID};
}
elsif ( $Param{DefaultID} ) {
# Set conditions for default id.
$FieldName = 'sysconfig_default_id';
$FieldValue = $Param{DefaultID};
}
elsif ( $Param{Name} ) {
# Set conditions for name.
$FieldName = 'name';
$FieldValue = $Param{Name};
}
# Delete default from the list.
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => 'DELETE FROM sysconfig_default_version WHERE ' . $FieldName . ' = ?',
Bind => [ \$FieldValue ],
);
if ( !$Param{DefaultVersionID} ) {
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => 'SysConfigDefaultVersion',
);
}
else {
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigDefaultVersion',
Key => 'DefaultSettingVersionGet::id::' . $Param{DefaultVersionID},
);
}
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => 'SysConfigDefaultVersionList',
);
return 1;
}
=head2 DefaultSettingVersionGetLast()
Get last deployment.
my %DefaultSettingVersionGetLast = $SysConfigDBObject->DefaultSettingVersionGetLast(
DefaultID => 456,
);
Returns:
%DefaultSettingVersion = (
DefaultVersionID => 123,
DefaultID => 456,
Name => "ProductName",
Description => "Defines the name of the application ...",
Navigation => "ASimple::Path::Structure",
IsInvisible => 1, # 1 or 0
IsReadonly => 0, # 1 or 0
IsRequired => 1, # 1 or 0
IsValid => 1, # 1 or 0
HasConfigLevel => 200,
UserModificationPossible => 0, # 1 or 0
UserModificationActive => 0, # 1 or 0
UsePreferencesGroup => 'Advanced', # optional
XMLContentRaw => "The XML structure as it is on the config file",
XMLContentParsed => "XML parsed to Perl",
XMLFilename => 'Framework.xml',
EffectiveValue => "Product 6",
CreateTime => "2016-05-29 11:04:04",
ChangeTime => "2016-05-29 11:04:04",
);
=cut
sub DefaultSettingVersionGetLast {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need DefaultID!',
);
return;
}
my $CacheType = 'SysConfigDefaultVersion';
my $CacheKey = 'DefaultSettingVersionGetLast::' . $Param{DefaultID};
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return %{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
return if !$DBObject->Prepare(
SQL => 'SELECT MAX(id) FROM sysconfig_default_version WHERE sysconfig_default_id = ?',
Bind => [ \$Param{DefaultID} ],
);
my $DefaultVersionID;
while ( my @Row = $DBObject->FetchrowArray() ) {
$DefaultVersionID = $Row[0];
}
return if !$DefaultVersionID;
my %DefaultSettingVersion = $Self->DefaultSettingVersionGet(
DefaultVersionID => $DefaultVersionID,
);
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \%DefaultSettingVersion,
TTL => $Self->{CacheTTL},
);
return %DefaultSettingVersion;
}
=head2 DefaultSettingVersionListGet()
Get version setting list with complete data.
my @List = $SysConfigDBObject->DefaultSettingVersionListGet(
Name => 'SettingName', # optional
# or
DefaultID => 123, # optional
);
Returns:
@List = (
{
DefaultVersionID => 123,
DefaultID => 456,
Name => "ProductName",
Description => "Defines the name of the application ...",
Navigation => "ASimple::Path::Structure",
IsInvisible => 1, # 1 or 0
IsReadonly => 0, # 1 or 0
IsRequired => 1, # 1 or 0
IsValid => 1, # 1 or 0
HasConfigLevel => 200,
UserModificationPossible => 0, # 1 or 0
UserModificationActive => 0, # 1 or 0
UserPreferencesGroup => 'Advanced', # optional
XMLContentRaw => "The XML structure as it is on the config file",
XMLContentParsed => "XML parsed to Perl",
XMLFilename => 'Framework.xml',
EffectiveValue => "Product 6",
CreateTime => "2016-05-29 11:04:04",
ChangeTime => "2016-05-29 11:04:04",
},
{
DefaultVersionID => 321,
DefaultID => 890,
Name => 'FieldName',
# ...
CreateTime => '2010-09-11 10:08:00',
ChangeTime => '2011-01-01 01:01:01',
},
# ...
);
=cut
sub DefaultSettingVersionListGet {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need DefaultID or Name!',
);
return;
}
my $FieldName;
my $FieldValue;
my $FieldCache;
if ( $Param{DefaultID} ) {
# Set conditions for default id.
$FieldName = 'sysconfig_default_id';
$FieldValue = $Param{DefaultID};
$FieldCache = "DefaultID::$Param{DefaultID}";
}
elsif ( $Param{Name} ) {
# Set conditions for name.
$FieldName = 'name';
$FieldValue = $Param{Name};
$FieldCache = "Name::$Param{Name}";
}
# Set filters on SQL and cache key.
my $SQLFilter = "WHERE $FieldName = '$FieldValue' ";
my $CacheType = 'SysConfigDefaultVersionList';
my $CacheKey = 'DefaultSettingVersionList::' . $FieldCache;
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return @{$Cache} if ref $Cache eq 'ARRAY';
# Start SQL statement.
my $SQL = 'SELECT id, name FROM sysconfig_default_version ' . $SQLFilter . ' ORDER BY id DESC';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my @Data;
return if !$DBObject->Prepare( SQL => $SQL );
my @DefaultVersionIDs;
while ( my @Row = $DBObject->FetchrowArray() ) {
push @DefaultVersionIDs, $Row[0];
}
# Get default settings.
for my $ItemID (@DefaultVersionIDs) {
my %DefaultSetting = $Self->DefaultSettingVersionGet(
DefaultVersionID => $ItemID,
);
push @Data, \%DefaultSetting;
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \@Data,
TTL => $Self->{CacheTTL},
);
return @Data;
}
=head2 ModifiedSettingAdd()
Add a new SysConfig modified entry.
my $ModifiedID = $SysConfigDBObject->ModifiedSettingAdd(
DefaultID => 456,
Name => "ProductName",
IsValid => 1, # 1 or 0, optional (uses the value from DefaultSetting if not defined)
UserModificationPossible => 0, # 1 or 0, optional (uses the value from DefaultSetting if not defined)
UserModificationActive => 0, # 1 or 0, optional (uses the value from DefaultSetting if not defined)
ResetToDefault => 0, # 1 or 0, optional, modified 0
EffectiveValue => $SettingEffectiveValue,
TargetUserID => 2, # Optional, ID of the user for which the modified setting is meant,
# leave it undef for global changes.
ExclusiveLockGUID => $LockingString, # the GUID used to lock the setting
DeploymentExclusiveLockGUID => $LockingString, # the GUID used to lock the deployment (in case of deployment failure)
UserID => 1,
);
Returns:
my $ModifiedID = 123; # false in case of an error
=cut
sub ModifiedSettingAdd {
my ( $Self, %Param ) = @_;
# Store params for further usage.
my %ModifiedVersionParams = %Param;
for my $Key (qw(DefaultID Name UserID)) {
if ( !defined $Param{$Key} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Key!",
);
return;
}
}
if ( !$Param{TargetUserID} && !$Param{ExclusiveLockGUID} && !$Param{DeploymentExclusiveLockGUID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need ExclusiveLockGUID or DeploymentExclusiveLockGUID!",
);
}
# Check duplicate name (with same TargetUserID).
my %ModifiedSetting = $Self->ModifiedSettingGet(
Name => $Param{Name},
TargetUserID => $Param{TargetUserID},
);
if (%ModifiedSetting) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "There is already a modified setting for this user (or global)!",
);
return;
}
# Check duplicate name.
my %DefaultSetting = $Self->DefaultSettingGet(
DefaultID => $Param{DefaultID},
);
if ( !%DefaultSetting ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "DefaultID is invalid!",
);
return;
}
if ( $Param{Name} ne $DefaultSetting{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Name doesn't match ('$Param{Name}')! It should be '$DefaultSetting{Name}'.",
);
return;
}
# Check we have not UserModificationActive if we have TargetUserID they are exclusive.
if ( defined $Param{UserModificationActive} && $Param{TargetUserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Could not set UserModificationActive on a user setting!",
);
return;
}
# Update params with DefaultSetting if not defined.
for my $Attribute (qw(UserModificationActive IsValid)) {
$Param{$Attribute} //= $DefaultSetting{$Attribute};
$Param{$Attribute} = $Param{$Attribute} ? 1 : 0;
}
# Is possible to disable UserModificationActive just if it is enabled on default.
if ( !$DefaultSetting{UserModificationPossible} && $Param{UserModificationActive} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Could not UserModificationActive if default setting prohibits!",
);
return;
}
# Serialize data as string.
$Param{EffectiveValue} = $Kernel::OM->Get('Kernel::System::YAML')->Dump(
Data => $Param{EffectiveValue},
);
# Set is dirty as enabled due it is a new setting.
my $IsDirty = 1;
$Param{ResetToDefault} = $Param{ResetToDefault} ? 1 : 0;
# Default should be locked.
my $LockedByUser = 1;
if ( !$Param{TargetUserID} ) {
$LockedByUser = $Self->DefaultSettingIsLockedByUser(
DefaultID => $Param{DefaultID},
ExclusiveLockUserID => $Param{UserID},
ExclusiveLockGUID => $Param{ExclusiveLockGUID},
);
}
# Check if we are on a deployment and a deleted value needs to be restored due an error
if ( !$LockedByUser && $Param{DeploymentExclusiveLockGUID} ) {
$LockedByUser = $Self->DeploymentIsLockedByUser(
ExclusiveLockGUID => $Param{DeploymentExclusiveLockGUID},
UserID => $Param{UserID},
);
}
if ( !$LockedByUser ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Default setting is not locked to this user!",
);
return;
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Insert the modified.
return if !$DBObject->Do(
SQL => '
INSERT INTO sysconfig_modified
(sysconfig_default_id, name, user_id, is_valid, user_modification_active,
effective_value, is_dirty, reset_to_default, create_time, create_by, change_time, change_by)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)',
Bind => [
\$Param{DefaultID}, \$Param{Name}, \$Param{TargetUserID}, \$Param{IsValid},
\$Param{UserModificationActive}, \$Param{EffectiveValue},
\$IsDirty, \$Param{ResetToDefault}, \$Param{UserID}, \$Param{UserID},
],
);
my $SQLSelect = 'SELECT id, effective_value FROM sysconfig_modified
WHERE sysconfig_default_id = ?
AND name = ?
AND is_dirty = ? ';
my @BindSelect = ( \$Param{DefaultID}, \$Param{Name}, \$IsDirty );
if ( $Param{TargetUserID} ) {
$SQLSelect .= "AND user_id = ? ";
push @BindSelect, \$Param{TargetUserID};
}
else {
$SQLSelect .= "AND user_id IS NULL ";
}
# Get modified ID.
$DBObject->Prepare(
SQL => $SQLSelect,
Bind => \@BindSelect,
Limit => 1,
);
# Fetch the modified setting ID.
my $ModifiedSettingID;
ROW:
while ( my @Row = $DBObject->FetchrowArray() ) {
next ROW if $Row[1] ne $Param{EffectiveValue};
$ModifiedSettingID = $Row[0];
}
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->CleanUp(
Type => 'SysConfigModified',
);
$CacheObject->Delete(
Type => 'SysConfigModifiedList',
Key => 'ModifiedSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigNavigation',
);
$CacheObject->CleanUp(
Type => 'SysConfigEntities',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
# Clean cache for setting translations.
my %Languages = %{ $Kernel::OM->Get('Kernel::Config')->Get('DefaultUsedLanguages') };
for my $Language ( sort keys %Languages ) {
$CacheObject->Delete(
Type => 'SysConfig',
Key => "SettingTranslatedGet::$Language" . "::$Param{Name}",
);
$CacheObject->Delete(
Type => 'SysConfig',
Key => "ConfigurationTranslatedGet::$Language",
);
}
# Unlock the setting.
my $IsUnlock = $Self->DefaultSettingUnlock(
DefaultID => $Param{DefaultID},
);
if ( !$IsUnlock ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Default setting with ID: $Param{DefaultID} was not possible to unlock!",
);
return;
}
return $ModifiedSettingID;
}
=head2 ModifiedSettingGet()
Get SysConfig modified value.
my %ModifiedSetting = $SysConfigDBObject->ModifiedSettingGet(
ModifiedID => 123, # ModifiedID or NAME are required.
Name => 'Setting::Name',
TargetUserID => 2, # The ID of the user for which the modified setting is meant,
# exclusive with IsGlobal.
IsGlobal => 1, # Define a search for settings don't belong an user,
# exclusive with TargetUserID.
);
Returns:
%ModifiedSetting = (
ModifiedID => "123",
DefaultID => 456,
Name => "ProductName",
IsGlobal => 1, # 1 or 0, optional
IsValid => 1, # 1 or 0, optional, modified 0
IsDirty => 1, # 1 or 0, optional, modified 0
ResetToDefault => 1, # 1 or 0, optional, modified 0
UserModificationActive => 0, # 1 or 0, optional, modified 0
EffectiveValue => $SettingEffectiveValue,
TargetUserID => 2, # ID of the user for which the modified setting is meant
CreateTime => "2016-05-29 11:04:04",
CreateBy => 1,
ChangeTime => "2016-05-29 11:04:04",
ChangeBy => 1,
SettingUID => 'Modified12320160529110404',
);
=cut
sub ModifiedSettingGet {
my ( $Self, %Param ) = @_;
if ( !$Param{ModifiedID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need ModifiedID or Name!',
);
return;
}
my $FieldName;
my $FieldValue;
if ( $Param{ModifiedID} ) {
# Set DefaultID as filter.
$FieldName = 'id';
$FieldValue = $Param{ModifiedID};
}
elsif ( $Param{Name} ) {
# Set Name as filter.
$FieldName = 'name';
$FieldValue = $Param{Name};
}
# IsGlobal and TargetUserID are exclusive each other.
if ( defined $Param{IsGlobal} && defined $Param{TargetUserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Use IsGlobal and TargetUserID at the same time is not allowed!",
);
return;
}
# Check optional settings.
for my $Item (qw(IsGlobal TargetUserID)) {
$Param{$Item} //= 0;
}
# Ff not defined TargetUserID it should be global.
if ( !$Param{TargetUserID} && $FieldName eq 'name' ) {
$Param{IsGlobal} = 1;
}
my $SQLExtra = '';
my @Bind = ( \$FieldValue );
# In case of global search user value is needed as null.
if ( $Param{IsGlobal} ) {
$SQLExtra = '
AND user_id IS NULL';
}
# Otherwise check effective user id.
elsif ( $Param{TargetUserID} ) {
$SQLExtra = "
AND user_id = ? ";
push @Bind, \$Param{TargetUserID};
}
my $CacheType = "SysConfigModified";
my $CacheKey = 'ModifiedSettingGet::' # this cache key gets more elements
. $FieldName . '::'
. $FieldValue . '::'
. $Param{IsGlobal} . '::'
. $Param{TargetUserID};
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return %{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my $SQL = '
SELECT id, sysconfig_default_id, name, user_id, is_valid, user_modification_active,
effective_value, is_dirty, reset_to_default, create_time, create_by, change_time, change_by
FROM sysconfig_modified
WHERE';
$SQL .= ' ' . $FieldName . ' = ?' . $SQLExtra;
$SQL .= '
ORDER BY id DESC';
# Get modified from database.
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Bind,
);
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
my %ModifiedSetting;
while ( my @Data = $DBObject->FetchrowArray() ) {
# De-serialize modified data.
my $EffectiveValue = $YAMLObject->Load( Data => $Data[6] );
my $TimeStamp = $Data[11];
$TimeStamp =~ s{:|-|[ ]}{}gmsx;
%ModifiedSetting = (
ModifiedID => $Data[0],
DefaultID => $Data[1],
Name => $Data[2],
TargetUserID => $Data[3],
IsValid => $Data[4],
UserModificationActive => $Data[5],
EffectiveValue => $EffectiveValue,
IsDirty => $Data[7] ? 1 : 0,
ResetToDefault => $Data[8] ? 1 : 0,
CreateTime => $Data[9],
CreateBy => $Data[10],
ChangeTime => $Data[11],
ChangeBy => $Data[12],
SettingUID => "Modified$Data[0]$TimeStamp",
);
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \%ModifiedSetting,
TTL => $Self->{CacheTTL},
);
return %ModifiedSetting;
}
=head2 ModifiedSettingListGet()
Get modified setting list with complete data.
my @List = $SysConfigDBObject->ModifiedSettingListGet(
IsInvisible => 1, # 1 or 0
IsReadonly => 0, # 1 or 0
IsRequired => 1, # 1 or 0
IsValid => 1, # 1 or 0
IsDirty => 1, # 1 or 0
ResetToDefault => 1, # 1 or 0
TargetUserID => 2, # the ID of the user for which the modified setting is meant,
# exclusive with IsGlobal.
IsGlobal => 1, # Define a search for settings don't belong an user,
# exclusive with TargetUserID.
HasConfigLevel => 0, # 1 or 0
UserModificationActive => 0, # 1 or 0
Name => 'ACL::CacheTTL', # setting name
ChangeBy => 123,
);
Returns:
@List = (
{
ModifiedID => 123,
Name => "ProductName",
Description => "Defines the name of the application ...",
Navigation => "ASimple::Path::Structure",
IsInvisible => 1,
IsReadonly => 0,
IsRequired => 1,
IsValid => 1,
ResetToDefault => 1, # 1 or 0
HasConfigLevel => 200,
UserModificationActive => 0, # 1 or 0
XMLContentRaw => "The XML structure as it is on the config file",
XMLContentParsed => "XML parsed to Perl",
EffectiveValue => "Product 6",
IsDirty => 1, # 1 or 0
ExclusiveLockGUID => 'A32CHARACTERLONGSTRINGFORLOCKING',
ExclusiveLockUserID => 1,
ExclusiveLockExpiryTime => '2016-05-29 11:09:04',
CreateTime => "2016-05-29 11:04:04",
ChangeTime => "2016-05-29 11:04:04",
},
{
ModifiedID => 321,
Name => 'FieldName',
# ...
CreateTime => '2010-09-11 10:08:00',
ChangeTime => '2011-01-01 01:01:01',
},
# ...
);
=cut
sub ModifiedSettingListGet {
my ( $Self, %Param ) = @_;
# IsGlobal and TargetUserID are exclusive each other.
if ( defined $Param{IsGlobal} && defined $Param{TargetUserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Use IsGlobal and TargetUserID at the same time is not allowed!",
);
return;
}
my @Filters;
my @Bind;
my $CacheType = 'SysConfigModifiedList';
my $CacheKey = 'ModifiedSettingList';
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
my @DataRaw;
if ( ref $Cache eq 'ARRAY' ) {
@DataRaw = @{$Cache};
}
else {
my $SQL = '
SELECT id, sysconfig_default_id, name, user_id, is_valid, user_modification_active,
effective_value, is_dirty, reset_to_default, create_time, create_by, change_time, change_by
FROM sysconfig_modified';
$SQL .= ' ORDER BY id';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Get modified from database.
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Bind,
);
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
while ( my @Row = $DBObject->FetchrowArray() ) {
# De-serialize modified data.
my $EffectiveValue = $YAMLObject->Load( Data => $Row[6] );
my $TimeStamp = $Row[11];
$TimeStamp =~ s{:|-|[ ]}{}gmsx;
my %ModifiedSetting = (
ModifiedID => $Row[0],
DefaultID => $Row[1],
Name => $Row[2],
TargetUserID => $Row[3],
IsValid => $Row[4],
UserModificationActive => $Row[5],
EffectiveValue => $EffectiveValue,
IsDirty => $Row[7] ? 1 : 0,
ResetToDefault => $Row[8] ? 1 : 0,
CreateTime => $Row[9],
CreateBy => $Row[10],
ChangeTime => $Row[11],
ChangeBy => $Row[12],
SettingUID => "Modified$Row[0]$TimeStamp",
);
push @DataRaw, \%ModifiedSetting;
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \@DataRaw,
TTL => $Self->{CacheTTL},
);
}
# Copy DataRaw to prevent modifications to in memory cache.
my @Data = @DataRaw;
if ( defined $Param{IsInvisible} ) {
@Data = grep { $_->{IsInvisible} eq $Param{IsInvisible} } @Data;
}
if ( defined $Param{IsReadonly} ) {
@Data = grep { $_->{IsReadonly} eq $Param{IsReadonly} } @Data;
}
if ( defined $Param{IsRequired} ) {
@Data = grep { $_->{IsRequired} eq $Param{IsRequired} } @Data;
}
if ( defined $Param{IsValid} ) {
@Data = grep { $_->{IsValid} eq $Param{IsValid} } @Data;
}
if ( defined $Param{IsDirty} ) {
@Data = grep { $_->{IsDirty} eq $Param{IsDirty} } @Data;
}
if ( defined $Param{HasConfigLevel} ) {
@Data = grep { $_->{HasConfigLevel} eq $Param{HasConfigLevel} } @Data;
}
if ( defined $Param{UserModificationActive} ) {
@Data = grep { $_->{UserModificationActive} eq $Param{UserModificationActive} } @Data;
}
if ( defined $Param{Name} ) {
@Data = grep { $_->{Name} eq $Param{Name} } @Data;
}
if ( defined $Param{TargetUserID} ) {
@Data = grep { $_->{TargetUserID} && $_->{TargetUserID} eq $Param{TargetUserID} } @Data;
}
if ( defined $Param{ChangeBy} ) {
@Data = grep { $_->{ChangeBy} eq $Param{ChangeBy} } @Data;
}
if ( defined $Param{Locked} ) {
if ( $Param{Locked} ) {
@Data = grep { $_->{ExclusiveLockGUID} } @Data;
}
else {
@Data = grep { !$_->{ExclusiveLockGUID} } @Data;
}
}
if ( $Param{IsGlobal} ) {
@Data = grep { !$_->{TargetUserID} } @Data;
}
return @Data;
}
=head2 ModifiedSettingDelete()
Delete a modified setting from list.
my $Success = $SysConfigDBObject->ModifiedSettingDelete(
ModifiedID => 123,
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub ModifiedSettingDelete {
my ( $Self, %Param ) = @_;
if ( !$Param{ModifiedID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need ModifiedID!',
);
return;
}
my %ModifiedSetting = $Self->ModifiedSettingGet(
ModifiedID => $Param{ModifiedID},
);
return if !IsHashRefWithData( \%ModifiedSetting );
# Delete modified from the list.
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => 'DELETE FROM sysconfig_modified WHERE id = ?',
Bind => [ \$Param{ModifiedID} ],
);
for my $Item (qw(0 1)) {
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigModified',
Key => 'ModifiedSettingGet::id::'
. $ModifiedSetting{ModifiedID} . '::'
. $Item . '::0',
);
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigModified',
Key => 'ModifiedSettingGet::name::'
. $ModifiedSetting{Name} . '::'
. $Item . '::0',
);
}
if ( $ModifiedSetting{TargetUserID} ) {
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigModified',
Key => 'ModifiedSettingGet::id::'
. $ModifiedSetting{ModifiedID} . '::0::'
. $ModifiedSetting{TargetUserID},
);
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigModified',
Key => 'ModifiedSettingGet::name::'
. $ModifiedSetting{Name} . '::0::'
. $ModifiedSetting{TargetUserID},
);
}
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->Delete(
Type => 'SysConfigModifiedList',
Key => 'ModifiedSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigNavigation',
);
$CacheObject->CleanUp(
Type => 'SysConfigEntities',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
# Clean cache for setting translations.
my %Languages = %{ $Kernel::OM->Get('Kernel::Config')->Get('DefaultUsedLanguages') };
for my $Language ( sort keys %Languages ) {
$CacheObject->Delete(
Type => 'SysConfig',
Key => "SettingTranslatedGet::$Language" . "::$ModifiedSetting{Name}",
);
$CacheObject->Delete(
Type => 'SysConfig',
Key => "ConfigurationTranslatedGet::$Language",
);
}
return 1;
}
=head2 ModifiedSettingUpdate()
Update SysConfig modified.
my $Success = $SysConfigDBObject->ModifiedSettingUpdate(
ModifiedID => 123, # (required)
DefaultID => 456, # (required)
Name => "ProductName", # (required)
IsValid => 1, # (optional) 1 or 0, optional (uses the value from DefaultSetting if not defined)
IsDirty => 1, # (optional) Default 1.
ResetToDefault => 1, # (optional), default 0
UserModificationActive => 1, # (optional) 1 or 0 (uses the value from DefaultSetting if not defined)
EffectiveValue => $SettingEffectiveValue,
TargetUserID => 2, # (optional), ID of the user for which the modified setting is meant,
# leave it undef for global changes.
ExclusiveLockGUID => $LockingString, # the GUID used to locking the setting
UserID => 1, # (required)
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub ModifiedSettingUpdate {
my ( $Self, %Param ) = @_;
# Store params for further usage.
my %ModifiedVersionParams = %Param;
for my $Key (qw(ModifiedID DefaultID Name EffectiveValue UserID)) {
if ( !defined $Param{$Key} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Key!",
);
return;
}
}
# Set is dirty to 1 if not defined.
$Param{IsDirty} //= 1;
# Get modified setting.
my %ModifiedSetting = $Self->ModifiedSettingGet(
ModifiedID => $Param{ModifiedID},
);
# Check if we really need to update.
my $IsDifferent = 0;
for my $Key (qw(ModifiedID DefaultID Name IsValid EffectiveValue UserModificationActive)) {
my $DataIsDifferent = DataIsDifferent(
Data1 => $Param{$Key},
Data2 => $ModifiedSetting{$Key},
);
if ($DataIsDifferent) {
$IsDifferent = 1;
}
}
if ( $ModifiedSetting{IsDirty} != $Param{IsDirty} ) {
$IsDifferent = 1;
}
return 1 if !$IsDifferent;
# Retrieve default setting.
my %DefaultSetting = $Self->DefaultSettingGet(
DefaultID => $Param{DefaultID},
);
if ( !%DefaultSetting ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "DefaultID is invalid!",
);
return;
}
if ( $Param{Name} ne $DefaultSetting{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Name is Invalid!",
);
return;
}
# Check we have not UserModificationActive if we have TargetUserID they are exclusive
if ( defined $Param{UserModificationActive} && $Param{TargetUserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Could not set UserModificationActive on a user setting!",
);
return;
}
# Update params with DefaultSetting if not defined.
for my $Attribute (qw(UserModificationActive IsValid)) {
$Param{$Attribute} //= $DefaultSetting{$Attribute};
$Param{$Attribute} = $Param{$Attribute} ? 1 : 0;
}
# Is possible to disable UserModificationActive just if it is enabled on default.
if ( !$DefaultSetting{UserModificationPossible} && $Param{UserModificationActive} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Could not UserModificationActive if default setting prohibits!",
);
return;
}
# Serialize data as string.
$Param{EffectiveValue} = $Kernel::OM->Get('Kernel::System::YAML')->Dump(
Data => $Param{EffectiveValue},
);
$Param{ResetToDefault} = $Param{ResetToDefault} ? 1 : 0;
# Default should be locked.
my $LockedByUser = 1;
if ( !$Param{UserID} ) {
$LockedByUser = $Self->DefaultSettingIsLockedByUser(
DefaultID => $Param{DefaultID},
ExclusiveLockUserID => $Param{UserID},
ExclusiveLockGUID => $Param{ExclusiveLockGUID},
);
}
if ( !$LockedByUser ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Default setting is not locked to this user!",
);
return;
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Insert the modified.
return if !$DBObject->Do(
SQL => '
UPDATE sysconfig_modified
SET sysconfig_default_id = ?, name = ?, is_valid = ?, user_modification_active = ?,
effective_value = ?, is_dirty = ?, reset_to_default = ?, change_time = current_timestamp, change_by = ?
WHERE id = ?',
Bind => [
\$Param{DefaultID}, \$Param{Name}, \$Param{IsValid}, \$Param{UserModificationActive},
\$Param{EffectiveValue}, \$Param{IsDirty}, \$Param{ResetToDefault},
\$Param{UserID}, \$Param{ModifiedID},
],
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->CleanUp(
Type => 'SysConfigModified',
);
$CacheObject->Delete(
Type => 'SysConfigModifiedList',
Key => 'ModifiedSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigNavigation',
);
$CacheObject->CleanUp(
Type => 'SysConfigEntities',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
# Clean cache for setting translations.
my %Languages = %{ $Kernel::OM->Get('Kernel::Config')->Get('DefaultUsedLanguages') };
for my $Language ( sort keys %Languages ) {
$CacheObject->Delete(
Type => 'SysConfig',
Key => "SettingTranslatedGet::$Language" . "::$Param{Name}",
);
$CacheObject->Delete(
Type => 'SysConfig',
Key => "ConfigurationTranslatedGet::$Language",
);
}
return 1;
}
=head2 ModifiedSettingDirtyCleanUp()
Removes the IsDirty flag from modified settings.
my $Success = $SysConfigDBObject->ModifiedSettingDirtyCleanUp(
TargetUserID => 123, # (optional)
ModifiedIDs => [ # (optional) applies to only this list of settings
123,
456,
],
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub ModifiedSettingDirtyCleanUp {
my ( $Self, %Param ) = @_;
if ( defined $Param{TargetUserID} && !IsPositiveInteger( $Param{TargetUserID} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "TargetUserID is invalid",
);
return;
}
if ( defined $Param{ModifiedIDs} && !IsArrayRefWithData( $Param{ModifiedIDs} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "ModifiedIDs is invalid",
);
return;
}
# Define common SQL.
my $SQL = '
UPDATE sysconfig_modified
SET is_dirty = 0
WHERE is_dirty = 1';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
if ( $Param{ModifiedIDs} ) {
my $ModifiedIDsStrg = join ',', map { $DBObject->Quote( $_, 'Integer' ) } @{ $Param{ModifiedIDs} };
$SQL .= "
AND id IN ($ModifiedIDsStrg)";
}
my @Bind;
# Define user condition.
my $UserCondition = '
AND user_id IS NULL';
if ( $Param{TargetUserID} ) {
$UserCondition = '
AND user_id = ?';
push @Bind, \$Param{TargetUserID};
}
# Remove is dirty flag for modified settings.
return if !$DBObject->Do(
SQL => $SQL . $UserCondition,
Bind => \@Bind,
);
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
$CacheObject->CleanUp(
Type => 'SysConfigModified',
);
$CacheObject->Delete(
Type => 'SysConfigModifiedList',
Key => 'ModifiedSettingList',
);
$CacheObject->CleanUp(
Type => 'SysConfigModifiedVersion',
);
$CacheObject->CleanUp(
Type => 'SysConfigIsDirty',
);
return 1;
}
=head2 ModifiedSettingVersionAdd()
Add a new SysConfig modified version entry.
my $ModifiedVersionID = $SysConfigDBObject->ModifiedSettingVersionAdd(
DefaultVersionID => 456,
Name => "ProductName",
IsValid => 1, # 1 or 0, optional, optional 0
UserModificationActive => 0, # 1 or 0, optional, optional 0
TargetUserID => 2, # The ID of the user for which the modified setting is meant,
# leave it undef for global changes.
EffectiveValue => $SettingEffectiveValue, # the value as will be stored in the Perl configuration file
DeploymentTimeStamp => '2015-12-12 12:00:00', # unique timestamp per deployment
ResetToDefault => 1, # optional, default 0
UserID => 1,
);
Returns:
my $ModifiedVersionID = 123; # false in case of an error
=cut
sub ModifiedSettingVersionAdd {
my ( $Self, %Param ) = @_;
for my $Key (
qw(DefaultVersionID Name EffectiveValue DeploymentTimeStamp UserID)
)
{
if ( !defined $Param{$Key} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Key!",
);
return;
}
}
# Check boolean parameters, set 0 as default value).
for my $Key (qw(IsValid UserModificationActive ResetToDefault)) {
$Param{$Key} = ( defined $Param{$Key} && $Param{$Key} ? 1 : 0 );
}
# Serialize data as string.
$Param{EffectiveValue} = $Kernel::OM->Get('Kernel::System::YAML')->Dump(
Data => $Param{EffectiveValue},
);
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Insert the modified.
return if !$DBObject->Do(
SQL => '
INSERT INTO sysconfig_modified_version
(sysconfig_default_version_id, name, user_id, is_valid, reset_to_default,
user_modification_active, effective_value, create_time, create_by,
change_time, change_by)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
Bind => [
\$Param{DefaultVersionID}, \$Param{Name}, \$Param{TargetUserID}, \$Param{IsValid},
\$Param{ResetToDefault}, \$Param{UserModificationActive},
\$Param{EffectiveValue}, \$Param{DeploymentTimeStamp}, \$Param{UserID},
\$Param{DeploymentTimeStamp}, \$Param{UserID},
],
);
# Get modified ID.
$DBObject->Prepare(
SQL => '
SELECT id
FROM sysconfig_modified_version
WHERE sysconfig_default_version_id =?
AND name = ?
ORDER BY id DESC',
Bind => [ \$Param{DefaultVersionID}, \$Param{Name} ],
Limit => 1,
);
# Fetch the modified setting ID
my $ModifiedVersionID;
while ( my @Row = $DBObject->FetchrowArray() ) {
$ModifiedVersionID = $Row[0];
}
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => 'SysConfigModifiedVersion',
);
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => 'SysConfigModifiedVersionList',
);
return $ModifiedVersionID;
}
=head2 ModifiedSettingVersionGet()
Get SysConfig modified version entry.
my %ModifiedSettingVersion = $SysConfigDBObject->ModifiedSettingVersionGet(
ModifiedVersionID => 123,
);
Returns:
%ModifiedSetting = (
ModifiedVersionID => 123,
DefaultVersionID => 456,
Name => "ProductName",
TargetUserID => 123,
IsValid => 1, # 1 or 0
ResetToDefault => 1, # 1 or 0
UserModificationActive => 0, # 1 or 0
EffectiveValue => "Product 6",
CreateTime => "2016-05-29 11:04:04",
ChangeTime => "2016-05-29 11:04:04",
);
=cut
sub ModifiedSettingVersionGet {
my ( $Self, %Param ) = @_;
if ( !$Param{ModifiedVersionID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need ModifiedVersionID!',
);
return;
}
my $CacheType = "SysConfigModifiedVersion";
my $CacheKey = 'ModifiedSettingVersionGet::' . $Param{ModifiedVersionID};
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return %{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Get modified from database.
return if !$DBObject->Prepare(
SQL => '
SELECT smv.id, smv.sysconfig_default_version_id, sdv.sysconfig_default_id, sm.id,
smv.name, smv.user_id,
smv.is_valid, smv.reset_to_default, smv.user_modification_active, smv.effective_value,
smv.create_time, smv.change_time
FROM sysconfig_modified_version smv
LEFT JOIN sysconfig_default_version sdv
ON smv.sysconfig_default_version_id = sdv.id
LEFT JOIN sysconfig_modified sm
ON sdv.sysconfig_default_id = sm.sysconfig_default_id
WHERE smv.id = ?',
Bind => [ \$Param{ModifiedVersionID} ],
);
my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML');
my %ModifiedSettingVersion;
while ( my @Data = $DBObject->FetchrowArray() ) {
# De-serialize modified data.
my $EffectiveValue = $YAMLObject->Load( Data => $Data[9] );
%ModifiedSettingVersion = (
ModifiedVersionID => $Data[0],
DefaultVersionID => $Data[1],
DefaultID => $Data[2],
ModifiedID => $Data[3],
Name => $Data[4],
TargetUserID => $Data[5],
IsValid => $Data[6],
ResetToDefault => $Data[7] ? 1 : 0,
UserModificationActive => $Data[8],
EffectiveValue => $EffectiveValue,
DeploymentTimeStamp => $Data[10],
CreateTime => $Data[10],
ChangeTime => $Data[11],
);
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \%ModifiedSettingVersion,
TTL => $Self->{CacheTTL},
);
return %ModifiedSettingVersion;
}
=head2 ModifiedSettingVersionListGet()
Get version setting list with complete data.
my @List = $SysConfigDBObject->ModifiedSettingVersionListGet(
Name => 1, # optional
DefaultVersionID => 230, # optional
);
Returns:
@List = (
{
ModifiedVersionID => 123,
ModifiedID => 456,
Name => "ProductName",
TargetUserID => 78,
IsValid => 1, # 1 or 0
ResetToDefault => 1, # 1 or 0
UserModificationActive => 0, # 1 or 0
EffectiveValue => "Product 6",
CreateTime => "2016-05-29 11:04:04",
ChangeTime => "2016-05-29 11:04:04",
},
{
ModifiedVersionID => 789,
ModifiedID => 579,
Name => "ADifferentProductName",
TargetUserID => 909,
IsValid => 1, # 1 or 0
ResetToDefault => 1, # 1 or 0
UserModificationActive => 0, # 1 or 0
. . .
},
# ...
);
=cut
sub ModifiedSettingVersionListGet {
my ( $Self, %Param ) = @_;
if ( !$Param{DefaultVersionID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need DefaultVersionID or Name!',
);
return;
}
my $FieldName;
my $FieldValue;
my $FieldCache;
if ( $Param{DefaultVersionID} ) {
# Set conditions for modified ID.
$FieldName = 'sysconfig_default_version_id';
$FieldValue = $Param{DefaultVersionID};
$FieldCache = 'DefaultVersionID';
}
elsif ( $Param{Name} ) {
# Set conditions for name.
$FieldName = 'name';
$FieldValue = $Param{Name};
$FieldCache = 'Name';
}
# Loop over filters and set them on SQL and cache key.
my $SQLFilter = "WHERE $FieldName = '$FieldValue' ";
my $CacheType = 'SysConfigModifiedVersionList';
my $CacheKey = 'ModifiedSettingVersionList::' . $FieldCache . '=' . $FieldValue;
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return @{$Cache} if ref $Cache eq 'ARRAY';
# Start SQL statement.
my $SQL = '
SELECT id, name
FROM sysconfig_modified_version';
$SQL .= ' ' . $SQLFilter . ' ORDER BY id DESC';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my @Data;
return if !$DBObject->Prepare(
SQL => $SQL,
);
my @ModifiedVersionIDs;
while ( my @Row = $DBObject->FetchrowArray() ) {
push @ModifiedVersionIDs, $Row[0];
}
# Get modified settings.
ITEMID:
for my $ItemID (@ModifiedVersionIDs) {
my %ModifiedSetting = $Self->ModifiedSettingVersionGet(
ModifiedVersionID => $ItemID,
);
next ITEMID if !%ModifiedSetting;
push @Data, \%ModifiedSetting;
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \@Data,
TTL => $Self->{CacheTTL},
);
return @Data;
}
=head2 ModifiedSettingVersionGetLast()
Get last deployment.
my %ModifiedSettingVersion = $SysConfigDBObject->ModifiedSettingVersionGetLast(
Name => 'ProductName',
);
Returns:
%ModifiedSettingVersion = (
DefaultVersionID => 123,
ModifiedID => 456,
Name => "ProductName",
TargetUserID => 45,
IsValid => 1, # 1 or 0
ResetToDefault => 1, # 1 or 0
UserModificationActive => 0, # 1 or 0
EffectiveValue => "Product 6",
CreateTime => "2016-05-29 11:04:04",
ChangeTime => "2016-05-29 11:04:04",
);
=cut
sub ModifiedSettingVersionGetLast {
my ( $Self, %Param ) = @_;
if ( !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need Name!',
);
return;
}
my $CacheType = 'SysConfigModifiedVersion';
my $CacheKey = 'ModifiedSettingVersionGetLast::' . $Param{Name};
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return %{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
return if !$DBObject->Prepare(
SQL => 'SELECT MAX(id) FROM sysconfig_modified_version WHERE name = ?',
Bind => [ \$Param{Name} ],
);
my $ModifiedVersionID;
while ( my @Row = $DBObject->FetchrowArray() ) {
$ModifiedVersionID = $Row[0];
}
return if !$ModifiedVersionID;
my %ModifiedSetting = $Self->ModifiedSettingVersionGet(
ModifiedVersionID => $ModifiedVersionID,
);
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \%ModifiedSetting,
TTL => $Self->{CacheTTL},
);
return %ModifiedSetting;
}
=head2 ModifiedSettingVersionListGetLast()
Get a list of the last deployed version of each modified SysConfig setting
my @List = $SysConfigDBObject->ModifiedSettingVersionListGetLast();
Returns:
@List = (
{
ModifiedVersionID => 123,
ModifiedID => 456,
Name => "ProductName",
TargetUserID => 78,
IsValid => 1, # 1 or 0
ResetToDefault => 1, # 1 or 0
UserModificationActive => 0, # 1 or 0
EffectiveValue => "Product 6",
CreateTime => "2016-05-29 11:04:04",
ChangeTime => "2016-05-29 11:04:04",
},
{
ModifiedVersionID => 789,
ModifiedID => 579,
Name => "ADifferentProductName",
TargetUserID => 909,
IsValid => 1, # 1 or 0
ResetToDefault => 1, # 1 or 0
UserModificationActive => 0, # 1 or 0
. . .
},
# ...
);
=cut
sub ModifiedSettingVersionListGetLast {
my ( $Self, %Param ) = @_;
my $CacheType = 'SysConfigModifiedVersionList';
my $CacheKey = 'ModifiedSettingVersionListGetLast';
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return @{$Cache} if ref $Cache eq 'ARRAY';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my @Data;
return if !$DBObject->Prepare(
SQL => '
SELECT MAX(id), sysconfig_default_version_id
FROM sysconfig_modified_version
GROUP BY sysconfig_default_version_id
ORDER BY sysconfig_default_version_id ASC'
);
my @ModifiedVersionIDs;
while ( my @Row = $DBObject->FetchrowArray() ) {
push @ModifiedVersionIDs, $Row[0];
}
# Get modified settings.
for my $ItemID (@ModifiedVersionIDs) {
my %ModifiedSetting = $Self->ModifiedSettingVersionGet(
ModifiedVersionID => $ItemID,
);
push @Data, \%ModifiedSetting;
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \@Data,
TTL => $Self->{CacheTTL},
);
return @Data;
}
=head2 ModifiedSettingVersionDelete()
Delete a modified setting version from list based on modified version ID or modified ID.
my $Success = $SysConfigDBObject->ModifiedSettingVersionDelete(
ModifiedVersionID => 123,
);
or
my $Success = $SysConfigDBObject->ModifiedSettingVersionDelete(
ModifiedID => 45,
);
or
my $Success = $SysConfigDBObject->ModifiedSettingVersionDelete(
Name => 'AnyName',
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub ModifiedSettingVersionDelete {
my ( $Self, %Param ) = @_;
if ( !$Param{ModifiedVersionID} && !$Param{ModifiedID} && !$Param{Name} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need ID, ModifiedID or Name!',
);
return;
}
my $FieldName;
my $FieldValue;
if ( $Param{ModifiedVersionID} ) {
# Set conditions for ID.
$FieldName = 'id';
$FieldValue = $Param{ModifiedVersionID};
}
elsif ( $Param{DefaultVersionID} ) {
# Set conditions for default version id.
$FieldName = 'sysconfig_default_version_id';
$FieldValue = $Param{DefaultVersionID};
}
elsif ( $Param{Name} ) {
# Set conditions for name.
$FieldName = 'name';
$FieldValue = $Param{Name};
}
# Delete modified from the list.
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => 'DELETE FROM sysconfig_modified_version WHERE ' . $FieldName . ' = ?',
Bind => [ \$FieldValue ],
);
if ( $FieldName eq 'id' ) {
my %ModifiedVersionSetting = $Self->ModifiedSettingVersionGet(
ModifiedVersionID => $FieldValue,
);
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigModifiedVersion',
Key => 'ModifiedSettingVersionGet::' . $FieldValue,
);
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigModifiedVersion',
Key => 'ModifiedSettingVersionGetLast::' . $ModifiedVersionSetting{DefaultVersionID},
);
}
else {
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => 'SysConfigModifiedVersion',
);
}
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
Type => 'SysConfigModifiedVersionList',
);
return 1;
}
=head2 ConfigurationIsDirty()
Check if there are not deployed changes on system configuration.
my $Result = $SysConfigDBObject->ConfigurationIsDirty(
UserID => 123, # optional, the user that changes a modified setting
);
Returns:
$Result = 1; # or 0 if configuration is not dirty.
=cut
sub ConfigurationIsDirty {
my ( $Self, %Param ) = @_;
my $CacheType = 'SysConfigIsDirty';
my $CacheKey = 'IsDirty';
if ( $Param{UserID} ) {
$CacheKey .= "::UserID=$Param{UserID}";
}
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return ${$Cache} if ref $Cache eq 'SCALAR';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my $SQL = '
SELECT sd.id
FROM sysconfig_default sd
LEFT OUTER JOIN sysconfig_modified sm ON sm.name = sd.name
WHERE ';
my $SQLWhere = 'sd.is_dirty = 1 OR (sm.user_id IS NULL AND sm.is_dirty = 1)';
my @Bind;
if ( $Param{UserID} ) {
$SQLWhere = 'sd.is_dirty = 1 OR (sm.user_id IS NULL AND sm.is_dirty = 1 AND sm.change_by = ? )';
push @Bind, \$Param{UserID};
}
$SQL .= $SQLWhere;
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Bind,
Limit => 1,
);
my $Result;
while ( my @Row = $DBObject->FetchrowArray() ) {
$Result = 1;
}
$Result //= '0';
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \$Result,
TTL => $Self->{CacheTTL},
);
return $Result;
}
=head2 DeploymentAdd()
Adds a new deployment.
my $DeploymentID = $SysConfigDBObject->DeploymentAdd(
Comments => 'Some Comments', # optional
EffectiveValueStrg => $EffectiveValuesStrgRef, # string reference with the value of all settings,
# to be stored in a Perl cache file
TargetUserID => 123, # to deploy only user specific settings
ExclusiveLockGUID => $LockingString, # the GUID used to locking the deployment,
# not needed if TargetUserID is used
DeploymentTimeStamp => '1977-12-12 12:00:00',
UserID => 123,
);
Returns:
$DeploymentID = 123; # or false in case of an error
=cut
sub DeploymentAdd {
my ( $Self, %Param ) = @_;
for my $Key (qw(UserID DeploymentTimeStamp)) {
if ( !$Param{$Key} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Key!",
);
return;
}
}
if ( !defined $Param{EffectiveValueStrg} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need EffectiveValueStrg!"
);
return;
}
if ( !$Param{TargetUserID} && !$Param{ExclusiveLockGUID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need ExclusiveLockGUID",
);
}
if ( ref $Param{EffectiveValueStrg} ne 'SCALAR' || !IsStringWithData( ${ $Param{EffectiveValueStrg} } ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "EffectiveValueStrg is invalid!",
);
return;
}
if ( exists $Param{TargetUserID} && !$Param{TargetUserID} ) {
delete $Param{TargetUserID};
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my @UserDeploymentIDs;
if ( $Param{TargetUserID} ) {
# Remember previous user deployments.
return if !$DBObject->Prepare(
SQL => '
SELECT id
FROM sysconfig_deployment
WHERE user_id = ?',
Bind => [ \$Param{TargetUserID}, ],
);
while ( my @Row = $DBObject->FetchrowArray() ) {
push @UserDeploymentIDs, $Row[0];
}
}
else {
my $ExclusiveLockGUID = $Self->DeploymentIsLockedByUser(
ExclusiveLockGUID => $Param{ExclusiveLockGUID},
UserID => $Param{UserID},
);
if ( !$ExclusiveLockGUID ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Deployment is not locked to this user!",
);
return;
}
}
my $UID = 'OTRSInvalid-' . $Self->_GetUID();
# Create a deployment record without the real comments.
return if !$DBObject->Do(
SQL => '
INSERT INTO sysconfig_deployment
(comments, effective_value, user_id, create_time, create_by)
VALUES
(?, ?, ?, ?, ?)',
Bind => [
\$UID, \${ $Param{EffectiveValueStrg} }, \$Param{TargetUserID}, \$Param{DeploymentTimeStamp},
\$Param{UserID},
],
);
# Get deployment ID.
my $SQL = '
SELECT id
FROM sysconfig_deployment
WHERE comments = ?
AND create_by = ?';
my @Bind = ( \$UID, \$Param{UserID} );
if ( $Param{TargetUserID} ) {
$SQL .= '
AND user_id = ?
';
push @Bind, \$Param{TargetUserID};
}
else {
$SQL .= '
AND user_id IS NULL
';
}
$SQL .= '
ORDER BY id DESC';
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => \@Bind,
Limit => 1,
);
# Fetch the deployment ID.
my $DeploymentID;
while ( my @Row = $DBObject->FetchrowArray() ) {
$DeploymentID = $Row[0];
}
my $CurrentDeploymentIDStr = 'CurrentDeploymentID';
if ( $Param{TargetUserID} ) {
$CurrentDeploymentIDStr = 'CurrentUserDeploymentID';
}
# Add the deployment ID to the values
${ $Param{EffectiveValueStrg} }
=~ s{( \s+ my [ ] \(\$File, [ ] \$Self\) [ ] = [ ] \@_; \s+ )}{$1\$Self->{'$CurrentDeploymentIDStr'} = '$DeploymentID';\n}msx;
# Set the real deployment value.
return if !$DBObject->Do(
SQL => '
Update sysconfig_deployment
SET comments = ?, effective_value = ?
WHERE id = ?',
Bind => [
\$Param{Comments}, \${ $Param{EffectiveValueStrg} }, \$DeploymentID,
],
);
# Remove previous user deployments (if any).
for my $DeploymentID (@UserDeploymentIDs) {
$Self->DeploymentDelete(
DeploymentID => $DeploymentID,
);
}
if ( $Param{TargetUserID} ) {
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigDeployment',
Key => 'DeploymentUserList',
);
}
else {
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigDeployment',
Key => 'DeploymentList',
);
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigDeployment',
Key => 'DeploymentGetLast',
);
}
return $DeploymentID;
}
=head2 DeploymentGet()
Gets deployment information.
my %Deployment = $SysConfigDBObject->DeploymentGet(
DeploymentID => 123,
Valid => 1, # optional (this is deprecated and will be removed in next mayor release).
);
Returns:
%Deployment = (
DeploymentID => 123,
Comments => 'Some Comments',
EffectiveValueStrg => $SettingEffectiveValues, # string with the value of all settings,
# as seen in the Perl configuration file.
TargetUserID => 123, # optional (only in case of user specific deployments).
CreateTime => "2016-05-29 11:04:04",
CreateBy => 123,
);
=cut
sub DeploymentGet {
my ( $Self, %Param ) = @_;
if ( !$Param{DeploymentID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need DeploymentID!",
);
return;
}
my $CacheType = "SysConfigDeployment";
my $CacheKey = 'DeploymentGet::DeploymentID::' . $Param{DeploymentID};
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => $CacheType,
Key => $CacheKey,
);
return %{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Get deployment from database.
return if !$DBObject->Prepare(
SQL => '
SELECT id, comments, effective_value, user_id, create_time, create_by
FROM sysconfig_deployment
WHERE id = ?',
Bind => [ \$Param{DeploymentID} ],
);
my %Deployment;
while ( my @Data = $DBObject->FetchrowArray() ) {
%Deployment = (
DeploymentID => $Data[0],
Comments => $Data[1],
EffectiveValueStrg => $Data[2],
TargetUserID => $Data[3],
CreateTime => $Data[4],
CreateBy => $Data[5],
);
}
return if !%Deployment;
my $Valid = defined $Param{Valid} ? $Param{Valid} : 1;
if ( $Deployment{EffectiveValueStrg} eq 'Invalid' && $Valid ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "The Deployment $Param{DeploymentID} is invalid!",
);
return;
}
$CacheObject->Set(
Type => $CacheType,
Key => $CacheKey,
Value => \%Deployment,
TTL => $Self->{CacheTTL},
);
return %Deployment;
}
=head2 DeploymentListGet()
Get global deployment list with complete data.
my @List = $SysConfigDBObject->DeploymentListGet();
Returns:
@List = (
{
DeploymentID => 123,
Comments => 'Some Comments',
EffectiveValueStrg => $SettingEffectiveValues, # String with the value of all settings,
# as seen in the Perl configuration file.
CreateTime => "2016-05-29 11:04:04",
CreateBy => 123,
},
{
DeploymentID => 456,
Comments => 'Some Comments',
EffectiveValueStrg => $SettingEffectiveValues2, # String with the value of all settings,
# as seen in the Perl configuration file.
CreateTime => "2016-05-29 12:00:01",
CreateBy => 123,
},
# ...
);
=cut
sub DeploymentListGet {
my ( $Self, %Param ) = @_;
my $CacheKey = 'DeploymentList';
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => 'SysConfigDeployment',
Key => $CacheKey,
);
return @{$Cache} if ref $Cache eq 'ARRAY';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my @Data;
return if !$DBObject->Prepare(
SQL => '
SELECT id
FROM sysconfig_deployment
WHERE user_id IS NULL
ORDER BY id DESC',
);
my @DeploymentIDs;
while ( my @Row = $DBObject->FetchrowArray() ) {
push @DeploymentIDs, $Row[0];
}
# Get deployments.
for my $ItemID (@DeploymentIDs) {
my %Deployment = $Self->DeploymentGet(
DeploymentID => $ItemID,
);
push @Data, \%Deployment;
}
$CacheObject->Set(
Type => 'SysConfigDeployment',
Key => $CacheKey,
Value => \@Data,
TTL => $Self->{CacheTTL},
);
return @Data;
}
=head2 DeploymentUserList()
Get DeploymentID -> UserID list of all user deployments.
my %List = $SysConfigDBObject->DeploymentUserList();
Returns:
%List = {
9876 => 123,
5432 => 456,
# ...
};
=cut
sub DeploymentUserList {
my ( $Self, %Param ) = @_;
my $CacheKey = 'DeploymentUserList';
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => 'SysConfigDeployment',
Key => $CacheKey,
);
return @{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my @Data;
return if !$DBObject->Prepare(
SQL => '
SELECT id, user_id
FROM sysconfig_deployment
WHERE user_id IS NOT NULL
ORDER BY id DESC',
);
my %Data;
while ( my @Row = $DBObject->FetchrowArray() ) {
$Data{ $Row[0] } = $Row[1];
}
$CacheObject->Set(
Type => 'SysConfigDeployment',
Key => $CacheKey,
Value => \@Data,
TTL => $Self->{CacheTTL},
);
return %Data;
}
=head2 DeploymentGetLast()
Get last global deployment.
my %Deployment = $SysConfigDBObject->DeploymentGetLast();
Returns:
%Deployment = (
DeploymentID => 123,
Comments => 'Some Comments',
EffectiveValueStrg => $SettingEffectiveValues, # String with the value of all settings,
# as seen in the Perl configuration file.
CreateTime => "2016-05-29 11:04:04",
CreateBy => 123,
);
=cut
sub DeploymentGetLast {
my ( $Self, %Param ) = @_;
my $CacheKey = 'DeploymentGetLast';
my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
# Return cache.
my $Cache = $CacheObject->Get(
Type => 'SysConfigDeployment',
Key => $CacheKey,
);
return %{$Cache} if ref $Cache eq 'HASH';
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
my $DeploymentID;
return if !$DBObject->Prepare(
SQL => '
SELECT MAX(id)
FROM sysconfig_deployment
WHERE user_id IS NULL',
);
my @DeploymentID;
while ( my @Row = $DBObject->FetchrowArray() ) {
$DeploymentID = $Row[0];
}
return if !$DeploymentID;
my %Deployment = $Self->DeploymentGet(
DeploymentID => $DeploymentID,
);
$CacheObject->Set(
Type => 'SysConfigDeployment',
Key => $CacheKey,
Value => \%Deployment,
TTL => $Self->{CacheTTL},
);
return %Deployment;
}
=head2 DeploymentDelete()
Delete a deployment from the database.
my $Success = $SysConfigDBObject->DeploymentDelete(
DeploymentID => 123,
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub DeploymentDelete {
my ( $Self, %Param ) = @_;
if ( !$Param{DeploymentID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'Need DeploymentID!',
);
return;
}
my %Deployment = $Self->DeploymentGet(
DeploymentID => $Param{DeploymentID},
Valid => 0,
);
return 1 if !%Deployment;
# Delete deployment from the data base.
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => 'DELETE FROM sysconfig_deployment WHERE id = ?',
Bind => [ \$Param{DeploymentID} ],
);
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigDeployment',
Key => 'DeploymentGet::DeploymentID::' . $Param{DeploymentID},
);
if ( $Deployment{TargetUserID} ) {
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigDeployment',
Key => 'DeploymentUserList',
);
}
else {
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigDeployment',
Key => 'DeploymentList',
);
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
Type => 'SysConfigDeployment',
Key => 'DeploymentGetLast',
);
}
return 1;
}
=head2 DeploymentLock()
Lock global deployment to a particular user.
my $ExclusiveLockGUID = $SysConfigDBObject->DeploymentLock(
UserID => 123,
ExclusiveLockGUID => $LockingString, # optional (if specific GUID is needed)
Force => 1, # Optional, locks the deployment even if is already
# locked to another user, also removes locks for
# all settings.
);
Returns:
$ExclusiveLockGUID = 'SomeLockingString'; # or false in case of an error or already locked
=cut
sub DeploymentLock {
my ( $Self, %Param ) = @_;
if ( !$Param{UserID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need UserID!",
);
return;
}
my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
# It's not possible to lock a deployment if a setting is locked on a valid time.
my @LockedList;
if ( $Param{Force} ) {
my $Success = $Self->DefaultSettingUnlock(
UnlockAll => 1,
);
}
else {
@LockedList = $Self->DefaultSettingListGet(
Locked => 1,
);
}
# Get current time.
my $CurrentDateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
if ( IsArrayRefWithData( \@LockedList ) ) {
LOCKED:
for my $Locked (@LockedList) {
next LOCKED if $Locked->{ExclusiveLockUserID} ne $Param{UserID};
my $LockedDateTimeObject = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
String => $Locked->{ExclusiveLockExpiryTime},
},
);
my $IsLocked = $LockedDateTimeObject > $CurrentDateTimeObject ? 1 : 0;
if ($IsLocked) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message =>
"It's not possible to lock a deployment if a setting is currently locked ($Locked->{Name}).",
);
return;
}
}
}
if ( defined $Param{ExclusiveLockGUID} && length $Param{ExclusiveLockGUID} != 32 ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "ExclusiveLockGUID is invalid",
);
return;
}
if ( $Param{Force} ) {
my $Success = $Self->DeploymentUnlock(
All => 1,
);
}
# Check if it's already locked.
return if $Self->DeploymentIsLocked();
# If its not locked use or create a new locking string.
my $ExclusiveLockGUID = $Param{ExclusiveLockGUID} || $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString(
Length => 32,
);
my $DeploymentExpireTimeMinutes = 5;
# Set expire time.
$DateTimeObject->Add(
Minutes => $DeploymentExpireTimeMinutes,
);
my $ExpiryTime = $DateTimeObject->ToString();
my $SQL = '
INSERT INTO sysconfig_deployment_lock
( exclusive_lock_guid, exclusive_lock_user_id, exclusive_lock_expiry_time )
VALUES
( ?, ?, ? )';
my @Bind = (
\$ExclusiveLockGUID, \$Param{UserID},
\$ExpiryTime,
);
# Create db record.
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => $SQL,
Bind => \@Bind,
);
return $ExclusiveLockGUID;
}
=head2 DeploymentIsLocked()
Check if global deployment is locked.
my $Locked = $SysConfigDBObject->DeploymentIsLocked();
Returns:
$Locked = 1; # or false if it is not locked
=cut
sub DeploymentIsLocked {
my ( $Self, %Param ) = @_;
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Get deployment lock from the DB.
my %DeploymentLock = $Self->_DeploymentLockGet();
# Return no lock if there is no locking information.
return if !%DeploymentLock;
# Return no lock if there is no lock expiry time.
return if !$DeploymentLock{ExclusiveLockExpiryTime};
# Deployment was locked, check if lock has expired.
# Get current time.
my $CurrentDateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
my $LockedDateTimeObject = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
String => $DeploymentLock{ExclusiveLockExpiryTime},
},
);
my $Locked = $LockedDateTimeObject > $CurrentDateTimeObject ? 1 : 0;
if ( !$Locked ) {
$Self->DeploymentUnlock(
All => 1,
);
}
return $Locked;
}
=head2 DeploymentIsLockedByUser()
Check if global deployment is locked for a determined user.
my $LockedByUser = $SysConfigDBObject->DeploymentIsLockedByUser(
ExclusiveLockGUID => $LockingString, # the GUID used to locking the deployment
UserID => 123, # the user should have locked the deployment
);
Returns:
$LockedByUser = 'SomeLockingString'; # or false in case of not locked
=cut
sub DeploymentIsLockedByUser {
my ( $Self, %Param ) = @_;
# Check needed stuff.
for my $Needed (qw(UserID ExclusiveLockGUID)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!",
);
return;
}
}
return if !IsStringWithData( $Param{ExclusiveLockGUID} );
# ExclusiveLockGUID should not be 0
return if !$Param{ExclusiveLockGUID};
# Get deployment lock from the DB.
my %DeploymentLock = $Self->_DeploymentLockGet();
# Return no lock if there is no locking information.
return if !%DeploymentLock;
# Return no lock if there is no lock expiry time.
return if !$DeploymentLock{ExclusiveLockExpiryTime};
# Check ExclusiveLockUserID
return if $DeploymentLock{ExclusiveLockUserID} ne $Param{UserID};
# Check ExclusiveLockGUID
return if !$DeploymentLock{ExclusiveLockGUID};
return if $DeploymentLock{ExclusiveLockGUID} ne $Param{ExclusiveLockGUID};
my $ExclusiveLockGUID = $DeploymentLock{ExclusiveLockGUID};
# If deployment was locked, check if lock has expired.
my $CurrentDateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
my $LockedDateTimeObject = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
String => $DeploymentLock{ExclusiveLockExpiryTime},
},
);
my $Locked = $LockedDateTimeObject > $CurrentDateTimeObject ? 1 : 0;
# Extend the time if it was already locked for the user but time has been expired
if ( !$Locked ) {
$ExclusiveLockGUID = $Self->DeploymentLock(
UserID => $Param{UserID},
ExclusiveLockGUID => $Param{ExclusiveLockGUID},
);
return if !$ExclusiveLockGUID;
}
return 1;
}
=head2 DeploymentModifiedVersionList()
Return a list of modified versions for a global deployment based on the deployment time. Limited
to a particular deployment or including also all previous deployments
my %ModifiedVersionList = $SysConfigDBObject->DeploymentModifiedVersionList(
DeploymentID => 123, # the deployment id
Mode => 'Equals' # (optional) default 'Equals'
# Equals: only the settings from the given deployment
# GreaterThan: only the settings after the given deployment
# GreaterThanEquals: includes the settings of the given deployment and after
# SmallerThan: only the settings before the given deployment
# SmallerThanEquals: includes the settings of the given deployment and before
);
Returns:
%ModifiedVersionIDs = (
123 => 'Setting1',
124 => 'Setting2',
125 => 'Setting3'
);
=cut
sub DeploymentModifiedVersionList {
my ( $Self, %Param ) = @_;
if ( !$Param{DeploymentID} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need DeploymentID!",
);
return;
}
my $Mode = $Param{Mode} // 'Equals';
my %ModeMapping = (
Equals => '=',
GreaterThan => '>',
GreaterThanEquals => '>=',
SmallerThan => '<',
SmallerThanEquals => '<=',
);
if ( !$ModeMapping{$Mode} ) {
$Self->{LogObject}->Log(
Priority => 'error',
Message => "Mode $Mode is invalid!",
);
return;
}
my %Deployment = $Self->DeploymentGet(
DeploymentID => $Param{DeploymentID},
);
return if !IsHashRefWithData( \%Deployment );
return if $Deployment{TargetUserID};
my $CreateTime = $Deployment{CreateTime} || '';
return if !$CreateTime;
my $SQL = "
SELECT max(smv.id) id, smv.name
FROM sysconfig_modified_version smv
WHERE smv.create_time $ModeMapping{$Mode} ?
GROUP BY smv.name";
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
return if !$DBObject->Prepare(
SQL => $SQL,
Bind => [ \$CreateTime, ]
);
my %ModifiedVersionList;
while ( my @Row = $DBObject->FetchrowArray() ) {
$ModifiedVersionList{ $Row[0] } = $Row[1];
}
return %ModifiedVersionList;
}
=head2 DeploymentUnlock()
Unlock global deployment.
my $Success = $SysConfigDBObject->DeploymentUnlock(
ExclusiveLockGUID => '12ad34f21b',
UserID => 123,
);
or
my $Success = $SysConfigDBObject->DeploymentUnlock(
All => 1,
);
Returns:
$Success = 1; # or false in case of an error
=cut
sub DeploymentUnlock {
my ( $Self, %Param ) = @_;
# Check needed
if ( !$Param{ExclusiveLockGUID} && !$Param{UserID} && !$Param{All} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'All or ExclusiveLockGUID and UserID are needed!',
);
return;
}
if ( ( $Param{ExclusiveLockGUID} && !$Param{UserID} ) || ( $Param{UserID} && !$Param{ExclusiveLockGUID} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => 'ExclusiveLockGUID and UserID are needed!',
);
return;
}
my $SQL = 'DELETE FROM sysconfig_deployment_lock';
my @Bind;
if ( $Param{ExclusiveLockGUID} ) {
$SQL .= '
WHERE exclusive_lock_guid = ?
AND exclusive_lock_user_id = ?';
@Bind = ( \$Param{ExclusiveLockGUID}, \$Param{UserID} );
}
# Update db record.
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
SQL => $SQL,
Bind => \@Bind,
);
return 1;
}
=head2 DeploymentListCleanup()
Removes invalid deployments from the database.
my $Success = $SysConfigDBObject->DeploymentListCleanup( );
Returns:
$Success = 1; # Returns 1 if all records are valid (or all invalid was removed)
# Returns -1 if there is an invalid deployment that could be in adding process
# Returns false in case of an error
=cut
sub DeploymentListCleanup {
my ( $Self, %Param ) = @_;
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
return if !$DBObject->Prepare(
SQL => '
SELECT id, create_time
FROM sysconfig_deployment
WHERE effective_value LIKE \'Invalid%\'
OR comments LIKE \'OTRSInvalid-%\'
ORDER BY id DESC',
);
my @Deployments;
while ( my @Row = $DBObject->FetchrowArray() ) {
my %Deployment = (
DeploymentID => $Row[0],
CreateTime => $Row[1],
);
push @Deployments, \%Deployment;
}
my $Success = 1;
my $CurrentDateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
DEPLOYMENT:
for my $Deployment (@Deployments) {
my $DeploymentDateTimeObject = $Kernel::OM->Create(
'Kernel::System::DateTime',
ObjectParams => {
String => $Deployment->{CreateTime},
},
);
my $Delta = $CurrentDateTimeObject->Delta( DateTimeObject => $DeploymentDateTimeObject );
# Remove deployment only if it is old (more than 20 secs)
if ( $DeploymentDateTimeObject < $CurrentDateTimeObject && $Delta >= 20 ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Deployment $Deployment->{DeploymentID} is invalid and will be removed!",
);
my $DeleteSuccess = $Self->DeploymentDelete(
DeploymentID => $Deployment->{DeploymentID},
);
if ( !$DeleteSuccess ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Could not delete deployment $Deployment->{DeploymentID}",
);
$Success = 0;
}
last DEPLOYMENT;
}
# Otherwise just log that there is something wrong with the deployment but do not remove it
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Deployment $Deployment->{DeploymentID} seams to be invalid or its not fully updated",
);
$Success = -1;
}
return $Success;
}
=head1 PRIVATE INTERFACE
=head2 _DeploymentLockGet()
Get deployment lock entry.
my %DeploymentLock = $SysConfigDBObject->_DeploymentLockGet();
Returns:
%DeploymentLock = (
DeploymentLoclID => "123",
ExclusiveLockGUID => $LockingString,
ExclusiveLockUserID => 1,
ExclusiveLockExpiryTime => '2016-05-29 11:09:04',
CreateTime => "2016-05-29 11:04:04",
);
=cut
sub _DeploymentLockGet {
my ( $Self, %Param ) = @_;
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Get deployment lock from the DB.
return if !$DBObject->Prepare(
SQL => '
SELECT id, exclusive_lock_guid, exclusive_lock_user_id, exclusive_lock_expiry_time
FROM sysconfig_deployment_lock
ORDER BY exclusive_lock_expiry_time DESC',
Limit => 1,
);
my %DeploymentLock;
while ( my @Data = $DBObject->FetchrowArray() ) {
$DeploymentLock{ID} = $Data[0];
$DeploymentLock{ExclusiveLockGUID} = $Data[1];
$DeploymentLock{ExclusiveLockUserID} = $Data[2];
$DeploymentLock{ExclusiveLockExpiryTime} = $Data[3];
}
return %DeploymentLock;
}
=head2 _BulkInsert()
Add batch entries to the DB into a given table.
my $Success = $SysConfigDBObject->_BulkInsert(
Table => 'table_name', # (required) Table name
Columns => [ # (required) Array of column names
'column_name',
...
],
Data => [ # (required) AoA with data
[
'record 1',
'record 2',
],
[
...
],
...
],
);
=cut
sub _BulkInsert {
my ( $Self, %Param ) = @_;
for my $Needed (qw(Table)) {
if ( !$Param{$Needed} ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Need $Needed!",
);
return;
}
}
for my $Parameter (qw(Columns Data)) {
if ( !IsArrayRefWithData( $Param{Columns} ) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "$Parameter must be not empty array!"
);
return;
}
}
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
# Get the database type.
my $DBType = $DBObject->GetDatabaseFunction('Type');
# Define database specific SQL for the multi-line inserts.
my %DatabaseSQL;
my $Columns = join( ',', @{ $Param{Columns} } );
# Check the first array in Data and create Mask (current_timestamp is always on same place in array).
my @Mask = map {
( $_ && $_ eq 'current_timestamp' )
? 'current_timestamp' : '?'
} @{ $Param{Data}->[0] };
my $MaskedValues = join( ',', @Mask );
if ( $DBType eq 'oracle' ) {
%DatabaseSQL = (
Start => 'INSERT ALL ',
FirstLine => "
INTO $Param{Table} ($Columns)
VALUES ( $MaskedValues ) ",
NextLine => "
INTO $Param{Table} (
$Columns
)
VALUES ( $MaskedValues ) ",
End => 'SELECT * FROM DUAL',
);
}
else {
%DatabaseSQL = (
Start => "
INSERT INTO $Param{Table} (
$Columns
)",
FirstLine => "VALUES ( $MaskedValues )",
NextLine => ", ( $MaskedValues ) ",
End => '',
);
}
my $SQL = '';
my @Bind;
my $Count = 0;
RECORD:
for my $Entry ( @{ $Param{Data} } ) {
$Count++;
if ( !IsArrayRefWithData($Entry) ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Data contains empty array, skipped!"
);
next RECORD;
}
if ( scalar @{$Entry} != scalar @{ $Param{Columns} } ) {
$Kernel::OM->Get('Kernel::System::Log')->Log(
Priority => 'error',
Message => "Array size doesn't match Columns size, skipped!"
);
my $Col = scalar @{ $Param{Columns} };
next RECORD;
}
# Now the article entry is validated and can be added to sql.
if ( !$SQL ) {
$SQL = $DatabaseSQL{Start} . $DatabaseSQL{FirstLine};
}
else {
$SQL .= $DatabaseSQL{NextLine};
}
BIND:
for my $Item ( @{$Entry} ) {
next BIND if ( $Item && $Item eq 'current_timestamp' ); # Already included in the SQL part.
push @Bind, \$Item;
}
# Check the length of the SQL string
# (some databases only accept SQL strings up to 4k,
# so we want to stay safe here with just 3500 bytes).
if ( length $SQL > 3500 || $Count == scalar @{ $Param{Data} } ) {
# Add the end line to sql string.
$SQL .= $DatabaseSQL{End};
# Insert multiple entries.
return if !$DBObject->Do(
SQL => $SQL,
Bind => \@Bind,
);
# Reset the SQL string and the Bind array.
$SQL = '';
@Bind = ();
}
}
return 1;
}
=head2 _GetUID()
Generates a unique identifier.
my $UID = $TicketNumberObject->_GetUID();
Returns:
my $UID = 14906327941360ed8455f125d0450277;
=cut
sub _GetUID {
my ( $Self, %Param ) = @_;
my $NodeID = $Kernel::OM->Get('Kernel::Config')->Get('NodeID') || 1;
my ( $Seconds, $Microseconds ) = Time::HiRes::gettimeofday();
my $ProcessID = $$;
my $CounterUID = $ProcessID . $Seconds . $Microseconds . $NodeID;
my $RandomString = $Kernel::OM->Get('Kernel::System::Main')->GenerateRandomString(
Length => 32 - length $CounterUID,
Dictionary => [ 0 .. 9, 'a' .. 'f' ], # hexadecimal
);
$CounterUID .= $RandomString;
return $CounterUID;
}
1;
=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