1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8## nofilter(TidyAll::Plugin::OTRS::Perl::LayoutObject) 9package Kernel::System::SysConfig::ValueType::DateTime; 10 11use strict; 12use warnings; 13 14use Kernel::System::VariableCheck qw(:all); 15 16use parent qw(Kernel::System::SysConfig::BaseValueType); 17 18our @ObjectDependencies = ( 19 'Kernel::Config', 20 'Kernel::Language', 21 'Kernel::Output::HTML::Layout', 22 'Kernel::System::Log', 23 'Kernel::System::JSON', 24 'Kernel::System::User', 25); 26 27=head1 NAME 28 29Kernel::System::SysConfig::ValueType::DateTime - System configuration date-time value type backed. 30 31=head1 PUBLIC INTERFACE 32 33=head2 new() 34 35Create an object. Do not use it directly, instead use: 36 37 use Kernel::System::ObjectManager; 38 local $Kernel::OM = Kernel::System::ObjectManager->new(); 39 my $ValueTypeObject = $Kernel::OM->Get('Kernel::System::SysConfig::ValueType::DateTime'); 40 41=cut 42 43sub new { 44 my ( $Type, %Param ) = @_; 45 46 # Allocate new hash for object. 47 my $Self = {}; 48 bless( $Self, $Type ); 49 50 return $Self; 51} 52 53=head2 SettingEffectiveValueCheck() 54 55Check if provided EffectiveValue matches structure defined in XMLContentParsed. 56 57 my %Result = $ValueTypeObject->SettingEffectiveValueCheck( 58 XMLContentParsed => { # (required) 59 Value => [ 60 { 61 'Item' => [ 62 { 63 'Content' => '2016-01-01 00:00:00', 64 'ValueType' => 'DateTime', 65 }, 66 ], 67 }, 68 ], 69 }, 70 EffectiveValue => '2016-02-02 01:12:22', # (optional) 71 UserID => 1, # (required) 72 ); 73 74Result: 75 %Result = ( 76 EffectiveValue => '2016-02-02 03:12:22', # Note that EffectiveValue can be modified 77 Success => 1, 78 Error => undef, 79 ); 80 81=cut 82 83sub SettingEffectiveValueCheck { 84 my ( $Self, %Param ) = @_; 85 86 for my $Needed (qw(XMLContentParsed UserID)) { 87 if ( !$Param{$Needed} ) { 88 $Kernel::OM->Get('Kernel::System::Log')->Log( 89 Priority => 'error', 90 Message => "Need $Needed!" 91 ); 92 93 return; 94 } 95 } 96 97 my %Result = ( 98 Success => 0, 99 ); 100 101 # Data should be scalar. 102 if ( ref $Param{EffectiveValue} ) { 103 $Result{Error} = 'EffectiveValue for DateTime must be a scalar!'; 104 return %Result; 105 } 106 107 if ( $Param{EffectiveValue} !~ m{\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}} ) { 108 $Result{Error} = 'EffectiveValue for DateTime must be in format YYYY-MM-DD hh:mm:ss!'; 109 return %Result; 110 } 111 112 my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences( 113 UserID => $Param{UserID}, 114 ); 115 116 my $OTRSTimeZone = $Kernel::OM->Get('Kernel::Config')->Get("OTRSTimeZone"); 117 my $DateTimeObject; 118 119 if ( !$Preferences{UserTimeZone} || $Preferences{UserTimeZone} eq $OTRSTimeZone ) { 120 $DateTimeObject = $Kernel::OM->Create( 121 'Kernel::System::DateTime', 122 ObjectParams => { 123 TimeZone => $OTRSTimeZone, 124 }, 125 ); 126 127 my $SetSuccess = $DateTimeObject->Set( String => $Param{EffectiveValue} ); 128 129 if ( !$SetSuccess ) { 130 $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( 131 "EffectiveValue for DateTime($Param{EffectiveValue}) must be in format YYYY-MM-DD hh:mm:ss!", 132 ); 133 return %Result; 134 } 135 136 $Result{EffectiveValue} = $Param{EffectiveValue}; 137 } 138 else { 139 $DateTimeObject = $Kernel::OM->Create( 140 'Kernel::System::DateTime', 141 ObjectParams => { 142 TimeZone => $Preferences{UserTimeZone}, 143 }, 144 ); 145 146 my $SetSuccess = $DateTimeObject->Set( String => $Param{EffectiveValue} ); 147 148 if ( !$SetSuccess ) { 149 $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( 150 "EffectiveValue for DateTime($Param{EffectiveValue}) must be in format YYYY-MM-DD hh:mm:ss!", 151 ); 152 return %Result; 153 } 154 155 my $Success = $DateTimeObject->ToTimeZone( 156 TimeZone => $OTRSTimeZone, 157 ); 158 159 if ($Success) { 160 $Result{EffectiveValue} = $DateTimeObject->ToString(); 161 } 162 else { 163 $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( 164 "System was not able to calculate user DateTime in OTRSTimeZone!" 165 ); 166 167 $Kernel::OM->Get('Kernel::System::Log')->Log( 168 Priority => 'error', 169 Message => "System was not able to calculate user DateTime in OTRSTimeZone!" 170 ); 171 } 172 } 173 174 if ( !$DateTimeObject ) { 175 $Result{Error} = $Kernel::OM->Get('Kernel::Language')->Translate( 176 "EffectiveValue for DateTime($Param{EffectiveValue}) must be in format YYYY-MM-DD hh:mm:ss!", 177 ); 178 return %Result; 179 } 180 181 $Result{Success} = 1; 182 183 return %Result; 184} 185 186=head2 SettingRender() 187 188Extracts the effective value from a XML parsed setting. 189 190 my $SettingHTML = $ValueTypeObject->SettingRender( 191 Name => 'SettingName', 192 EffectiveValue => '2016-02-02 01:00:59', # (optional) 193 DefaultValue => 'Product 5', # (optional) 194 Class => 'My class' # (optional) 195 RW => 1, # (optional) Allow editing. Default 0. 196 Item => [ # (optional) XML parsed item 197 { 198 'ValueType' => 'Date', 199 'Content' => '2016-02-02 01:00:59', 200 'ValueRegex' => '', 201 }, 202 ], 203 IsArray => 1, # (optional) Item is part of the array 204 IsHash => 1, # (optional) Item is part of the hash 205 SkipEffectiveValueCheck => 1, # (optional) If enabled, system will not perform effective value check. 206 # Default: 1. 207 UserID => 1, # (required) UserID 208 ); 209 210Returns: 211 212 $SettingHTML = '<div class "Field"...</div>'; 213 214=cut 215 216sub SettingRender { 217 my ( $Self, %Param ) = @_; 218 219 for my $Needed (qw(Name UserID)) { 220 if ( !defined $Param{$Needed} ) { 221 $Kernel::OM->Get('Kernel::System::Log')->Log( 222 Priority => 'error', 223 Message => "Need $Needed", 224 ); 225 return; 226 } 227 } 228 229 $Param{Class} //= ''; 230 $Param{Class} .= ' DateTime'; 231 $Param{DefaultValue} //= ''; 232 233 my $IDSuffix = $Param{IDSuffix} || ''; 234 235 my $LanguageObject = $Kernel::OM->Get('Kernel::Language'); 236 237 my $EffectiveValue = $Param{EffectiveValue}; 238 if ( 239 !defined $EffectiveValue 240 && $Param{Item} 241 && $Param{Item}->[0]->{Content} 242 ) 243 { 244 $EffectiveValue = $Param{Item}->[0]->{Content}; 245 } 246 247 my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); 248 249 # Check if there is Datepicker before we add it. 250 my $HasDatepicker = $LayoutObject->{HasDatepicker}; 251 252 my $Name = $Param{Name} . $IDSuffix; 253 254 my %EffectiveValueCheck = ( 255 Success => 1, 256 ); 257 258 if ( !$Param{SkipEffectiveValueCheck} ) { 259 %EffectiveValueCheck = $Self->SettingEffectiveValueCheck( 260 EffectiveValue => $EffectiveValue, 261 XMLContentParsed => { 262 Value => [ 263 { 264 Item => $Param{Item}, 265 }, 266 ], 267 }, 268 UserID => $Param{UserID}, 269 ); 270 } 271 272 my $TimeZone = $Kernel::OM->Get('Kernel::Config')->Get("OTRSTimeZone"); 273 274 my $DateTimeObject = $Kernel::OM->Create( 275 'Kernel::System::DateTime', 276 ObjectParams => { 277 String => $EffectiveValue, 278 TimeZone => $TimeZone, 279 }, 280 ); 281 282 my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences( 283 UserID => $Param{UserID}, 284 ); 285 286 if ( $Preferences{UserTimeZone} ) { 287 my $Success = $DateTimeObject->ToTimeZone( 288 TimeZone => $Preferences{UserTimeZone}, 289 ); 290 $TimeZone = $Preferences{UserTimeZone}; 291 292 if ( !$Success ) { 293 $Kernel::OM->Get('Kernel::System::Log')->Log( 294 Priority => 'error', 295 Message => "System was not able to calculate DateTime in user timezone!" 296 ); 297 } 298 } 299 300 my @Date = split m{-|\s|:}, $DateTimeObject->ToString(); 301 302 my $HTML = "<div class='SettingContent'>\n"; 303 $HTML .= $LayoutObject->BuildDateSelection( 304 Prefix => $Name, 305 $Name . "Class" => $Param{Class}, 306 $Name . "Year" => $Date[0], 307 $Name . "Month" => $Date[1], 308 $Name . "Day" => $Date[2], 309 $Name . "Hour" => $Date[3], 310 $Name . "Minute" => $Date[4], 311 $Name . "Second" => $Date[5], 312 YearDiff => 10, 313 Format => 'DateInputFormatLong', 314 Validate => 1, 315 Disabled => $Param{RW} ? 0 : 1, 316 OverrideTimeZone => 1, 317 ); 318 319 my $TimeZoneText = $Kernel::OM->Get('Kernel::Language')->Translate("Time Zone"); 320 $HTML .= "<span class='TimeZoneText'>$TimeZoneText: $TimeZone</span>\n"; 321 322 if ( !$EffectiveValueCheck{Success} ) { 323 my $Message = $LanguageObject->Translate("Value is not correct! Please, consider updating this field."); 324 325 $HTML .= $Param{IsValid} ? "<div class='BadEffectiveValue'>\n" : "<div>\n"; 326 $HTML .= "<p>* $Message</p>\n"; 327 $HTML .= "</div>\n"; 328 } 329 330 $HTML .= "</div>\n"; 331 332 if ( !$Param{IsArray} && !$Param{IsHash} ) { 333 my $DefaultText = $Kernel::OM->Get('Kernel::Language')->Translate('Default'); 334 335 $HTML .= <<"EOF"; 336 <div class=\"WidgetMessage Bottom\"> 337 $DefaultText: $Param{DefaultValue} 338 </div> 339EOF 340 } 341 342 if ( $Param{IsAjax} && $LayoutObject->{_JSOnDocumentComplete} && $Param{RW} ) { 343 for my $JS ( @{ $LayoutObject->{_JSOnDocumentComplete} } ) { 344 345 $HTML .= "<script>$JS</script>"; 346 } 347 } 348 349 if ( $Param{IsAjax} ) { 350 351 # Remove JS generated in BuildDateSelection() call (setting is disabled or it's already sent together with HTML). 352 # It also prevents multiple Datepicker initializations (if there are several on the page). 353 pop @{ $LayoutObject->{_JSOnDocumentComplete} }; 354 355 if ( !$HasDatepicker ) { 356 my $VacationDays = $LayoutObject->DatepickerGetVacationDays(); 357 my $TextDirection = $LanguageObject->{TextDirection} || ''; 358 359 my $JSONString = $Kernel::OM->Get('Kernel::System::JSON')->Encode( 360 Data => { 361 VacationDays => $VacationDays, 362 IsRTL => ( $TextDirection eq 'rtl' ) ? 1 : 0, 363 }, 364 ); 365 366 $HTML .= "<script> 367 Core.Config.Set('Datepicker', $JSONString); 368 </script>"; 369 370 # If there are several DateTime settings, don't run this block again. 371 $LayoutObject->{HasDatepicker} = 1; 372 } 373 } 374 375 return $HTML; 376} 377 378=head2 AddItem() 379 380Generate HTML for new array/hash item. 381 382 my $HTML = $ValueTypeObject->AddItem( 383 Name => 'SettingName', (required) Name 384 DefaultItem => { (optional) DefaultItem hash, if available 385 Content => '2017-01-01 01:45:00', 386 ValueType => 'DateTime', 387 }, 388 IDSuffix => '_Array1', (optional) IDSuffix is needed for arrays and hashes. 389 ); 390 391Returns: 392 393 $HTML = '<select class="Validate_DateMonth Date" id="SettingName_Array1Month" ...'; 394 395=cut 396 397sub AddItem { 398 my ( $Self, %Param ) = @_; 399 400 # Check needed stuff. 401 for my $Needed (qw(Name)) { 402 if ( !$Param{$Needed} ) { 403 $Kernel::OM->Get('Kernel::System::Log')->Log( 404 Priority => 'error', 405 Message => "Need $Needed!", 406 ); 407 return; 408 } 409 } 410 411 my $IDSuffix = $Param{IDSuffix} || ''; 412 my $Class = $Param{Class} || ''; 413 $Class .= ' DateTime Entry'; 414 415 my $Name = $Param{Name} . $IDSuffix; 416 417 my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout'); 418 my $TimeZone = $Kernel::OM->Get('Kernel::Config')->Get("OTRSTimeZone"); 419 420 my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences( 421 UserID => $Param{UserID}, 422 ); 423 424 my $DefaultValue; 425 if ( $Param{DefaultItem} ) { 426 427 my $DateTimeObject = $Kernel::OM->Create( 428 'Kernel::System::DateTime', 429 ObjectParams => { 430 String => $Param{DefaultItem}->{Content}, 431 TimeZone => $TimeZone, 432 }, 433 ); 434 435 if ( $Preferences{UserTimeZone} ) { 436 my $Success = $DateTimeObject->ToTimeZone( 437 TimeZone => $Preferences{UserTimeZone}, 438 ); 439 440 if ( !$Success ) { 441 $Kernel::OM->Get('Kernel::System::Log')->Log( 442 Priority => 'error', 443 Message => "System was not able to calculate DateTime in user timezone!" 444 ); 445 } 446 } 447 448 $DefaultValue = $DateTimeObject->ToString(); 449 } 450 451 if ( $Preferences{UserTimeZone} ) { 452 $TimeZone = $Preferences{UserTimeZone}; 453 } 454 455 my $Result; 456 457 if ($DefaultValue) { 458 $DefaultValue =~ m{(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})}; 459 460 $Result = $LayoutObject->BuildDateSelection( 461 Prefix => $Name, 462 $Name . "Year" => $1, 463 $Name . "Month" => $2, 464 $Name . "Day" => $3, 465 $Name . "Hour" => $4, 466 $Name . "Minute" => $5, 467 $Name . "Second" => $6, 468 $Name . "Class" => $Class, 469 YearDiff => 10, 470 Format => 'DateInputFormatLong', 471 Validate => 1, 472 OverrideTimeZone => 1, 473 ); 474 } 475 else { 476 $Result = $LayoutObject->BuildDateSelection( 477 Prefix => $Name, 478 $Name . "Class" => $Class, 479 YearDiff => 10, 480 Format => 'DateInputFormatLong', 481 Validate => 1, 482 OverrideTimeZone => 1, 483 ); 484 } 485 486 my $TimeZoneText = $Kernel::OM->Get('Kernel::Language')->Translate("Time Zone"); 487 $Result .= "<span class='TimeZoneText'>$TimeZoneText: $TimeZone</span>\n"; 488 489 for my $JS ( @{ $LayoutObject->{_JSOnDocumentComplete} } ) { 490 $Result .= "<script>$JS</script>"; 491 } 492 493 return $Result; 494} 495 4961; 497 498=head1 TERMS AND CONDITIONS 499 500This software is part of the OTRS project (L<https://otrs.org/>). 501 502This software comes with ABSOLUTELY NO WARRANTY. For details, see 503the enclosed file COPYING for license information (GPL). If you 504did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 505 506=cut 507