1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
5# This software is Copyright (c) 1996-2021 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
49use warnings;
50use strict;
51
52package RT::Topic;
53use base 'RT::Record';
54
55sub Table {'Topics'}
56
57# {{{ Create
58
59=head2 Create PARAMHASH
60
61Create takes a hash of values and creates a row in the database:
62
63  int(11) 'Parent'.
64  varchar(255) 'Name'.
65  varchar(255) 'Description'.
66  varchar(64) 'ObjectType'.
67  int(11) 'ObjectId'.
68
69=cut
70
71sub Create {
72    my $self = shift;
73    my %args = (
74                Parent => '',
75                Name => '',
76                Description => '',
77                ObjectType => '',
78                ObjectId => '0',
79                @_);
80
81    my $obj = $RT::System;
82    if ($args{ObjectId}) {
83        $obj = $args{ObjectType}->new($self->CurrentUser);
84        $obj->Load($args{ObjectId});
85        $obj = $RT::System unless $obj->id;
86    }
87
88    return ( 0, $self->loc("Permission Denied"))
89      unless ( $self->CurrentUser->HasRight(
90                                            Right        => "AdminTopics",
91                                            Object       => $obj,
92                                            EquivObjects => [ $RT::System, $obj ],
93                                           ) );
94
95    $self->SUPER::Create(@_);
96}
97
98# }}}
99
100
101# {{{ Delete
102
103=head2 Delete
104
105Deletes this topic, reparenting all sub-topics to this one's parent.
106
107=cut
108
109sub Delete {
110    my $self = shift;
111
112    unless ( $self->CurrentUserHasRight('AdminTopics') ) {
113        return ( 0, $self->loc("Permission Denied") );
114    }
115
116    my $kids = RT::Topics->new($self->CurrentUser);
117    $kids->LimitToKids($self->Id);
118    while (my $topic = $kids->Next) {
119        $topic->setParent($self->Parent);
120    }
121
122    $self->SUPER::Delete(@_);
123    return (0, "Topic deleted");
124}
125
126# }}}
127
128
129# {{{ DeleteAll
130
131=head2 DeleteAll
132
133Deletes this topic, and all of its descendants.
134
135=cut
136
137sub DeleteAll {
138    my $self = shift;
139
140    unless ( $self->CurrentUserHasRight('AdminTopics') ) {
141        return ( 0, $self->loc("Permission Denied") );
142    }
143
144    $self->SUPER::Delete(@_);
145    my $kids = RT::Topics->new($self->CurrentUser);
146    $kids->LimitToKids($self->Id);
147    while (my $topic = $kids->Next) {
148        $topic->DeleteAll;
149    }
150
151    return (0, "Topic tree deleted");
152}
153
154# }}}
155
156
157# {{{ ParentObj
158
159=head2 ParentObj
160
161Returns the parent Topic of this one.
162
163=cut
164
165sub ParentObj {
166  my $self = shift;
167  my $id = $self->Parent;
168  my $obj = RT::Topic->new($self->CurrentUser);
169  $obj->Load($id);
170  return $obj;
171}
172
173# }}}
174
175# {{{ Children
176
177=head2 Children
178
179Returns a Topics object containing this topic's children,
180sorted by Topic.Name.
181
182=cut
183
184sub Children {
185    my $self = shift;
186    unless ($self->{'Children'}) {
187        $self->{'Children'} = RT::Topics->new($self->CurrentUser);
188        $self->{'Children'}->Limit('FIELD' => 'Parent',
189                                   'VALUE' => $self->Id);
190        $self->{'Children'}->OrderBy('FIELD' => 'Name');
191    }
192    return $self->{'Children'};
193}
194
195# {{{ _Set
196
197=head2 _Set
198
199Intercept attempts to modify the Topic so we can apply ACLs
200
201=cut
202
203sub _Set {
204    my $self = shift;
205
206    unless ( $self->CurrentUserHasRight('AdminTopics') ) {
207        return ( 0, $self->loc("Permission Denied") );
208    }
209    $self->SUPER::_Set(@_);
210}
211
212# }}}
213
214
215=head2 ACLEquivalenceObjects
216
217Rights on the topic are inherited from the object it is a topic on.
218
219=cut
220
221sub ACLEquivalenceObjects {
222    my $self  = shift;
223    return unless $self->id and $self->ObjectId;
224
225    return $self->Object;
226}
227
228
229sub Object {
230    my $self  = shift;
231    my $Object = $self->__Value('ObjectType')->new( $self->CurrentUser );
232    $Object->Load( $self->__Value('ObjectId') );
233    return $Object;
234}
235
236=head2 id
237
238Returns the current value of id.
239(In the database, id is stored as int(11).)
240
241
242=cut
243
244
245=head2 Parent
246
247Returns the current value of Parent.
248(In the database, Parent is stored as int(11).)
249
250
251
252=head2 SetParent VALUE
253
254
255Set Parent to VALUE.
256Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
257(In the database, Parent will be stored as a int(11).)
258
259
260=cut
261
262
263=head2 Name
264
265Returns the current value of Name.
266(In the database, Name is stored as varchar(255).)
267
268
269
270=head2 SetName VALUE
271
272
273Set Name to VALUE.
274Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
275(In the database, Name will be stored as a varchar(255).)
276
277
278=cut
279
280
281=head2 Description
282
283Returns the current value of Description.
284(In the database, Description is stored as varchar(255).)
285
286
287
288=head2 SetDescription VALUE
289
290
291Set Description to VALUE.
292Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
293(In the database, Description will be stored as a varchar(255).)
294
295
296=cut
297
298
299=head2 ObjectType
300
301Returns the current value of ObjectType.
302(In the database, ObjectType is stored as varchar(64).)
303
304
305
306=head2 SetObjectType VALUE
307
308
309Set ObjectType to VALUE.
310Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
311(In the database, ObjectType will be stored as a varchar(64).)
312
313
314=cut
315
316
317=head2 ObjectId
318
319Returns the current value of ObjectId.
320(In the database, ObjectId is stored as int(11).)
321
322
323
324=head2 SetObjectId VALUE
325
326
327Set ObjectId to VALUE.
328Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
329(In the database, ObjectId will be stored as a int(11).)
330
331
332=cut
333
334
335
336sub _CoreAccessible {
337    {
338
339        id =>
340                {read => 1, type => 'int(11)', default => ''},
341        Parent =>
342                {read => 1, write => 1, type => 'int(11)', default => ''},
343        Name =>
344                {read => 1, write => 1, type => 'varchar(255)', default => ''},
345        Description =>
346                {read => 1, write => 1, type => 'varchar(255)', default => ''},
347        ObjectType =>
348                {read => 1, write => 1, type => 'varchar(64)', default => ''},
349        ObjectId =>
350                {read => 1, write => 1, type => 'int(11)', default => '0'},
351
352 }
353};
354
355sub FindDependencies {
356    my $self = shift;
357    my ($walker, $deps) = @_;
358
359    $self->SUPER::FindDependencies($walker, $deps);
360    $deps->Add( out => $self->ParentObj ) if $self->ParentObj->Id;
361    $deps->Add( in  => $self->Children );
362    $deps->Add( out => $self->Object );
363}
364
365RT::Base->_ImportOverlays();
3661;
367