X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=rt%2Flib%2FRT%2FSystem.pm;h=af7a22bbb22244b38fd03cc338d7402736dcad9a;hp=ec0ae9854d853a5cd9a4dc193d35d7ce163ae1d8;hb=ecd038f7ae5c1ffc929f3c928ecd161eeb45d9be;hpb=ef20b2b6b1feb47ad02b5ff7525f1a0fd11d0fa4 diff --git a/rt/lib/RT/System.pm b/rt/lib/RT/System.pm index ec0ae9854..af7a22bbb 100644 --- a/rt/lib/RT/System.pm +++ b/rt/lib/RT/System.pm @@ -1,40 +1,40 @@ # BEGIN BPS TAGGED BLOCK {{{ -# +# # COPYRIGHT: -# -# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC -# -# +# +# This software is Copyright (c) 1996-2016 Best Practical Solutions, LLC +# +# # (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/copyleft/gpl.html. -# -# +# 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 @@ -43,8 +43,9 @@ # 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 }}} + =head1 NAME RT::System @@ -65,73 +66,90 @@ In the future, there will probably be other API goodness encapsulated here. package RT::System; -use base qw /RT::Record/; + use strict; +use warnings; -use RT::ACL; -use vars qw/ $RIGHTS/; - -# System rights are rights granted to the whole system -# XXX TODO Can't localize these outside of having an object around. -$RIGHTS = { - SuperUser => 'Do anything and everything', # loc_pair - AdminAllPersonalGroups => - "Create, delete and modify the members of any user's personal groups" - , # loc_pair - AdminOwnPersonalGroups => - 'Create, delete and modify the members of personal groups', # loc_pair - AdminUsers => 'Create, delete and modify users', # loc_pair - ModifySelf => "Modify one's own RT account", # loc_pair - DelegateRights => - "Delegate specific rights which have been granted to you.", # loc_pair - ShowConfigTab => "show Configuration tab", # loc_pair - LoadSavedSearch => "allow loading of saved searches", # loc_pair - CreateSavedSearch => "allow creation of saved searches", # loc_pair -}; - -# Tell RT::ACE that this sort of object can get acls granted -$RT::ACE::OBJECT_TYPES{'RT::System'} = 1; - -foreach my $right ( keys %{$RIGHTS} ) { - $RT::ACE::LOWERCASERIGHTNAMES{ lc $right } = $right; -} +use base qw/RT::Record/; + +use Role::Basic 'with'; +with "RT::Record::Role::Roles", + "RT::Record::Role::Rights" => { -excludes => [qw/AvailableRights RightCategories/] }; +use RT::ACL; +use RT::ACE; +use Data::GUID; + +__PACKAGE__->AddRight( Admin => SuperUser => 'Do anything and everything'); # loc +__PACKAGE__->AddRight( Staff => ShowUserHistory => 'Show history of public user properties'); # loc +__PACKAGE__->AddRight( Admin => AdminUsers => 'Create, modify and delete users'); # loc +__PACKAGE__->AddRight( Staff => ModifySelf => "Modify one's own RT account"); # loc +__PACKAGE__->AddRight( Staff => ShowArticlesMenu => 'Show Articles menu'); # loc +__PACKAGE__->AddRight( Admin => ShowConfigTab => 'Show Admin menu'); # loc +__PACKAGE__->AddRight( Admin => ShowApprovalsTab => 'Show Approvals tab'); # loc +__PACKAGE__->AddRight( Staff => ShowGlobalTemplates => 'Show global templates'); # loc +__PACKAGE__->AddRight( General => LoadSavedSearch => 'Allow loading of saved searches'); # loc +__PACKAGE__->AddRight( General => CreateSavedSearch => 'Allow creation of saved searches'); # loc +__PACKAGE__->AddRight( Admin => ExecuteCode => 'Allow writing Perl code in templates, scrips, etc'); # loc + +#freeside +__PACKAGE__->AddRight( Staff => BulkUpdateTickets => 'Bulk update tickets'); =head2 AvailableRights -Returns a hash of available rights for this object. The keys are the right names and the values are a description of what the rights do +Returns a hashref of available rights for this object. The keys are the +right names and the values are a description of what the rights do. -=begin testing +This method as well returns rights of other RT objects, like +L or L, to allow users to apply those rights +globally. -my $s = RT::System->new($RT::SystemUser); -my $rights = $s->AvailableRights; -ok ($rights, "Rights defined"); -ok ($rights->{'AdminUsers'},"AdminUsers right found"); -ok ($rights->{'CreateTicket'},"CreateTicket right found"); -ok ($rights->{'AdminGroupMembership'},"ModifyGroupMembers right found"); -ok (!$rights->{'CasdasdsreateTicket'},"bogus right not found"); +If an L is passed as the first argument, the available +rights will be limited to ones which make sense for the principal. +Currently only role groups are supported and rights announced by object +types to which the role group doesn't apply are not returned. +=cut +sub AvailableRights { + my $self = shift; + my $principal = shift; + my $class = ref($self) || $self; + + my @rights; + if ($principal and $principal->IsRoleGroup) { + my $role = $principal->Object->Name; + for my $class (keys %RT::ACE::RIGHTS) { + next unless $class->DOES('RT::Record::Role::Roles') and $class->HasRole($role) and $class ne "RT::System"; + push @rights, values %{ $RT::ACE::RIGHTS{$class} }; + } + } else { + @rights = map {values %{$_}} values %RT::ACE::RIGHTS; + } + + my %rights; + $rights{$_->{Name}} = $_->{Description} for @rights; + + delete $rights{ExecuteCode} if RT->Config->Get('DisallowExecuteCode'); + + return \%rights; +} -=end testing +=head2 RightCategories +Returns a hashref where the keys are rights for this type of object and the +values are the category (General, Staff, Admin) the right falls into. =cut -sub AvailableRights { +sub RightCategories { my $self = shift; + my $class = ref($self) || $self; - my $queue = RT::Queue->new($RT::SystemUser); - my $group = RT::Group->new($RT::SystemUser); - my $cf = RT::CustomField->new($RT::SystemUser); - - my $qr =$queue->AvailableRights(); - my $gr = $group->AvailableRights(); - my $cr = $cf->AvailableRights(); - - # Build a merged list of all system wide rights, queue rights and group rights. - my %rights = (%{$RIGHTS}, %{$gr}, %{$qr}, %{$cr}); - return(\%rights); + my %rights; + $rights{$_->{Name}} = $_->{Category} + for map {values %{$_}} values %RT::ACE::RIGHTS; + return \%rights; } sub _Init { @@ -143,48 +161,179 @@ sub _Init { Returns RT::System's id. It's 1. +=cut -=begin testing +*Id = \&id; +sub id { return 1 } -use RT::System; -my $sys = RT::System->new(); -is( $sys->Id, 1); -is ($sys->id, 1); +sub UID { return "RT::System" } -=end testing +=head2 Load +Since this object is pretending to be an RT::Record, we need a load method. +It does nothing =cut -*Id = \&id; +sub Load { return 1 } +sub Name { return 'RT System' } +sub __Set { return 0 } +sub __Value { return 0 } +sub Create { return 0 } +sub Delete { return 0 } + +sub SubjectTag { + my $self = shift; + my $queue = shift; -sub id { - return (1); + use Carp; + confess "SubjectTag called on $self with $queue" if $queue; + + return $queue->SubjectTag if $queue; + + my $queues = RT::Queues->new( $self->CurrentUser ); + $queues->Limit( FIELD => 'SubjectTag', OPERATOR => 'IS NOT', VALUE => 'NULL' ); + return $queues->DistinctFieldValues('SubjectTag'); } -=head2 Load +=head2 QueueCacheNeedsUpdate ( 1 ) -Since this object is pretending to be an RT::Record, we need a load method. -It does nothing +Attribute to decide when SelectQueue needs to flush the list of queues +and retrieve new ones. Set when queues are created, enabled/disabled +and on certain acl changes. Should also better understand group management. + +If passed a true value, will update the attribute to be the current time. + +=cut + +sub QueueCacheNeedsUpdate { + my $self = shift; + my $update = shift; + + if ($update) { + return $self->SetAttribute(Name => 'QueueCacheNeedsUpdate', Content => time); + } else { + my $cache = $self->FirstAttribute('QueueCacheNeedsUpdate'); + return (defined $cache ? $cache->Content : 0 ); + } +} + +=head2 AddUpgradeHistory package, data + +Adds an entry to the upgrade history database. The package can be either C +for core RT upgrades, or the fully qualified name of a plugin. The data must be +a hash reference. + +=cut + +sub AddUpgradeHistory { + my $self = shift; + my $package = shift; + my $data = shift; + + $data->{timestamp} ||= time; + $data->{rt_version} ||= $RT::VERSION; + + my $upgrade_history_attr = $self->FirstAttribute('UpgradeHistory'); + my $upgrade_history = $upgrade_history_attr ? $upgrade_history_attr->Content : {}; + + push @{ $upgrade_history->{$package} }, $data; + + $self->SetAttribute( + Name => 'UpgradeHistory', + Content => $upgrade_history, + ); +} + +=head2 UpgradeHistory [package] + +Returns the entries of RT's upgrade history. If a package is specified, the list +of upgrades for that package will be returned. Otherwise a hash reference of +C<< package => [upgrades] >> will be returned. =cut -sub Load { - return (1); +sub UpgradeHistory { + my $self = shift; + my $package = shift; + + my $upgrade_history_attr = $self->FirstAttribute('UpgradeHistory'); + my $upgrade_history = $upgrade_history_attr ? $upgrade_history_attr->Content : {}; + + if ($package) { + return @{ $upgrade_history->{$package} || [] }; + } + + return $upgrade_history; } -sub Name { - return 'RT System'; +sub ParsedUpgradeHistory { + my $self = shift; + my $package = shift; + + my $version_status = "Current version: "; + if ( $package eq 'RT' ){ + $version_status .= $RT::VERSION; + } elsif ( grep {/$package/} @{RT->Config->Get('Plugins')} ) { + no strict 'refs'; + $version_status .= ${ $package . '::VERSION' }; + } else { + $version_status = "Not currently loaded"; + } + + my %ids; + my @lines; + + my @events = $self->UpgradeHistory( $package ); + for my $event (@events) { + if ($event->{stage} eq 'before' or (($event->{action}||'') eq 'insert' and not $event->{full_id})) { + if (not $event->{full_id}) { + # For upgrade done in the 4.1 series without GUIDs + if (($event->{type}||'') eq 'full upgrade') { + $event->{full_id} = $event->{individual_id} = Data::GUID->new->as_string; + } else { + $event->{individual_id} = Data::GUID->new->as_string; + $event->{full_id} = (@lines ? $lines[-1]{full_id} : Data::GUID->new->as_string); + } + $event->{return_value} = [1] if $event->{stage} eq 'after'; + } + if ($ids{$event->{full_id}}) { + my $kids = $ids{$event->{full_id}}{sub_events} ||= []; + # Stitch non-"upgrade"s beneath the previous "upgrade" + if ( @{$kids} and $event->{action} ne 'upgrade' and $kids->[-1]{action} eq 'upgrade') { + push @{ $kids->[-1]{sub_events} }, $event; + } else { + push @{ $kids }, $event; + } + } else { + push @lines, $event; + } + $ids{$event->{individual_id}} = $event; + } elsif ($event->{stage} eq 'after') { + if (not $event->{individual_id}) { + if (($event->{type}||'') eq 'full upgrade') { + $lines[-1]{end} = $event->{timestamp} if @lines; + } elsif (($event->{type}||'') eq 'individual upgrade') { + $lines[-1]{sub_events}[-1]{end} = $event->{timestamp} + if @lines and @{ $lines[-1]{sub_events} }; + } + } elsif ($ids{$event->{individual_id}}) { + my $end = $event; + $event = $ids{$event->{individual_id}}; + $event->{end} = $end->{timestamp}; + + $end->{return_value} = [ split ', ', $end->{return_value}, 2 ] + if $end->{return_value} and not ref $end->{return_value}; + $event->{return_value} = $end->{return_value}; + $event->{content} ||= $end->{content}; + } + } + } + + return ($version_status, @lines); } -sub __Set { 0 } -sub __Value { 0 } -sub Create { 0 } -sub Delete { 0 } -eval "require RT::System_Vendor"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/System_Vendor.pm}); -eval "require RT::System_Local"; -die $@ if ($@ && $@ !~ qr{^Can't locate RT/System_Local.pm}); +RT::Base->_ImportOverlays(); 1;