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::CustomerGroup;
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::CustomerCompany',
20    'Kernel::System::CustomerGroup',
21    'Kernel::System::CustomerUser',
22    'Kernel::System::DB',
23    'Kernel::System::Group',
24    'Kernel::System::Log',
25    'Kernel::System::Valid',
26);
27
28=head1 NAME
29
30Kernel::System::CustomerGroup - customer group lib
31
32=head1 DESCRIPTION
33
34All customer group functions. E. g. to add groups or to get a member list of a group.
35
36=head1 PUBLIC INTERFACE
37
38=head2 new()
39
40Don't use the constructor directly, use the ObjectManager instead:
41
42    my $CustomerGroupObject = $Kernel::OM->Get('Kernel::System::CustomerGroup');
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->{CacheType} = 'CustomerGroup';
54    $Self->{CacheTTL}  = 60 * 60 * 24 * 20;
55
56    return $Self;
57}
58
59=head2 GroupMemberAdd()
60
61to add a member to a group
62
63    Permission: ro,move_into,priority,create,rw
64
65    my $Success = $CustomerGroupObject->GroupMemberAdd(
66        GID => 12,
67        UID => 6,
68        Permission => {
69            ro        => 1,
70            move_into => 1,
71            create    => 1,
72            owner     => 1,
73            priority  => 0,
74            rw        => 0,
75        },
76        UserID => 123,
77    );
78
79=cut
80
81sub GroupMemberAdd {
82    my ( $Self, %Param ) = @_;
83
84    # check needed stuff
85    for (qw(UID GID UserID Permission)) {
86        if ( !$Param{$_} ) {
87            $Kernel::OM->Get('Kernel::System::Log')->Log(
88                Priority => 'error',
89                Message  => "Need $_!",
90            );
91            return;
92        }
93    }
94
95    # check rw rule (set only rw and remove rest, because it's including all in rw)
96    if ( $Param{Permission}->{rw} ) {
97        $Param{Permission} = { rw => 1 };
98    }
99
100    # get database object
101    my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
102
103    # update permission
104    TYPE:
105    for my $Type ( sort keys %{ $Param{Permission} } ) {
106
107        # delete existing permission
108        $DBObject->Do(
109            SQL => 'DELETE FROM group_customer_user WHERE '
110                . ' group_id = ? AND user_id = ? AND permission_key = ?',
111            Bind => [ \$Param{GID}, \$Param{UID}, \$Type ],
112        );
113
114        # debug
115        if ( $Self->{Debug} ) {
116            $Kernel::OM->Get('Kernel::System::Log')->Log(
117                Priority => 'notice',
118                Message =>
119                    "Add UID:$Param{UID} to GID:$Param{GID}, $Type:$Param{Permission}->{$Type}!",
120            );
121        }
122
123        # insert new permission (if needed)
124        next TYPE if !$Param{Permission}->{$Type};
125
126        $DBObject->Do(
127            SQL => 'INSERT INTO group_customer_user '
128                . '(user_id, group_id, permission_key, permission_value, '
129                . 'create_time, create_by, change_time, change_by) '
130                . 'VALUES (?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)',
131            Bind => [
132                \$Param{UID}, \$Param{GID}, \$Type, \$Param{Permission}->{$Type}, \$Param{UserID},
133                \$Param{UserID},
134            ],
135        );
136    }
137
138    # delete cache
139    # remove complete CustomerGroup cache because
140    #   GroupMemberList() cache is CustomerUserID based
141    $Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
142        Type => $Self->{CacheType},
143    );
144
145    return 1;
146}
147
148=head2 GroupMemberList()
149
150Get users of the given group.
151
152    my %Users = $CustomerGroupObject->GroupMemberList(
153        GroupID        => '123',
154        Type           => 'move_into', # ro|move_into|priority|create|rw
155        Result         => 'HASH',      # return hash of user id => user name entries
156        RawPermissions => 0,           # 0 (return inherited permissions from CustomerCompany), default
157                                       # 1 (return only direct permissions)
158    );
159
160or
161
162    my @UserIDs = $CustomerGroupObject->GroupMemberList(
163        GroupID        => '123',
164        Type           => 'move_into', # ro|move_into|priority|create|rw
165        Result         => 'ID',        # return array of user ids
166        RawPermissions => 0,           # 0 (return inherited permissions from CustomerCompany), default
167                                       # 1 (return only direct permissions)
168    );
169
170or
171
172    my @UserNames = $CustomerGroupObject->GroupMemberList(
173        GroupID        => '123',
174        Type           => 'move_into', # ro|move_into|priority|create|rw
175        Result         => 'Name',        # return array of user names
176        RawPermissions => 0,           # 0 (return inherited permissions from CustomerCompany), default
177                                       # 1 (return only direct permissions)
178    );
179
180Get groups of given user.
181
182    my %Groups = $CustomerGroupObject->GroupMemberList(
183        UserID         => '123',
184        Type           => 'move_into', # ro|move_into|priority|create|rw
185        Result         => 'HASH',      # return hash of group id => group name entries
186        RawPermissions => 0,           # 0 (return inherited permissions from CustomerCompany), default
187                                       # 1 (return only direct permissions)
188    );
189
190or
191
192    my @GroupIDs = $CustomerGroupObject->GroupMemberList(
193        UserID         => '123',
194        Type           => 'move_into', # ro|move_into|priority|create|rw
195        Result         => 'ID',        # return array of group ids
196        RawPermissions => 0,           # 0 (return inherited permissions from CustomerCompany), default
197                                       # 1 (return only direct permissions)
198    );
199
200or
201
202    my @GroupNames = $CustomerGroupObject->GroupMemberList(
203        UserID         => '123',
204        Type           => 'move_into', # ro|move_into|priority|create|rw
205        Result         => 'Name',        # return array of group names
206        RawPermissions => 0,           # 0 (return inherited permissions from CustomerCompany), default
207                                       # 1 (return only direct permissions)
208    );
209
210=cut
211
212sub GroupMemberList {
213    my ( $Self, %Param ) = @_;
214
215    # check needed stuff
216    for my $Needed (qw(Result Type)) {
217        if ( !$Param{$Needed} ) {
218            $Kernel::OM->Get('Kernel::System::Log')->Log(
219                Priority => 'error',
220                Message  => "Need $Needed!",
221            );
222            return;
223        }
224    }
225    if ( !$Param{UserID} && !$Param{GroupID} ) {
226        $Kernel::OM->Get('Kernel::System::Log')->Log(
227            Priority => 'error',
228            Message  => 'Need UserID or GroupID!'
229        );
230        return;
231    }
232
233    # create cache key
234    my $CacheKey = 'GroupMemberList::' . $Param{Type} . '::';
235    if ( $Param{RawPermissions} ) {
236        $CacheKey .= "Raw::";
237    }
238    if ( $Param{UserID} ) {
239        $CacheKey .= "UserID::$Param{UserID}";
240    }
241    else {
242        $CacheKey .= "GroupID::$Param{GroupID}";
243    }
244
245    # check cache
246    my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
247        Type => $Self->{CacheType},
248        Key  => $CacheKey,
249    );
250
251    if ($Cache) {
252        if ( $Param{Result} eq 'HASH' ) {
253            return %{$Cache};
254        }
255        elsif ( $Param{Result} eq 'ID' ) {
256            return ( sort keys %{$Cache} );
257        }
258        elsif ( $Param{Result} eq 'Name' ) {
259            return ( sort values %{$Cache} );
260        }
261        return;
262    }
263
264    my %Data;
265
266    # check if customer group feature is active, if not, return all groups
267    if ( !$Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupSupport') ) {
268
269        # get permissions
270        %Data = $Kernel::OM->Get('Kernel::System::Group')->GroupList( Valid => 1 );
271    }
272    else {
273        # get database object
274        my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
275
276        # if it's active, return just the permitted groups
277        my $SQL =
278            'SELECT g.id, g.name, gu.permission_key, gu.permission_value, gu.user_id'
279            . ' FROM groups g, group_customer_user gu'
280            . ' WHERE g.valid_id IN ( ' . join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet() . ')'
281            . ' AND g.id = gu.group_id AND gu.permission_value = 1'
282            . " AND gu.permission_key IN (?, 'rw')";
283        my @Bind = ( \$Param{Type} );
284
285        if ( $Param{UserID} ) {
286            $SQL .= ' AND gu.user_id = ?';
287            push @Bind, \$Param{UserID};
288        }
289        else {
290            $SQL .= ' AND gu.group_id = ?';
291            push @Bind, \$Param{GroupID};
292        }
293
294        $DBObject->Prepare(
295            SQL  => $SQL,
296            Bind => \@Bind,
297        );
298
299        while ( my @Row = $DBObject->FetchrowArray() ) {
300            if ( $Param{UserID} ) {
301                $Data{ $Row[0] } = $Row[1];
302            }
303            else {
304                $Data{ $Row[4] } = $Row[1];
305            }
306        }
307
308        my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
309
310        for my $Key ( sort keys %Data ) {
311
312            # Bugfix #12285 - Check if customer user is valid.
313            if ( $Param{GroupID} ) {
314
315                my %User = $CustomerUserObject->CustomerUserDataGet(
316                    User => $Key,
317                );
318
319                if ( defined $User{ValidID} && $User{ValidID} != 1 ) {
320                    delete $Data{$Key};
321                }
322            }
323        }
324
325        # add customer company groups
326        if ( !$Param{RawPermissions} && $Param{UserID} ) {
327            my @CustomerIDs = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerIDs(
328                User => $Param{UserID},
329            );
330
331            for my $CustomerID (@CustomerIDs) {
332                my %CustomerGroups = $Self->GroupCustomerList(
333                    CustomerID => $CustomerID,
334                    Type       => $Param{Type},
335                    Result     => 'HASH',
336                );
337                GROUPID:
338                for my $GroupID ( sort keys %CustomerGroups ) {
339                    next GROUPID if $Data{$GroupID};
340                    $Data{$GroupID} = $CustomerGroups{$GroupID};
341                }
342            }
343        }
344        elsif ( !$Param{RawPermissions} ) {
345            my %CustomerGroups = $Self->GroupCustomerList(
346                GroupID => $Param{GroupID},
347                Type    => $Param{Type},
348                Result  => 'HASH',
349            );
350
351            my $CustomerUserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
352            for my $CustomerID ( sort keys %CustomerGroups ) {
353                my %CustomerUsers = $CustomerUserObject->CustomerSearch(
354                    CustomerIDRaw => $CustomerID,
355                    Valid         => 1,
356                );
357                CUSTOMERUSERID:
358                for my $CustomerUserID ( sort keys %CustomerUsers ) {
359                    next CUSTOMERUSERID if $Data{$CustomerUserID};
360                    $Data{$CustomerUserID} = $CustomerGroups{$CustomerID};
361                }
362            }
363        }
364    }
365
366    # add always groups if groups are requested
367    if (
368        $Param{UserID}
369        && $Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupAlwaysGroups')
370        )
371    {
372        my %Groups        = $Kernel::OM->Get('Kernel::System::Group')->GroupList( Valid => 1 );
373        my %GroupsReverse = reverse %Groups;
374        ALWAYSGROUP:
375        for my $AlwaysGroup ( @{ $Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupAlwaysGroups') } ) {
376            next ALWAYSGROUP if !$GroupsReverse{$AlwaysGroup};
377            next ALWAYSGROUP if $Data{ $GroupsReverse{$AlwaysGroup} };
378            $Data{ $GroupsReverse{$AlwaysGroup} } = $AlwaysGroup;
379        }
380    }
381
382    # set cache
383    $Kernel::OM->Get('Kernel::System::Cache')->Set(
384        Type  => $Self->{CacheType},
385        TTL   => $Self->{CacheTTL},
386        Key   => $CacheKey,
387        Value => \%Data,
388    );
389
390    # return data depending on requested result
391    if ( $Param{Result} eq 'HASH' ) {
392        return %Data;
393    }
394    elsif ( $Param{Result} eq 'ID' ) {
395        return ( sort keys %Data );
396    }
397    elsif ( $Param{Result} eq 'Name' ) {
398        return ( sort values %Data );
399    }
400    return;
401}
402
403=head2 GroupCustomerAdd()
404
405to add a customer to a group
406
407    Permission types: e.g. ro,move_into,priority,create,rw
408    Permission context: e.g. Ticket::CustomerID::Same, Ticket::CustomerID::Other
409
410    my $Success = $CustomerGroupObject->GroupCustomerAdd(
411        GID        => 12,
412        CustomerID => 'customer-company',
413        Permission => {
414            'Ticket::CustomerID::Same' => {
415                ro            => 1,
416                move_into     => 1,
417                create        => 1,
418                owner         => 1,
419                priority      => 0,
420                rw            => 0,
421            },
422            'Ticket::CustomerID::Other' => {
423                ro        => 1,
424                move_into => 1,
425                create    => 1,
426                owner     => 1,
427                priority  => 0,
428                rw        => 0,
429            },
430            ...
431        },
432        UserID => 123,
433    );
434
435=cut
436
437sub GroupCustomerAdd {
438    my ( $Self, %Param ) = @_;
439
440    # check needed stuff
441    for my $Needed (qw(CustomerID GID UserID Permission)) {
442        if ( !$Param{$Needed} ) {
443            $Kernel::OM->Get('Kernel::System::Log')->Log(
444                Priority => 'error',
445                Message  => "Need $Needed!",
446            );
447            return;
448        }
449    }
450
451    # check rw rule (set only rw and remove rest, because it's including all in rw)
452    my @Contexts = $Self->GroupContextNameList();
453    CONTEXT:
454    for my $Context (@Contexts) {
455        next CONTEXT if !$Param{Permission}->{$Context}->{rw};
456        $Param{Permission}->{$Context} = { rw => 1 };
457    }
458
459    # get database object
460    my $DBObject    = $Kernel::OM->Get('Kernel::System::DB');
461    my $Permissions = $Kernel::OM->Get('Kernel::Config')->Get('System::Customer::Permission');
462
463    # update permission
464    CONTEXT:
465    for my $Context (@Contexts) {
466        next CONTEXT if !IsHashRefWithData( $Param{Permission}->{$Context} );
467
468        # delete existing permission
469        $DBObject->Do(
470            SQL => 'DELETE FROM group_customer WHERE '
471                . ' group_id = ? AND customer_id = ? AND '
472                . ' permission_context = ?',
473            Bind => [ \$Param{GID}, \$Param{CustomerID}, \$Context ],
474        );
475
476        # insert new permission (if needed)
477        TYPE:
478        for my $Type ( @{$Permissions} ) {
479            next TYPE if !$Param{Permission}->{$Context}->{$Type};
480
481            # debug
482            if ( $Self->{Debug} ) {
483                $Kernel::OM->Get('Kernel::System::Log')->Log(
484                    Priority => 'notice',
485                    Message =>
486                        "Add CustomerID:$Param{CustomerID} to GID:$Param{GID}, $Type:$Param{Permission}->{$Context}->{$Type}, Context:$Context!",
487                );
488            }
489
490            $DBObject->Do(
491                SQL => 'INSERT INTO group_customer '
492                    . '(customer_id, group_id, permission_key, permission_value, '
493                    . 'permission_context, create_time, create_by, change_time, change_by) '
494                    . 'VALUES (?, ?, ?, ?, ?, current_timestamp, ?, current_timestamp, ?)',
495                Bind => [
496                    \$Param{CustomerID}, \$Param{GID}, \$Type, \$Param{Permission}->{$Context}->{$Type},
497                    \$Context, \$Param{UserID}, \$Param{UserID},
498                ],
499            );
500        }
501    }
502
503    # delete cache
504    # remove complete CustomerGroup cache because
505    #   it affects GroupMemberList() which is CustomerUserID based
506    $Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
507        Type => $Self->{CacheType},
508    );
509
510    return 1;
511}
512
513=head2 GroupCustomerList()
514
515Get customers of the given group.
516
517    my %Customers = $CustomerGroupObject->GroupCustomerList(
518        GroupID => '123',
519        Type    => 'ro',    # ro|move_into|priority|create|owner|rw
520        Context => 'Ticket::CustomerID::Same',
521                            # permissions to same company tickets, default context
522        Result  => 'HASH',  # return hash of customer id => group name entries
523    );
524
525or
526
527    my @CustomerIDs = $CustomerGroupObject->GroupCustomerList(
528        GroupID => '123',
529        Type    => 'ro',    # ro|move_into|priority|create|owner|rw
530        Context => 'Ticket::CustomerID::Same',
531                            # permissions to same company tickets, default context
532        Result  => 'ID',    # return array of customer ids
533    );
534
535or
536
537    my @CustomerNames = $CustomerGroupObject->GroupCustomerList(
538        GroupID => '123',
539        Type    => 'ro',    # ro|move_into|priority|create|owner|rw
540        Context => 'Ticket::CustomerID::Same',
541                            # permissions to same company tickets, default context
542        Result  => 'Name',  # return array of customer ids
543    );
544
545Get groups of given customer.
546
547    my %Groups = $CustomerGroupObject->GroupCustomerList(
548        CustomerID => '123',
549        Type       => 'ro',     # ro|move_into|priority|create|owner|rw
550        Context => 'Ticket::CustomerID::Same',
551                            # permissions to same company tickets, default context
552        Result     => 'HASH',   # return hash of group id => group name entries
553    );
554
555or
556
557    my @GroupIDs = $CustomerGroupObject->GroupCustomerList(
558        CustomerID => '123',
559        Type       => 'ro',     # ro|move_into|priority|create|owner|rw
560        Context => 'Ticket::CustomerID::Same',
561                            # permissions to same company tickets, default context
562        Result     => 'ID',     # return array of group ids
563    );
564
565or
566
567    my @GroupNames = $CustomerGroupObject->GroupCustomerList(
568        CustomerID => '123',
569        Type       => 'ro',     # ro|move_into|priority|create|owner|rw
570        Context => 'Ticket::CustomerID::Same',
571                            # permissions to same company tickets, default context
572        Result     => 'Name',   # return array of group names
573    );
574
575=cut
576
577sub GroupCustomerList {
578    my ( $Self, %Param ) = @_;
579
580    # check needed stuff
581    for my $Needed (qw(Result Type)) {
582        if ( !$Param{$Needed} ) {
583            $Kernel::OM->Get('Kernel::System::Log')->Log(
584                Priority => 'error',
585                Message  => "Need $Needed!",
586            );
587            return;
588        }
589    }
590    if ( !$Param{CustomerID} && !$Param{GroupID} ) {
591        $Kernel::OM->Get('Kernel::System::Log')->Log(
592            Priority => 'error',
593            Message  => 'Need CustomerID or GroupID!',
594        );
595        return;
596    }
597
598    # fallback to the default context
599    if ( !$Param{Context} ) {
600        $Param{Context} = $Self->GroupContextNameGet(
601            SysConfigName => '001-CustomerID-same',
602        );
603    }
604
605    # create cache key
606    my $CacheKey = 'GroupCustomerList::' . $Param{Type} . '::' . $Param{Context} . '::';
607    if ( $Param{CustomerID} ) {
608        $CacheKey .= 'CustomerID::' . $Param{CustomerID};
609    }
610    else {
611        $CacheKey .= 'GroupID::' . $Param{GroupID};
612    }
613
614    # check cache
615    my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
616        Type => $Self->{CacheType},
617        Key  => $CacheKey,
618    );
619    if ($Cache) {
620        if ( $Param{Result} eq 'HASH' ) {
621            return %{$Cache};
622        }
623        elsif ( $Param{Result} eq 'ID' ) {
624            return ( sort keys %{$Cache} );
625        }
626        elsif ( $Param{Result} eq 'Name' ) {
627            return ( sort values %{$Cache} );
628        }
629        return;
630    }
631
632    my %Data;
633
634    # check if customer group feature is active, if not, return all groups
635    if ( !$Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupSupport') ) {
636
637        # get permissions
638        %Data = $Kernel::OM->Get('Kernel::System::Group')->GroupList( Valid => 1 );
639    }
640    else {
641        # get database object
642        my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
643
644        # if it's active, return just the permitted groups
645        my $SQL =
646            'SELECT g.id, g.name, gc.permission_key, gc.permission_value, gc.customer_id'
647            . ' FROM groups g, group_customer gc'
648            . ' WHERE g.valid_id IN ( ' . join ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet() . ')'
649            . ' AND g.id = gc.group_id AND gc.permission_value = 1'
650            . " AND gc.permission_key IN (?, 'rw')"
651            . ' AND gc.permission_context = ?';
652        my @Bind = ( \$Param{Type}, \$Param{Context} );
653
654        if ( $Param{CustomerID} ) {
655            $SQL .= ' AND gc.customer_id = ?';
656            push @Bind, \$Param{CustomerID};
657        }
658        else {
659            $SQL .= ' AND gc.group_id = ?';
660            push @Bind, \$Param{GroupID};
661        }
662        $DBObject->Prepare(
663            SQL  => $SQL,
664            Bind => \@Bind,
665        );
666        while ( my @Row = $DBObject->FetchrowArray() ) {
667            if ( $Param{CustomerID} ) {
668                $Data{ $Row[0] } = $Row[1];
669            }
670            else {
671                $Data{ $Row[4] } = $Row[1];
672            }
673        }
674    }
675
676    # add always groups if groups are requested
677    # don't add them for non-default context (same CustomerID permission) requests
678    my $DefaultContextName = $Self->GroupContextNameGet(
679        SysConfigName => '001-CustomerID-same',
680    );
681    if (
682        $Param{CustomerID}
683        && $Param{Context} eq $DefaultContextName
684        && $Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupCompanyAlwaysGroups')
685        )
686    {
687        my %Groups        = $Kernel::OM->Get('Kernel::System::Group')->GroupList( Valid => 1 );
688        my %GroupsReverse = reverse %Groups;
689        ALWAYSGROUP:
690        for my $AlwaysGroup ( @{ $Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupCompanyAlwaysGroups') } ) {
691            next ALWAYSGROUP if !$GroupsReverse{$AlwaysGroup};
692            next ALWAYSGROUP if $Data{ $GroupsReverse{$AlwaysGroup} };
693            $Data{ $GroupsReverse{$AlwaysGroup} } = $AlwaysGroup;
694        }
695    }
696
697    # set cache
698    $Kernel::OM->Get('Kernel::System::Cache')->Set(
699        Type  => $Self->{CacheType},
700        TTL   => $Self->{CacheTTL},
701        Key   => $CacheKey,
702        Value => \%Data,
703    );
704
705    # return data depending on requested result
706    if ( $Param{Result} eq 'HASH' ) {
707        return %Data;
708    }
709    elsif ( $Param{Result} eq 'ID' ) {
710        return ( sort keys %Data );
711    }
712    elsif ( $Param{Result} eq 'Name' ) {
713        return ( sort values %Data );
714    }
715    return;
716}
717
718=head2 GroupContextNameGet()
719
720Helper function to get currently configured name of a specific group access context
721
722    my $ContextName = $CustomerGroupObject->GroupContextNameGet(
723        SysConfigName => '100-CustomerID-other', # optional, defaults to '001-CustomerID-same'
724    );
725
726=cut
727
728sub GroupContextNameGet {
729    my ( $Self, %Param ) = @_;
730
731    # get config name
732    # fallback to 'normal' group permission config
733    $Param{SysConfigName} ||= '001-CustomerID-same';
734
735    my $ContextConfig = $Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupPermissionContext');
736    return if !IsHashRefWithData($ContextConfig);
737    return if !IsHashRefWithData( $ContextConfig->{ $Param{SysConfigName} } );
738
739    return $ContextConfig->{ $Param{SysConfigName} }->{Value};
740}
741
742=head2 GroupContextNameList()
743
744Helper function to get the names of all configured group access contexts
745
746    my @ContextNames = $CustomerGroupObject->GroupContextNameList();
747
748=cut
749
750sub GroupContextNameList {
751    my ( $Self, %Param ) = @_;
752
753    my $ContextConfig = $Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupPermissionContext');
754    return () if !IsHashRefWithData($ContextConfig);
755
756    # fill list
757    my @ContextNames;
758    CONTEXT:
759    for my $Item ( sort keys %{$ContextConfig} ) {
760        next CONTEXT if !IsHashRefWithData( $ContextConfig->{$Item} );
761        next CONTEXT if !$ContextConfig->{$Item}->{Value};
762
763        push @ContextNames, $ContextConfig->{$Item}->{Value};
764    }
765
766    return @ContextNames;
767}
768
769=head2 GroupContextCustomers()
770
771Get all customer companies of the given customer user,
772including those associated via context based permissions.
773
774    my %Customers = $CustomerGroupObject->GroupContextCustomers(
775        CustomerUserID => '123',
776    );
777
778Returns hash with Customer IDs as key and Customer Company Name as value:
779
780    %Customers = {
781      '001' => 'Customer Company 1',
782      '002' => 'Customer Company 2',
783    };
784
785=cut
786
787sub GroupContextCustomers {
788    my ( $Self, %Param ) = @_;
789
790    # check needed stuff
791    if ( !$Param{CustomerUserID} ) {
792        $Kernel::OM->Get('Kernel::System::Log')->Log(
793            Priority => 'error',
794            Message  => 'Need CustomerUserID!',
795        );
796        return;
797    }
798
799    # no cache is used because of too many factors outside our control
800
801    # get customer ids from backend
802    my @CustomerIDs = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerIDs(
803        User => $Param{CustomerUserID},
804    );
805
806    # check for access to other CustomerIDs via group assignment
807    # add all combinations based on context bases group access
808    my $ExtraPermissionContext = $Self->GroupContextNameGet(
809        SysConfigName => '100-CustomerID-other',
810    );
811    if (
812        $Kernel::OM->Get('Kernel::Config')->Get('CustomerGroupSupport')
813        && $ExtraPermissionContext
814        )
815    {
816
817        # for all CustomerIDs get groups with extra access
818        my %ExtraPermissionGroups;
819        CUSTOMERID:
820        for my $CustomerID (@CustomerIDs) {
821            my %GroupList = $Self->GroupCustomerList(
822                CustomerID => $CustomerID,
823                Type       => 'ro',
824                Context    => $ExtraPermissionContext,
825                Result     => 'HASH',
826            );
827            next CUSTOMERID if !%GroupList;
828
829            # add to groups
830            %ExtraPermissionGroups = (
831                %ExtraPermissionGroups,
832                %GroupList,
833            );
834        }
835
836        # add all accessible CustomerIDs
837        GROUPID:
838        for my $GroupID ( sort keys %ExtraPermissionGroups ) {
839            my @ExtraCustomerIDs = $Self->GroupCustomerList(
840                GroupID => $GroupID,
841                Type    => 'ro',
842                Result  => 'ID',
843            );
844            next GROUPID if !@ExtraCustomerIDs;
845
846            # add to CustomerIDs
847            push @CustomerIDs, @ExtraCustomerIDs;
848        }
849    }
850
851    # get all customer companies for quick name lookup
852    my %AllCustomers = $Kernel::OM->Get('Kernel::System::CustomerCompany')->CustomerCompanyList(
853        Valid => 1,
854        Limit => 0,
855    );
856
857    # filter results using valid customers, add customer name to results
858    my %Customers;
859    CUSTOMERID:
860    for my $CustomerID (@CustomerIDs) {
861        next CUSTOMERID if !$AllCustomers{$CustomerID};
862        next CUSTOMERID if $Customers{$CustomerID};
863        $Customers{$CustomerID} = $AllCustomers{$CustomerID};
864    }
865
866    return %Customers;
867}
868
869=head2 GroupLookup()
870
871get id or name for group
872
873    my $Group = $CustomerGroupObject->GroupLookup(GroupID => $GroupID);
874
875    my $GroupID = $CustomerGroupObject->GroupLookup(Group => $Group);
876
877=cut
878
879sub GroupLookup {
880    my ( $Self, %Param ) = @_;
881
882    # check needed stuff
883    if ( !$Param{Group} && !$Param{GroupID} ) {
884        $Kernel::OM->Get('Kernel::System::Log')->Log(
885            Priority => 'error',
886            Message  => 'Got no Group or GroupID!',
887        );
888        return;
889    }
890
891    # check if result is cached
892    my $CacheKey;
893    if ( $Param{GroupID} ) {
894        $CacheKey = "GroupLookup::ID::$Param{GroupID}";
895    }
896    elsif ( $Param{Group} ) {
897        $CacheKey = "GroupLookup::Name::$Param{Group}";
898    }
899
900    my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
901        Type => $Self->{CacheType},
902        Key  => $CacheKey,
903    );
904    return ${$Cache} if ( ref $Cache eq 'SCALAR' );
905
906    # get database object
907    my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
908
909    # get data
910    my $SQL;
911    my @Bind;
912    my $Suffix;
913    if ( $Param{Group} ) {
914        $Param{What} = $Param{Group};
915        $Suffix      = 'GroupID';
916        $SQL         = 'SELECT id FROM groups WHERE name = ?';
917        push @Bind, \$Param{Group};
918    }
919    else {
920        $Param{What} = $Param{GroupID};
921        $Suffix      = 'Group';
922        $SQL         = 'SELECT name FROM groups WHERE id = ?';
923        push @Bind, \$Param{GroupID};
924    }
925    return if !$DBObject->Prepare(
926        SQL  => $SQL,
927        Bind => \@Bind,
928    );
929
930    my $Result;
931    while ( my @Row = $DBObject->FetchrowArray() ) {
932
933        # store result
934        $Result = $Row[0];
935    }
936
937    # check if data exists
938    if ( !$Result ) {
939        $Kernel::OM->Get('Kernel::System::Log')->Log(
940            Priority => 'error',
941            Message  => "Found no \$$Suffix for $Param{What}!",
942        );
943        return;
944    }
945
946    # set cache
947    $Kernel::OM->Get('Kernel::System::Cache')->Set(
948        Type  => $Self->{CacheType},
949        TTL   => $Self->{CacheTTL},
950        Key   => $CacheKey,
951        Value => \$Result,
952    );
953
954    return $Result;
955}
956
957=head2 PermissionCheck()
958
959Check if a customer user has a certain permission for a certain group.
960
961    my $HasPermission = $CustomerGroupObject->PermissionCheck(
962        UserID    => $UserID,
963        GroupName => $GroupName,
964        Type      => 'move_into',
965    );
966
967=cut
968
969sub PermissionCheck {
970    my ( $Self, %Param ) = @_;
971
972    # check needed stuff
973    for (qw(UserID GroupName Type)) {
974        if ( !$Param{$_} ) {
975            $Kernel::OM->Get('Kernel::System::Log')->Log(
976                Priority => 'error',
977                Message  => "Need $_!",
978            );
979            return;
980        }
981    }
982
983    my %GroupMemberList = reverse $Self->GroupMemberList(
984        UserID => $Param{UserID},
985        Type   => $Param{Type},
986        Result => 'HASH',
987    );
988
989    return $GroupMemberList{ $Param{GroupName} } ? 1 : 0;
990}
991
9921;
993
994=head1 TERMS AND CONDITIONS
995
996This software is part of the OTRS project (L<https://otrs.org/>).
997
998This software comes with ABSOLUTELY NO WARRANTY. For details, see
999the enclosed file COPYING for license information (GPL). If you
1000did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
1001
1002=cut
1003