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