first pass RT4 merge, RT#13852
[freeside.git] / rt / lib / RT / Topic.pm
diff --git a/rt/lib/RT/Topic.pm b/rt/lib/RT/Topic.pm
new file mode 100644 (file)
index 0000000..3499a4d
--- /dev/null
@@ -0,0 +1,376 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+#                                          <sales@bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+
+use warnings;
+use strict;
+
+package RT::Topic;
+use base 'RT::Record';
+
+sub Table {'Topics'}
+
+# {{{ Create
+
+=head2 Create PARAMHASH
+
+Create takes a hash of values and creates a row in the database:
+
+  int(11) 'Parent'.
+  varchar(255) 'Name'.
+  varchar(255) 'Description'.
+  varchar(64) 'ObjectType'.
+  int(11) 'ObjectId'.
+
+=cut
+
+sub Create {
+    my $self = shift;
+    my %args = (
+                Parent => '',
+                Name => '',
+                Description => '',
+                ObjectType => '',
+                ObjectId => '0',
+                @_);
+
+    my $obj = $RT::System;
+    if ($args{ObjectId}) {
+        $obj = $args{ObjectType}->new($self->CurrentUser);
+        $obj->Load($args{ObjectId});
+        $obj = $RT::System unless $obj->id;
+    }
+
+    return ( 0, $self->loc("Permission denied"))
+      unless ( $self->CurrentUser->HasRight(
+                                            Right        => "AdminTopics",
+                                            Object       => $obj,
+                                            EquivObjects => [ $RT::System, $obj ],
+                                           ) );
+
+    $self->SUPER::Create(@_);
+}
+
+# }}}
+
+
+# {{{ Delete
+
+=head2 Delete
+
+Deletes this topic, reparenting all sub-topics to this one's parent.
+
+=cut
+
+sub Delete {
+    my $self = shift;
+    
+    unless ( $self->CurrentUserHasRight('AdminTopics') ) {
+        return ( 0, $self->loc("Permission Denied") );
+    }
+
+    my $kids = RT::Topics->new($self->CurrentUser);
+    $kids->LimitToKids($self->Id);
+    while (my $topic = $kids->Next) {
+        $topic->setParent($self->Parent);
+    }
+
+    $self->SUPER::Delete(@_);
+    return (0, "Topic deleted");
+}
+
+# }}}
+
+
+# {{{ DeleteAll
+
+=head2 DeleteAll
+
+Deletes this topic, and all of its descendants.
+
+=cut
+
+sub DeleteAll {
+    my $self = shift;
+    
+    unless ( $self->CurrentUserHasRight('AdminTopics') ) {
+        return ( 0, $self->loc("Permission Denied") );
+    }
+
+    $self->SUPER::Delete(@_);
+    my $kids = RT::Topics->new($self->CurrentUser);
+    $kids->LimitToKids($self->Id);
+    while (my $topic = $kids->Next) {
+        $topic->DeleteAll;
+    }
+
+    return (0, "Topic tree deleted");
+}
+
+# }}}
+
+
+# {{{ ParentObj
+
+=head2 ParentObj
+
+Returns the parent Topic of this one.
+
+=cut
+
+sub ParentObj {
+  my $self = shift;
+  my $id = $self->Parent;
+  my $obj = RT::Topic->new($self->CurrentUser);
+  $obj->Load($id);
+  return $obj;
+}
+
+# }}}
+
+# {{{ Children
+
+=head2 Children
+
+Returns a Topics object containing this topic's children,
+sorted by Topic.Name.
+
+=cut
+
+sub Children {
+    my $self = shift;
+    unless ($self->{'Children'}) {
+        $self->{'Children'} = RT::Topics->new($self->CurrentUser);
+        $self->{'Children'}->Limit('FIELD' => 'Parent',
+                                   'VALUE' => $self->Id);
+        $self->{'Children'}->OrderBy('FIELD' => 'Name');
+    }
+    return $self->{'Children'};
+}
+
+# {{{ _Set
+
+=head2 _Set
+
+Intercept attempts to modify the Topic so we can apply ACLs
+
+=cut
+
+sub _Set {
+    my $self = shift;
+    
+    unless ( $self->CurrentUserHasRight('AdminTopics') ) {
+        return ( 0, $self->loc("Permission Denied") );
+    }
+    $self->SUPER::_Set(@_);
+}
+
+# }}}
+
+
+# {{{ CurrentUserHasRight
+
+=head2 CurrentUserHasRight
+
+Returns true if the current user has the right for this topic, for the
+whole system or for whatever object this topic is associated with
+
+=cut
+
+sub CurrentUserHasRight {
+    my $self  = shift;
+    my $right = shift;
+
+    my $equiv = [ $RT::System ];
+    if ($self->ObjectId) {
+        my $obj = $self->ObjectType->new($self->CurrentUser);
+        $obj->Load($self->ObjectId);
+        push @{$equiv}, $obj;
+    }
+    if ($self->Id) {
+        return ( $self->CurrentUser->HasRight(
+                                              Right        => $right,
+                                              Object       => $self,
+                                              EquivObjects => $equiv,
+                                             ) );
+    } else {
+        # If we don't have an ID, we don't even know what object we're
+        # attached to -- so the only thing we can fall back on is the
+        # system object.
+        return ( $self->CurrentUser->HasRight(
+                                              Right        => $right,
+                                              Object       => $RT::System,
+                                             ) );
+    }
+    
+
+}
+
+# }}}
+
+
+=head2 id
+
+Returns the current value of id. 
+(In the database, id is stored as int(11).)
+
+
+=cut
+
+
+=head2 Parent
+
+Returns the current value of Parent. 
+(In the database, Parent is stored as int(11).)
+
+
+
+=head2 SetParent VALUE
+
+
+Set Parent to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Parent will be stored as a int(11).)
+
+
+=cut
+
+
+=head2 Name
+
+Returns the current value of Name. 
+(In the database, Name is stored as varchar(255).)
+
+
+
+=head2 SetName VALUE
+
+
+Set Name to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Name will be stored as a varchar(255).)
+
+
+=cut
+
+
+=head2 Description
+
+Returns the current value of Description. 
+(In the database, Description is stored as varchar(255).)
+
+
+
+=head2 SetDescription VALUE
+
+
+Set Description to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Description will be stored as a varchar(255).)
+
+
+=cut
+
+
+=head2 ObjectType
+
+Returns the current value of ObjectType. 
+(In the database, ObjectType is stored as varchar(64).)
+
+
+
+=head2 SetObjectType VALUE
+
+
+Set ObjectType to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, ObjectType will be stored as a varchar(64).)
+
+
+=cut
+
+
+=head2 ObjectId
+
+Returns the current value of ObjectId. 
+(In the database, ObjectId is stored as int(11).)
+
+
+
+=head2 SetObjectId VALUE
+
+
+Set ObjectId to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, ObjectId will be stored as a int(11).)
+
+
+=cut
+
+
+
+sub _CoreAccessible {
+    {
+     
+        id =>
+               {read => 1, type => 'int(11)', default => ''},
+        Parent => 
+               {read => 1, write => 1, type => 'int(11)', default => ''},
+        Name => 
+               {read => 1, write => 1, type => 'varchar(255)', default => ''},
+        Description => 
+               {read => 1, write => 1, type => 'varchar(255)', default => ''},
+        ObjectType => 
+               {read => 1, write => 1, type => 'varchar(64)', default => ''},
+        ObjectId => 
+               {read => 1, write => 1, type => 'int(11)', default => '0'},
+
+ }
+};
+
+RT::Base->_ImportOverlays();
+1;