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
9package Kernel::System::OTRSBusiness;
10
11use strict;
12use warnings;
13
14use Kernel::System::VariableCheck qw(:all);
15
16our @ObjectDependencies = (
17    'Kernel::Config',
18    'Kernel::System::Cache',
19    'Kernel::System::CloudService::Backend::Run',
20    'Kernel::System::DynamicField',
21    'Kernel::System::DynamicField::Backend',
22    'Kernel::System::Log',
23    'Kernel::System::DateTime',
24    'Kernel::System::DB',
25    'Kernel::System::Package',
26    'Kernel::System::SystemData',
27);
28
29=head1 NAME
30
31Kernel::System::OTRSBusiness - OTRSBusiness deployment backend
32
33=head1 PUBLIC INTERFACE
34
35=head2 new()
36
37create an object. Do not use it directly, instead use:
38
39    use Kernel::System::ObjectManager;
40    local $Kernel::OM = Kernel::System::ObjectManager->new();
41    my $RegistrationObject = $Kernel::OM->Get('Kernel::System::OTRSBusiness');
42
43
44=cut
45
46sub new {
47    my ( $Type, %Param ) = @_;
48
49    # allocate new hash for object
50    my $Self = {};
51    bless( $Self, $Type );
52
53    #$Self->{APIVersion} = 1;
54
55    # Get config object
56    my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
57
58    # Get OTRSBusiness::ReleaseChannel from SysConfig (Stable = 1, Development = 0)
59    $Self->{OnlyStable} = $ConfigObject->Get('OTRSBusiness::ReleaseChannel') // 1;
60
61    # Set cache params
62    $Self->{CacheType} = 'OTRSBusiness';
63    $Self->{CacheTTL}  = 60 * 60 * 24 * 30;    # 30 days
64
65    # Check if cloud services are disabled
66    $Self->{CloudServicesDisabled} = $ConfigObject->Get('CloudServices::Disabled') || 0;
67
68    # If we cannot connect to cloud.otrs.com for more than the second period, show an error.
69    $Self->{NoConnectErrorPeriod} = 60 * 60 * 24 * 15;    # 15 days
70
71    # If we cannot connect to cloud.otrs.com for more than the second period, block the system.
72    $Self->{NoConnectBlockPeriod} = 60 * 60 * 24 * 25;    # 25 days
73
74    # If the contract is about to expire in less than this time, show a hint
75    $Self->{ContractExpiryWarningPeriod} = 60 * 60 * 24 * 28;    # 28 days
76
77    return $Self;
78}
79
80=head2 OTRSBusinessIsInstalled()
81
82checks if OTRSBusiness is installed in the current system.
83That does not necessarily mean that it is also active, for
84example if the package is only on the database but not on
85the file system.
86
87=cut
88
89sub OTRSBusinessIsInstalled {
90    my ( $Self, %Param ) = @_;
91
92    my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
93
94    # as the check for installed packages can be
95    # very expensive, we want to use caching here
96    my $Cache = $CacheObject->Get(
97        Type => $Self->{CacheType},
98        TTL  => $Self->{CacheTTL},
99        Key  => 'OTRSBusinessIsInstalled',
100    );
101
102    return $Cache if defined $Cache;
103
104    my $IsInstalled = $Self->_GetOTRSBusinessPackageFromRepository() ? 1 : 0;
105
106    # set cache
107    $CacheObject->Set(
108        Type  => $Self->{CacheType},
109        TTL   => $Self->{CacheTTL},
110        Key   => 'OTRSBusinessIsInstalled',
111        Value => $IsInstalled,
112    );
113
114    return $IsInstalled;
115}
116
117=head2 OTRSSTORMIsInstalled()
118
119checks if OTRSStorm is installed in the current system.
120That does not necessarily mean that it is also active, for
121example if the package is only on the database but not on
122the file system.
123
124=cut
125
126sub OTRSSTORMIsInstalled {
127    my ( $Self, %Param ) = @_;
128
129    my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
130
131    # as the check for installed packages can be
132    # very expensive, we want to use caching here
133    my $Cache = $CacheObject->Get(
134        Type => $Self->{CacheType},
135        TTL  => $Self->{CacheTTL},
136        Key  => 'OTRSSTORMIsInstalled',
137    );
138
139    return $Cache if defined $Cache;
140
141    my $IsInstalled = $Self->_GetSTORMPackageFromRepository() ? 1 : 0;
142
143    # set cache
144    $CacheObject->Set(
145        Type  => $Self->{CacheType},
146        TTL   => $Self->{CacheTTL},
147        Key   => 'OTRSSTORMIsInstalled',
148        Value => $IsInstalled,
149    );
150
151    return $IsInstalled;
152}
153
154=head2 OTRSCONTROLIsInstalled()
155
156checks if OTRSControl is installed in the current system.
157That does not necessarily mean that it is also active, for
158example if the package is only on the database but not on
159the file system.
160
161=cut
162
163sub OTRSCONTROLIsInstalled {
164    my ( $Self, %Param ) = @_;
165
166    my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache');
167
168    # as the check for installed packages can be
169    # very expensive, we want to use caching here
170    my $Cache = $CacheObject->Get(
171        Type => $Self->{CacheType},
172        TTL  => $Self->{CacheTTL},
173        Key  => 'OTRSCONTROLIsInstalled',
174    );
175
176    return $Cache if defined $Cache;
177
178    my $IsInstalled = $Self->_GetCONTROLPackageFromRepository() ? 1 : 0;
179
180    # set cache
181    $CacheObject->Set(
182        Type  => $Self->{CacheType},
183        TTL   => $Self->{CacheTTL},
184        Key   => 'OTRSCONTROLIsInstalled',
185        Value => $IsInstalled,
186    );
187
188    return $IsInstalled;
189}
190
191=head2 OTRSBusinessIsAvailable()
192
193checks with C<cloud.otrs.com> if OTRSBusiness is available for the current framework.
194
195=cut
196
197sub OTRSBusinessIsAvailable {
198    my ( $Self, %Param ) = @_;
199
200    return if $Self->{CloudServicesDisabled};
201
202    my $CloudServiceObject = $Kernel::OM->Get('Kernel::System::CloudService::Backend::Run');
203    my $RequestResult      = $CloudServiceObject->Request(
204        RequestData => {
205            OTRSBusiness => [
206                {
207                    Operation => 'BusinessVersionCheck',
208                    Data      => {
209                        OnlyStable => $Self->{OnlyStable},
210                    },
211                },
212            ],
213        },
214    );
215
216    my $OperationResult;
217    if ( IsHashRefWithData($RequestResult) ) {
218        $OperationResult = $CloudServiceObject->OperationResultGet(
219            RequestResult => $RequestResult,
220            CloudService  => 'OTRSBusiness',
221            Operation     => 'BusinessVersionCheck',
222        );
223
224        if ( $OperationResult->{Success} ) {
225            $Self->HandleBusinessVersionCheckCloudServiceResult(
226                OperationResult => $OperationResult,
227            );
228
229            if ( $OperationResult->{Data}->{LatestVersionForCurrentFramework} ) {
230                return 1;
231            }
232        }
233    }
234    return;
235}
236
237=head2 OTRSBusinessIsAvailableOffline()
238
239retrieves the latest result of the BusinessVersionCheck cloud service
240that was stored in the system_data table.
241
242returns 1 if available.
243
244=cut
245
246sub OTRSBusinessIsAvailableOffline {
247    my ( $Self, %Param ) = @_;
248
249    my %BusinessVersionCheck = $Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGroupGet(
250        Group => 'OTRSBusiness',
251    );
252
253    return $BusinessVersionCheck{LatestVersionForCurrentFramework} ? 1 : 0;
254}
255
256=head2 OTRSBusinessIsCorrectlyDeployed()
257
258checks if the OTRSBusiness package is correctly
259deployed or if it needs to be reinstalled.
260
261=cut
262
263sub OTRSBusinessIsCorrectlyDeployed {
264    my ( $Self, %Param ) = @_;
265
266    my $Package = $Self->_GetOTRSBusinessPackageFromRepository();
267
268    # Package not found -> return failure
269    return if !$Package;
270
271    # first check the regular way if the files are present and the package
272    # itself is installed correctly
273    return if !$Kernel::OM->Get('Kernel::System::Package')->DeployCheck(
274        Name    => $Package->{Name}->{Content},
275        Version => $Package->{Version}->{Content},
276    );
277
278    # check if all tables have been created correctly
279    # we can't rely on any .opm file here, so we just check
280    # the list of tables manually
281    my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
282
283    TABLES:
284    for my $Table (qw(chat chat_participant chat_message)) {
285
286        # if a table does not exist, $TablePresent will be 'undef' for this table
287        my $TablePresent = $DBObject->Do(
288            SQL   => "SELECT * FROM $Table",
289            Limit => 1,
290        );
291
292        return if !$TablePresent;
293    }
294
295    return 1;
296}
297
298=head2 OTRSBusinessIsReinstallable()
299
300checks if the OTRSBusiness package can be reinstalled
301(if it supports the current framework version). If not,
302an update might be needed.
303
304=cut
305
306sub OTRSBusinessIsReinstallable {
307    my ( $Self, %Param ) = @_;
308
309    my $Package = $Self->_GetOTRSBusinessPackageFromRepository();
310
311    # Package not found -> return failure
312    return if !$Package;
313
314    my %Check = $Kernel::OM->Get('Kernel::System::Package')->AnalyzePackageFrameworkRequirements(
315        Framework => $Package->{Framework},
316    );
317    return $Check{Success};
318}
319
320=head2 OTRSBusinessIsUpdateable()
321
322checks with C<cloud.otrs.com> if the OTRSBusiness package is available in a newer version
323than the one currently installed. The result of this check will be stored in the
324system_data table for offline usage.
325
326=cut
327
328sub OTRSBusinessIsUpdateable {
329    my ( $Self, %Param ) = @_;
330
331    return 0 if $Self->{CloudServicesDisabled};
332
333    my $Package = $Self->_GetOTRSBusinessPackageFromRepository();
334    return if !$Package;
335
336    my $CloudServiceObject = $Kernel::OM->Get('Kernel::System::CloudService::Backend::Run');
337    my $RequestResult      = $CloudServiceObject->Request(
338        RequestData => {
339            OTRSBusiness => [
340                {
341                    Operation => 'BusinessVersionCheck',
342                    Data      => {
343                        OnlyStable => $Self->{OnlyStable},
344                    },
345                },
346            ],
347        },
348    );
349
350    my $OperationResult;
351    if ( IsHashRefWithData($RequestResult) ) {
352        $OperationResult = $CloudServiceObject->OperationResultGet(
353            RequestResult => $RequestResult,
354            CloudService  => 'OTRSBusiness',
355            Operation     => 'BusinessVersionCheck',
356        );
357
358        if ( $OperationResult && $OperationResult->{Success} ) {
359
360            $Self->HandleBusinessVersionCheckCloudServiceResult( OperationResult => $OperationResult );
361
362            if ( $OperationResult->{Data}->{LatestVersionForCurrentFramework} ) {
363                return $Kernel::OM->Get('Kernel::System::Package')->_CheckVersion(
364                    VersionNew       => $OperationResult->{Data}->{LatestVersionForCurrentFramework},
365                    VersionInstalled => $Package->{Version}->{Content},
366                    Type             => 'Max',
367                );
368            }
369        }
370    }
371
372    return 0;
373}
374
375=head2 OTRSBusinessVersionCheckOffline()
376
377retrieves the latest result of the BusinessVersionCheck cloud service
378that was stored in the system_data table.
379
380    my %Result = $OTRSBusinessObject->OTRSBusinessVersionCheckOffline();
381
382returns
383
384    $Result = (
385        OTRSBusinessUpdateAvailable      => 1,  # if applicable
386        FrameworkUpdateAvailable         => 1,  # if applicable
387    );
388
389=cut
390
391sub OTRSBusinessVersionCheckOffline {
392    my ( $Self, %Param ) = @_;
393
394    my $Package = $Self->_GetOTRSBusinessPackageFromRepository();
395
396    return if !$Package;
397
398    my %EntitlementData = $Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGroupGet(
399        Group => 'OTRSBusiness',
400    );
401
402    my %Result = (
403        FrameworkUpdateAvailable => $EntitlementData{FrameworkUpdateAvailable} // '',
404    );
405
406    if ( $EntitlementData{LatestVersionForCurrentFramework} ) {
407        $Result{OTRSBusinessUpdateAvailable} = $Kernel::OM->Get('Kernel::System::Package')->_CheckVersion(
408            VersionNew       => $EntitlementData{LatestVersionForCurrentFramework},
409            VersionInstalled => $Package->{Version}->{Content},
410            Type             => 'Max',
411        );
412    }
413
414    return %Result;
415}
416
417=head2 OTRSBusinessGetDependencies()
418
419checks if there are any active dependencies on OTRSBusiness.
420
421=cut
422
423sub OTRSBusinessGetDependencies {
424    my ( $Self, %Param ) = @_;
425
426    my @Packages = $Kernel::OM->Get('Kernel::System::Package')->RepositoryList();
427
428    my @DependentPackages;
429    PACKAGE:
430    for my $Package (@Packages) {
431
432        next PACKAGE if !IsHashRefWithData($Package);
433        next PACKAGE if !IsArrayRefWithData( $Package->{PackageRequired} );
434
435        DEPENDENCY:
436        for my $Dependency ( @{ $Package->{PackageRequired} } ) {
437
438            next DEPENDENCY if !IsHashRefWithData($Dependency);
439            next DEPENDENCY if !$Dependency->{Content};
440            next DEPENDENCY if $Dependency->{Content} ne 'OTRSBusiness';
441
442            push @DependentPackages, {
443                Name        => $Package->{Name}->{Content},
444                Vendor      => $Package->{Vendor}->{Content},
445                Version     => $Package->{Version}->{Content},
446                Description => $Package->{Description},
447            };
448
449            last DEPENDENCY;
450        }
451    }
452
453    return \@DependentPackages;
454}
455
456=head2 OTRSBusinessEntitlementCheck()
457
458determines the OTRSBusiness entitlement status of this system as reported by C<cloud.otrs.com>
459and stores it in the system_data cache.
460
461Returns 1 if the cloud call was successful.
462
463=cut
464
465sub OTRSBusinessEntitlementCheck {
466    my ( $Self, %Param ) = @_;
467
468    # If OTRSSTORM package is installed, system is able to do a Cloud request even if CloudService is disabled.
469    if (
470        !$Self->OTRSSTORMIsInstalled()
471        && $Self->{CloudServicesDisabled}
472        )
473    {
474        return;
475    }
476
477    my $CloudServiceObject = $Kernel::OM->Get('Kernel::System::CloudService::Backend::Run');
478    my $RequestResult      = $CloudServiceObject->Request(
479        RequestData => {
480            OTRSBusiness => [
481                {
482                    Operation => 'BusinessPermission',
483                    Data      => {},
484                },
485            ],
486        },
487    );
488
489    my $OperationResult;
490    if ( IsHashRefWithData($RequestResult) ) {
491        $OperationResult = $CloudServiceObject->OperationResultGet(
492            RequestResult => $RequestResult,
493            CloudService  => 'OTRSBusiness',
494            Operation     => 'BusinessPermission',
495        );
496    }
497
498    # OK, so we got a successful cloud call result. Then we will use it and remember it.
499    if ( IsHashRefWithData($OperationResult) && $OperationResult->{Success} ) {
500
501        # Store it in the SystemData so that it is also available for the notification modules,
502        #   even before the first run of RegistrationUpdate.
503        $Self->HandleBusinessPermissionCloudServiceResult(
504            OperationResult => $OperationResult,
505        );
506        return 1;
507    }
508
509    if ( !IsHashRefWithData($RequestResult) || !$RequestResult->{Success} ) {
510        my $Message = "BusinessPermission - Can't contact cloud.otrs.com server";
511        $Kernel::OM->Get('Kernel::System::Log')->Log(
512            Priority => 'error',
513            Message  => $Message
514        );
515    }
516
517    if ( !IsHashRefWithData($OperationResult) || !$OperationResult->{Success} ) {
518        my $Message = "BusinessPermission - could not perform BusinessPermission check";
519        if ( IsHashRefWithData($OperationResult) ) {
520            $Message .= $OperationResult->{ErrorMessage};
521        }
522        $Kernel::OM->Get('Kernel::System::Log')->Log(
523            Priority => 'error',
524            Message  => $Message
525        );
526    }
527
528    return 0;
529}
530
531=head2 OTRSBusinessEntitlementStatus()
532
533Returns the current entitlement status.
534
535    my $Status = $OTRSBusinessObject->OTRSBusinessEntitlementStatus(
536        CallCloudService => 1,              # 0 or 1, call the cloud service before looking at the cache
537    );
538
539    $Status = 'entitled';      # everything is OK
540    $Status = 'warning';       # last check was OK, and we are in the waiting period - show warning
541    $Status = 'warning-error'; # last check was OK, and we are past waiting period - show error message
542    $Status = 'forbidden';     # not entitled (either because the server said so or because the last check was too long ago)
543
544=cut
545
546sub OTRSBusinessEntitlementStatus {
547    my ( $Self, %Param ) = @_;
548
549    # If the system is not registered, it cannot have an OB permission.
550    #   Also, the BusinessPermissionChecks will not work any more, so the permission
551    #   would expire after our waiting period. But in this case we can immediately deny
552    #   the permission.
553    my $RegistrationState = $Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGet(
554        Key => 'Registration::State',
555    );
556    if ( !$RegistrationState || $RegistrationState ne 'registered' ) {
557        return 'forbidden';
558    }
559
560    # Cloud service is called and if cannot be connected, it must return 'forbidden'.
561    if ( $Param{CallCloudService} ) {
562        my $Check = $Self->OTRSBusinessEntitlementCheck();
563        return 'forbidden' if $Check == 0;
564    }
565
566    # OK. Let's look at the system_data cache now and use it if appropriate
567    my %EntitlementData = $Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGroupGet(
568        Group => 'OTRSBusiness',
569    );
570
571    if ( !%EntitlementData || !$EntitlementData{BusinessPermission} ) {
572        return 'forbidden';
573    }
574
575    # Check when the last successful BusinessPermission check was made.
576    my $DateTimeObject = $Kernel::OM->Create(
577        'Kernel::System::DateTime',
578        ObjectParams => {
579            String => $EntitlementData{LastUpdateTime},
580        },
581    );
582
583    my $Delta = $Kernel::OM->Create('Kernel::System::DateTime')->Delta(
584        DateTimeObject => $DateTimeObject,
585    );
586
587    if ( $Delta->{AbsoluteSeconds} > $Self->{NoConnectBlockPeriod} ) {
588        return 'forbidden';
589    }
590    if ( $Delta->{AbsoluteSeconds} > $Self->{NoConnectErrorPeriod} ) {
591        return 'warning-error';
592    }
593
594    # If we cannot connect to cloud.otrs.com for more than the first period, show a warning.
595    my $NoConnectWarningPeriod = 60 * 60 * 24 * 5;    # 5 days
596    if ( $Self->OTRSSTORMIsInstalled() ) {
597        $NoConnectWarningPeriod = 60 * 60 * 24 * 10;    # 10 days
598    }
599
600    if ( $Delta->{AbsoluteSeconds} > $NoConnectWarningPeriod ) {
601        return 'warning';
602    }
603
604    return 'entitled';
605}
606
607=head2 OTRSBusinessContractExpiryDateCheck()
608
609checks for the warning period before the contract expires
610
611    my $ExpiryDate = $OTRSBusinessObject->OTRSBusinessContractExpiryDateCheck();
612
613returns the ExpiryDate if a warning should be displayed
614
615    $ExpiryDate = undef;                    # everything is OK, no warning
616    $ExpiryDate = '2012-12-12 12:12:12'     # contract is about to expire, issue warning
617
618=cut
619
620sub OTRSBusinessContractExpiryDateCheck {
621    my ( $Self, %Param ) = @_;
622
623    if ( $Param{CallCloudService} ) {
624        $Self->OTRSBusinessEntitlementCheck();
625    }
626
627    # OK. Let's look at the system_data cache now and use it if appropriate
628    my %EntitlementData = $Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGroupGet(
629        Group => 'OTRSBusiness',
630    );
631
632    if ( !%EntitlementData || !$EntitlementData{ExpiryDate} ) {
633        return;
634    }
635
636    my $ExpiryDateTimeObj = $Kernel::OM->Create(
637        'Kernel::System::DateTime',
638        ObjectParams => {
639            String => $EntitlementData{ExpiryDate},
640        }
641    );
642
643    my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
644
645    my $Delta = $ExpiryDateTimeObj->Delta(
646        DateTimeObject => $DateTimeObject
647    );
648
649    if ( $Delta->{AbsoluteSeconds} < $Self->{ContractExpiryWarningPeriod} ) {
650        return $EntitlementData{ExpiryDate};
651    }
652
653    return;
654}
655
656sub HandleBusinessPermissionCloudServiceResult {
657    my ( $Self, %Param ) = @_;
658
659    my $OperationResult = $Param{OperationResult};
660
661    return if !$OperationResult->{Success};
662
663    # We store the current time as LastUpdateTime so that we know when the last
664    #   permission check could be successfully made with the server. This is needed
665    #   to determine if the results can still be used later, if a connection to
666    #   cloud.otrs.com cannot be made temporarily.
667    my %StoreData = (
668        BusinessPermission            => $OperationResult->{Data}->{BusinessPermission}            // 0,
669        ExpiryDate                    => $OperationResult->{Data}->{ExpiryDate}                    // '',
670        LastUpdateTime                => $Kernel::OM->Create('Kernel::System::DateTime')->ToString(),
671        AgentSessionLimit             => $OperationResult->{Data}->{AgentSessionLimit}             // 0,
672        AgentSessionLimitPriorWarning => $OperationResult->{Data}->{AgentSessionLimitPriorWarning} // 0,
673    );
674
675    my $SystemDataObject = $Kernel::OM->Get('Kernel::System::SystemData');
676
677    KEY:
678    for my $Key ( sort keys %StoreData ) {
679        next KEY if !defined $StoreData{$Key};
680
681        my $FullKey = 'OTRSBusiness::' . $Key;
682
683        if ( defined $SystemDataObject->SystemDataGet( Key => $FullKey ) ) {
684            $SystemDataObject->SystemDataUpdate(
685                Key    => $FullKey,
686                Value  => $StoreData{$Key},
687                UserID => 1,
688            );
689        }
690        else {
691            $SystemDataObject->SystemDataAdd(
692                Key    => $FullKey,
693                Value  => $StoreData{$Key},
694                UserID => 1,
695            );
696        }
697    }
698
699    return 1;
700}
701
702sub HandleBusinessVersionCheckCloudServiceResult {
703    my ( $Self, %Param ) = @_;
704
705    my $OperationResult = $Param{OperationResult};
706
707    return if !$OperationResult->{Success};
708
709    my %StoreData = (
710        LatestVersionForCurrentFramework => $OperationResult->{Data}->{LatestVersionForCurrentFramework} // '',
711        FrameworkUpdateAvailable         => $OperationResult->{Data}->{FrameworkUpdateAvailable}         // '',
712    );
713
714    my $SystemDataObject = $Kernel::OM->Get('Kernel::System::SystemData');
715
716    for my $Key ( sort keys %StoreData ) {
717        my $FullKey = 'OTRSBusiness::' . $Key;
718
719        if ( defined $SystemDataObject->SystemDataGet( Key => $FullKey ) ) {
720            $SystemDataObject->SystemDataUpdate(
721                Key    => $FullKey,
722                Value  => $StoreData{$Key},
723                UserID => 1,
724            );
725        }
726        else {
727            $SystemDataObject->SystemDataAdd(
728                Key    => $FullKey,
729                Value  => $StoreData{$Key},
730                UserID => 1,
731            );
732        }
733    }
734
735    return 1;
736}
737
738sub _OTRSBusinessFileGet {
739    my ( $Self, %Param ) = @_;
740
741    return if $Self->{CloudServicesDisabled};
742
743    my $CloudServiceObject = $Kernel::OM->Get('Kernel::System::CloudService::Backend::Run');
744    my $RequestResult      = $CloudServiceObject->Request(
745        RequestData => {
746            OTRSBusiness => [
747                {
748                    Operation => 'BusinessFileGet',
749                    Data      => {
750                        OnlyStable => $Self->{OnlyStable},
751                    },
752                },
753            ],
754        },
755    );
756
757    my $OperationResult;
758    if ( IsHashRefWithData($RequestResult) ) {
759        $OperationResult = $CloudServiceObject->OperationResultGet(
760            RequestResult => $RequestResult,
761            CloudService  => 'OTRSBusiness',
762            Operation     => 'BusinessFileGet',
763        );
764
765        if ( $OperationResult->{Success} && $OperationResult->{Data}->{Package} ) {
766            return $OperationResult->{Data}->{Package};
767        }
768    }
769
770    return;
771}
772
773=head2 OTRSBusinessInstall()
774
775downloads and installs OTRSBusiness.
776
777=cut
778
779sub OTRSBusinessInstall {
780    my ( $Self, %Param ) = @_;
781
782    my %Response = (
783        Success => 0,
784    );
785
786    my $PackageString = $Self->_OTRSBusinessFileGet();
787    return %Response if !$PackageString;
788
789    my $PackageObject = $Kernel::OM->Get('Kernel::System::Package');
790
791    # Parse package structure.
792    my %Structure = $PackageObject->PackageParse(
793        String    => $PackageString,
794        FromCloud => 1,
795    );
796
797    my %FrameworkCheck = $PackageObject->AnalyzePackageFrameworkRequirements(
798        Framework => $Structure{Framework},
799        NoLog     => 1,
800    );
801
802    if ( !$FrameworkCheck{Success} ) {
803        $FrameworkCheck{ShowBlock} = 'IncompatibleInfo';
804        return %FrameworkCheck;
805    }
806
807    my $Install = $Kernel::OM->Get('Kernel::System::Package')->PackageInstall(
808        String    => $PackageString,
809        FromCloud => 1,
810    );
811
812    return %Response if !$Install;
813
814    # now that we know that OTRSBusiness has been installed,
815    # we can just preset the cache instead of just swiping it.
816    $Kernel::OM->Get('Kernel::System::Cache')->Set(
817        Type  => $Self->{CacheType},
818        TTL   => $Self->{CacheTTL},
819        Key   => 'OTRSBusinessIsInstalled',
820        Value => 1,
821    );
822
823    $Response{Success} = 1;
824
825    return %Response;
826}
827
828=head2 OTRSBusinessReinstall()
829
830re-installs OTRSBusiness from local repository.
831
832=cut
833
834sub OTRSBusinessReinstall {
835    my ( $Self, %Param ) = @_;
836
837    my $Package = $Self->_GetOTRSBusinessPackageFromRepository();
838
839    # Package not found -> return failure
840    return if !$Package;
841
842    my $PackageString = $Kernel::OM->Get('Kernel::System::Package')->RepositoryGet(
843        Name    => $Package->{Name}->{Content},
844        Version => $Package->{Version}->{Content},
845    );
846
847    return $Kernel::OM->Get('Kernel::System::Package')->PackageReinstall(
848        String => $PackageString,
849    );
850}
851
852=head2 OTRSBusinessUpdate()
853
854downloads and updates OTRSBusiness.
855
856=cut
857
858sub OTRSBusinessUpdate {
859    my ( $Self, %Param ) = @_;
860
861    my %Response = (
862        Success => 0,
863    );
864    my $PackageString = $Self->_OTRSBusinessFileGet();
865    return if !$PackageString;
866
867    my $PackageObject = $Kernel::OM->Get('Kernel::System::Package');
868
869    # Parse package structure.
870    my %Structure = $PackageObject->PackageParse(
871        String    => $PackageString,
872        FromCloud => 1,
873    );
874
875    my %FrameworkCheck = $PackageObject->AnalyzePackageFrameworkRequirements(
876        Framework => $Structure{Framework},
877        NoLog     => 1,
878    );
879
880    if ( !$FrameworkCheck{Success} ) {
881        $FrameworkCheck{ShowBlock} = 'IncompatibleInfo';
882        return %FrameworkCheck;
883    }
884
885    my $Upgrade = $Kernel::OM->Get('Kernel::System::Package')->PackageUpgrade(
886        String    => $PackageString,
887        FromCloud => 1,
888    );
889
890    return %Response if !$Upgrade;
891
892    $Response{Success} = 1;
893    return %Response;
894}
895
896=head2 OTRSBusinessUninstall()
897
898removes OTRSBusiness from the system.
899
900=cut
901
902sub OTRSBusinessUninstall {
903    my ( $Self, %Param ) = @_;
904
905    my $Package = $Self->_GetOTRSBusinessPackageFromRepository();
906
907    # Package not found -> return failure
908    return if !$Package;
909
910    # TODO: the following code is now Deprecated and should be removed in further versions of OTRS
911    # get a list of all dynamic fields for ticket and article
912    my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
913    my $DynamicFieldList   = $DynamicFieldObject->DynamicFieldListGet(
914        Valid      => 0,
915        ObjectType => [ 'Ticket', 'Article' ],
916    );
917
918    # filter only dynamic fields added by OTRSBusiness
919    my %OTRSBusinessDynamicFieldTypes = (
920        ContactWithData => 1,
921        Database        => 1,
922    );
923
924    my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
925
926    DYNAMICFIELD:
927    for my $DynamicFieldConfig ( @{$DynamicFieldList} ) {
928        next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
929        next DYNAMICFIELD if !$OTRSBusinessDynamicFieldTypes{ $DynamicFieldConfig->{FieldType} };
930
931        # remove data from the field
932        my $ValuesDeleteSuccess = $DynamicFieldBackendObject->AllValuesDelete(
933            DynamicFieldConfig => $DynamicFieldConfig,
934            UserID             => 1,
935        );
936
937        if ( !$ValuesDeleteSuccess ) {
938            $Kernel::OM->Get('Kernel::System::Log')->Log(
939                Priority => 'error',
940                Message  => "Values from dynamic field $DynamicFieldConfig->{Name} could not be deleted!",
941            );
942        }
943
944        my $Success = $DynamicFieldObject->DynamicFieldDelete(
945            ID      => $DynamicFieldConfig->{ID},
946            UserID  => 1,
947            Reorder => 1,
948        );
949
950        if ( !$Success ) {
951            $Kernel::OM->Get('Kernel::System::Log')->Log(
952                Priority => 'error',
953                Message  => "Dynamic field $DynamicFieldConfig->{Name} could not be deleted!",
954            );
955        }
956    }
957
958    # TODO: end Deprecated
959
960    my $PackageString = $Kernel::OM->Get('Kernel::System::Package')->RepositoryGet(
961        Name    => $Package->{Name}->{Content},
962        Version => $Package->{Version}->{Content},
963    );
964
965    my $Uninstall = $Kernel::OM->Get('Kernel::System::Package')->PackageUninstall(
966        String => $PackageString,
967    );
968
969    return $Uninstall if !$Uninstall;
970
971    # now that we know that OTRSBusiness has been uninstalled,
972    # we can just preset the cache instead of just swiping it.
973    $Kernel::OM->Get('Kernel::System::Cache')->Set(
974        Type  => $Self->{CacheType},
975        TTL   => $Self->{CacheTTL},
976        Key   => 'OTRSBusinessIsInstalled',
977        Value => 0,
978    );
979
980    return $Uninstall;
981}
982
983=head2 OTRSBusinessCommandNextUpdateTimeSet()
984
985Set the next update time for the given command in the system data table storage.
986
987    my $Success = $OTRSBusinessObject->OTRSBusinessCommandNextUpdateTimeSet(
988        Command => 'AvailabilityCheck',
989    );
990
991Returns 1 if the next update time was set successfully.
992
993=cut
994
995sub OTRSBusinessCommandNextUpdateTimeSet {
996    my ( $Self, %Param ) = @_;
997
998    return if !$Param{Command};
999
1000    my $Key = "OTRSBusiness::$Param{Command}::NextUpdateTime";
1001
1002    my $SystemDataObject = $Kernel::OM->Get('Kernel::System::SystemData');
1003
1004    my $NextUpdateTime = $SystemDataObject->SystemDataGet(
1005        Key => $Key,
1006    );
1007
1008    # set the default next update seconds offset
1009    my $NextUpdateSecondsOffset = 60 * 60 * 24;
1010
1011    # generate a random seconds offset, if no next update time exists
1012    if ( !$NextUpdateTime ) {
1013
1014        # create the random numbers
1015        my $RandomHour   = int 20 + rand 23 - 20;
1016        my $RandomMinute = int rand 60;
1017
1018        # create the random seconds offset
1019        $NextUpdateSecondsOffset = 60 * 60 * $RandomHour + ( 60 * $RandomMinute );
1020    }
1021
1022    my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
1023    $DateTimeObject->Add( Seconds => $NextUpdateSecondsOffset );
1024    my $CalculatedNextUpdateTime = $DateTimeObject->ToString();
1025
1026    if ( defined $NextUpdateTime ) {
1027        $SystemDataObject->SystemDataUpdate(
1028            Key    => $Key,
1029            Value  => $CalculatedNextUpdateTime,
1030            UserID => 1,
1031        );
1032    }
1033    else {
1034        $SystemDataObject->SystemDataAdd(
1035            Key    => $Key,
1036            Value  => $CalculatedNextUpdateTime,
1037            UserID => 1,
1038        );
1039    }
1040
1041    return 1;
1042}
1043
1044sub _GetOTRSBusinessPackageFromRepository {
1045    my ( $Self, %Param ) = @_;
1046
1047    my $PackageObject = $Kernel::OM->Get('Kernel::System::Package');
1048
1049    my @RepositoryList = $PackageObject->RepositoryList();
1050
1051    for my $Package (@RepositoryList) {
1052        return $Package if $Package->{Name}->{Content} eq 'OTRSBusiness';
1053    }
1054
1055    return;
1056}
1057
1058sub _GetSTORMPackageFromRepository {
1059    my ( $Self, %Param ) = @_;
1060
1061    my $PackageObject = $Kernel::OM->Get('Kernel::System::Package');
1062
1063    my @RepositoryList = $PackageObject->RepositoryList(
1064        Result => 'short',
1065    );
1066
1067    for my $Package (@RepositoryList) {
1068
1069        return $Package if $Package->{Name} eq 'OTRSSTORM';
1070    }
1071
1072    return;
1073}
1074
1075sub _GetCONTROLPackageFromRepository {
1076    my ( $Self, %Param ) = @_;
1077
1078    my $PackageObject = $Kernel::OM->Get('Kernel::System::Package');
1079
1080    my @RepositoryList = $PackageObject->RepositoryList(
1081        Result => 'short',
1082    );
1083
1084    for my $Package (@RepositoryList) {
1085
1086        return $Package if $Package->{Name} eq 'OTRSCONTROL';
1087    }
1088
1089    return;
1090}
1091
10921;
1093
1094=head1 TERMS AND CONDITIONS
1095
1096This software is part of the OTRS project (L<https://otrs.org/>).
1097
1098This software comes with ABSOLUTELY NO WARRANTY. For details, see
1099the enclosed file COPYING for license information (GPL). If you
1100did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
1101
1102=cut
1103