Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / rt / lib / RT / Record / Role / Links.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2 #
3 # COPYRIGHT:
4 #
5 # This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
6 #                                          <sales@bestpractical.com>
7 #
8 # (Except where explicitly superseded by other copyright notices)
9 #
10 #
11 # LICENSE:
12 #
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
16 # from www.gnu.org.
17 #
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 # General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28 #
29 #
30 # CONTRIBUTION SUBMISSION POLICY:
31 #
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
37 #
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
46 #
47 # END BPS TAGGED BLOCK }}}
48
49 use strict;
50 use warnings;
51
52 package RT::Record::Role::Links;
53 use Role::Basic;
54
55 =head1 NAME
56
57 RT::Record::Role::Links - Common methods for records which handle links
58
59 =head1 REQUIRES
60
61 =head2 L<RT::Record::Role>
62
63 =head2 _AddLink
64
65 Usually provided by L<RT::Record/_AddLink>.
66
67 =head2 _DeleteLink
68
69 Usually provided by L<RT::Record/_DeleteLink>.
70
71 =head2 ModifyLinkRight
72
73 The right name to check in L<AddLink> and L<DeleteLink>.
74
75 =head2 CurrentUserHasRight
76
77 =cut
78
79 with 'RT::Record::Role';
80
81 requires '_AddLink';
82 requires '_DeleteLink';
83
84 requires 'ModifyLinkRight';
85 requires 'CurrentUserHasRight';
86
87 =head1 PROVIDES
88
89 =head2 _AddLinksOnCreate
90
91 Calls _AddLink (usually L<RT::Record/_AddLink>) for all valid link types and
92 aliases found in the hash.  Refer to L<RT::Link/%TYPEMAP> for details of link
93 types.  Key values may be a single URI or an arrayref of URIs.
94
95 Takes two hashrefs.  The first is the argument hash provided to the consuming
96 class's Create method.  The second is optional and contains extra arguments to
97 pass to _AddLink.
98
99 By default records a transaction on the link's destination object (if any), but
100 not on the origin object.
101
102 Returns an array of localized error messages, if any.
103
104 =cut
105
106 sub _AddLinksOnCreate {
107     my $self    = shift;
108     my %args    = %{shift || {}};
109     my %AddLink = %{shift || {}};
110     my @results;
111
112     foreach my $type ( keys %RT::Link::TYPEMAP ) {
113         next unless defined $args{$type};
114
115         my $links = $args{$type};
116            $links = [$links] unless ref $links;
117
118         for my $link (@$links) {
119             my $typemap       = $RT::Link::TYPEMAP{$type};
120             my $opposite_mode = $typemap->{Mode} eq "Base" ? "Target" : "Base";
121             my ($ok, $msg) = $self->_AddLink(
122                 Type                    => $typemap->{Type},
123                 $typemap->{Mode}        => $link,
124                 "Silent$opposite_mode"  => 1,
125                 %AddLink,
126             );
127             push @results,
128                  $self->loc("Unable to add [_1] link: [_2]", $self->loc($type), $msg)
129                      unless $ok;
130         }
131     }
132     return @results;
133 }
134
135 =head2 AddLink
136
137 Takes a paramhash of Type and one of Base or Target. Adds that link to this
138 record.
139
140 Refer to L<RT::Record/_AddLink> for full documentation.  This method implements
141 permissions and ticket validity checks before calling into L<RT::Record>
142 (usually).
143
144 =cut
145
146 sub AddLink {
147     my $self = shift;
148
149     return (0, $self->loc("Permission Denied"))
150         unless $self->CurrentUserHasRight($self->ModifyLinkRight);
151
152     return $self->_AddLink(@_);
153 }
154
155 =head2 DeleteLink
156
157 Takes a paramhash of Type and one of Base or Target. Removes that link from the
158 record.
159
160 Refer to L<RT::Record/_DeleteLink> for full documentation.  This method
161 implements permission checks before calling into L<RT::Record> (usually).
162
163 =cut
164
165 sub DeleteLink {
166     my $self = shift;
167
168     return (0, $self->loc("Permission Denied"))
169         unless $self->CurrentUserHasRight($self->ModifyLinkRight);
170
171     return $self->_DeleteLink(@_);
172 }
173
174 1;