diff options
author | Shawn M Moore <shawn@bestpractical.com> | 2017-04-13 19:49:27 +0300 |
---|---|---|
committer | sunnavy <sunnavy@bestpractical.com> | 2022-10-19 00:25:59 +0300 |
commit | fa751b05d04d91341e112f40b9fd629aea1b4039 (patch) | |
tree | a1c82d9f222944c13ef0141463ced1356eaeff09 | |
parent | 2fe3c023215ea27710e5b8bcf7fda3a95dee272e (diff) |
Add support for LookupType to custom roles
This allows custom roles to be reused for any object class, not just tickets
and queues.
-rw-r--r-- | etc/schema.Oracle | 1 | ||||
-rw-r--r-- | etc/schema.Pg | 1 | ||||
-rw-r--r-- | etc/schema.SQLite | 1 | ||||
-rw-r--r-- | etc/schema.mysql | 1 | ||||
-rw-r--r-- | etc/upgrade/5.0.4/schema.Oracle | 2 | ||||
-rw-r--r-- | etc/upgrade/5.0.4/schema.Pg | 2 | ||||
-rw-r--r-- | etc/upgrade/5.0.4/schema.SQLite | 2 | ||||
-rw-r--r-- | etc/upgrade/5.0.4/schema.mysql | 2 | ||||
-rw-r--r-- | lib/RT/CustomRole.pm | 200 | ||||
-rw-r--r-- | lib/RT/CustomRoles.pm | 13 | ||||
-rw-r--r-- | lib/RT/ObjectCustomRole.pm | 46 | ||||
-rw-r--r-- | lib/RT/ObjectCustomRoles.pm | 19 | ||||
-rw-r--r-- | lib/RT/Queue.pm | 2 | ||||
-rw-r--r-- | lib/RT/Record/Role/LookupType.pm | 3 | ||||
-rw-r--r-- | lib/RT/Ticket.pm | 44 | ||||
-rw-r--r-- | share/html/Admin/CustomRoles/Modify.html | 11 | ||||
-rw-r--r-- | share/html/Admin/CustomRoles/Objects.html | 18 |
17 files changed, 265 insertions, 103 deletions
diff --git a/etc/schema.Oracle b/etc/schema.Oracle index 324f790d19..7b7ac07475 100644 --- a/etc/schema.Oracle +++ b/etc/schema.Oracle @@ -520,6 +520,7 @@ CREATE TABLE CustomRoles ( Description VARCHAR2(255), MaxValues NUMBER(11,0) DEFAULT 0 NOT NULL, EntryHint VARCHAR2(255), + LookupType VARCHAR2(255), Creator NUMBER(11,0) DEFAULT 0 NOT NULL, Created DATE, LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL, diff --git a/etc/schema.Pg b/etc/schema.Pg index 9f34ec4b0a..0c81859312 100644 --- a/etc/schema.Pg +++ b/etc/schema.Pg @@ -753,6 +753,7 @@ CREATE TABLE CustomRoles ( Description varchar(255) NULL , MaxValues integer NOT NULL DEFAULT 0 , EntryHint varchar(255) NULL , + LookupType varchar(255) NOT NULL , Creator integer NOT NULL DEFAULT 0 , Created TIMESTAMP NULL , diff --git a/etc/schema.SQLite b/etc/schema.SQLite index d2e455f9e5..2811ed2c4c 100644 --- a/etc/schema.SQLite +++ b/etc/schema.SQLite @@ -549,6 +549,7 @@ CREATE TABLE CustomRoles ( Description varchar(255) collate NOCASE NULL , MaxValues integer, EntryHint varchar(255) collate NOCASE NULL , + LookupType varchar(255) collate NOCASE NOT NULL, Creator integer NOT NULL DEFAULT 0 , Created DATETIME NULL , diff --git a/etc/schema.mysql b/etc/schema.mysql index f773ffd472..15868174dc 100644 --- a/etc/schema.mysql +++ b/etc/schema.mysql @@ -538,6 +538,7 @@ CREATE TABLE CustomRoles ( Description varchar(255) NULL , MaxValues integer, EntryHint varchar(255) NULL , + LookupType varchar(255) CHARACTER SET ascii NOT NULL, Creator integer NOT NULL DEFAULT 0 , Created DATETIME NULL , diff --git a/etc/upgrade/5.0.4/schema.Oracle b/etc/upgrade/5.0.4/schema.Oracle new file mode 100644 index 0000000000..300bf8d8b6 --- /dev/null +++ b/etc/upgrade/5.0.4/schema.Oracle @@ -0,0 +1,2 @@ +ALTER TABLE CustomRoles ADD LookupType VARCHAR2(255); +UPDATE CustomRoles SET LookupType='RT::Queue-RT::Ticket'; diff --git a/etc/upgrade/5.0.4/schema.Pg b/etc/upgrade/5.0.4/schema.Pg new file mode 100644 index 0000000000..671d871f45 --- /dev/null +++ b/etc/upgrade/5.0.4/schema.Pg @@ -0,0 +1,2 @@ +ALTER TABLE CustomRoles ADD COLUMN LookupType VARCHAR(255); +UPDATE CustomRoles SET LookupType='RT::Queue-RT::Ticket'; diff --git a/etc/upgrade/5.0.4/schema.SQLite b/etc/upgrade/5.0.4/schema.SQLite new file mode 100644 index 0000000000..ec766a33cd --- /dev/null +++ b/etc/upgrade/5.0.4/schema.SQLite @@ -0,0 +1,2 @@ +ALTER TABLE CustomRoles ADD COLUMN LookupType VARCHAR(255) collate NOCASE; +UPDATE CustomRoles SET LookupType='RT::Queue-RT::Ticket'; diff --git a/etc/upgrade/5.0.4/schema.mysql b/etc/upgrade/5.0.4/schema.mysql new file mode 100644 index 0000000000..850f200953 --- /dev/null +++ b/etc/upgrade/5.0.4/schema.mysql @@ -0,0 +1,2 @@ +ALTER TABLE CustomRoles ADD COLUMN LookupType varchar(255) CHARACTER SET ascii; +UPDATE CustomRoles SET LookupType='RT::Queue-RT::Ticket'; diff --git a/lib/RT/CustomRole.pm b/lib/RT/CustomRole.pm index fa4ec0f747..077e8bc052 100644 --- a/lib/RT/CustomRole.pm +++ b/lib/RT/CustomRole.pm @@ -55,6 +55,9 @@ use base 'RT::Record'; use RT::CustomRoles; use RT::ObjectCustomRole; +use Role::Basic 'with'; +with "RT::Record::Role::LookupType"; + =head1 NAME RT::CustomRole - user-defined role groups @@ -79,6 +82,7 @@ Create takes a hash of values and creates a row in the database: varchar(255) 'Description'. int(11) 'MaxValues'. varchar(255) 'EntryHint'. + varchar(255) 'LookupType'. smallint(6) 'Disabled'. =cut @@ -90,6 +94,7 @@ sub Create { Description => '', MaxValues => 0, EntryHint => '', + LookupType => '', Disabled => 0, @_, ); @@ -106,6 +111,9 @@ sub Create { $args{'Disabled'} ||= 0; $args{'MaxValues'} = int $args{'MaxValues'}; + # backwards compatibility; used to be the only possibility + $args{'LookupType'} ||= 'RT::Queue-RT::Ticket'; + $RT::Handle->BeginTransaction; my ($ok, $msg) = $self->SUPER::Create( @@ -113,6 +121,7 @@ sub Create { Description => $args{'Description'}, MaxValues => $args{'MaxValues'}, EntryHint => $args{'EntryHint'}, + LookupType => $args{'LookupType'}, Disabled => $args{'Disabled'}, ); unless ($ok) { @@ -152,9 +161,9 @@ sub _RegisterAsRole { my $self = shift; my $id = $self->Id; - RT::Ticket->RegisterRole( + $self->ObjectTypeFromLookupType->RegisterRole( Name => $self->GroupType, - EquivClasses => ['RT::Queue'], + EquivClasses => [$self->RecordClassFromLookupType], Single => $self->SingleValue, UserDefined => 1, @@ -171,17 +180,10 @@ sub _RegisterAsRole { my $role = RT::CustomRole->new(RT->SystemUser); $role->Load($id); - if ($object->isa('RT::Queue')) { - # In case queue level custom role groups got deleted - # somehow. Allow to re-create them like default ones. - return $role->IsAdded($object->id); - } - elsif ($object->isa('RT::Ticket')) { - # see if the role has been applied to the ticket's queue - # need to walk around ACLs because of the common case of - # (e.g. Everyone) having the CreateTicket right but not - # ShowTicket - return $role->IsAdded($object->__Value('Queue')); + if ( $role->Id ) { + if (my $predicate = $role->LookupTypeRegistration($role->LookupType, 'CreateGroupPredicate')) { + return $predicate->($object, $role); + } } return 0; @@ -205,16 +207,10 @@ sub _RegisterAsRole { my $role = RT::CustomRole->new(RT->SystemUser); $role->Load($id); - if ( $object->isa('RT::Ticket') || $object->isa('RT::Queue') ) { - return 0 unless $object->CurrentUserHasRight('SeeQueue'); - - # custom roles apply to queues, so canonicalize a ticket - # into its queue - if ( $object->isa('RT::Ticket') ) { - $object = $object->QueueObj; + if ( $role->Id ) { + if (my $predicate = $role->LookupTypeRegistration($role->LookupType, 'AppliesToObjectPredicate')) { + return $predicate->($object, $role); } - - return $role->IsAdded( $object->Id ); } return 0; @@ -235,7 +231,7 @@ sub _RegisterAsRole { sub _UnregisterAsRole { my $self = shift; - RT::Ticket->UnregisterRole($self->GroupType); + $self->ObjectTypeFromLookupType->UnregisterRole($self->GroupType); } =head2 Load ID/NAME @@ -375,7 +371,7 @@ sub NotAddedTo { =head2 AddToObject -Adds (applies) this custom role to the provided queue (ObjectId). +Adds (applies) this custom role to the provided object (ObjectId). Accepts a param hash of: @@ -383,7 +379,7 @@ Accepts a param hash of: =item C<ObjectId> -Queue name or id. +Object id of the class corresponding with L</LookupType>. =item C<SortOrder> @@ -400,26 +396,30 @@ sub AddToObject { my $self = shift; my %args = @_%2? (ObjectId => @_) : (@_); - my $queue = RT::Queue->new( $self->CurrentUser ); - $queue->Load( $args{'ObjectId'} ); - return (0, $self->loc('Invalid queue')) - unless $queue->id; + my $class = $self->RecordClassFromLookupType; + my $object = $class->new( $self->CurrentUser ); + $object->Load( $args{'ObjectId'} ); + unless ($object->id) { + RT->Logger->warn("Unable to load $class '$args{'ObjectId'}' for custom role " . $self->Id); + return (0, $self->loc('Unable to load [_1]', $args{'ObjectId'})) + } - $args{'ObjectId'} = $queue->id; + $args{'ObjectId'} = $object->id; return ( 0, $self->loc('Permission Denied') ) - unless $queue->CurrentUserHasRight('AdminCustomRoles'); + unless $object->CurrentUserHasRight('AdminCustomRoles'); + my $rec = RT::ObjectCustomRole->new( $self->CurrentUser ); my ( $status, $add ) = $rec->Add( %args, CustomRole => $self ); my $msg; - $msg = $self->loc("[_1] added to queue [_2]", $self->Name, $queue->Name) if $status; + $msg = $self->loc("[_1] added to queue [_2]", $self->Name, $object->Name) if $status; return ( $add, $msg ); } =head2 RemoveFromObject -Removes this custom role from the provided queue (ObjectId). +Removes this custom role from the provided object (ObjectId). Accepts a param hash of: @@ -427,7 +427,7 @@ Accepts a param hash of: =item C<ObjectId> -Queue name or id. +Object id of the class corresponding with L</LookupType>. =back @@ -440,19 +440,25 @@ sub RemoveFromObject { my $self = shift; my %args = @_%2? (ObjectId => @_) : (@_); - my $queue = RT::Queue->new( $self->CurrentUser ); - $queue->Load( $args{'ObjectId'} ); - return (0, $self->loc('Invalid queue id')) - unless $queue->id; + my $class = $self->RecordClassFromLookupType; + my $object = $class->new( $self->CurrentUser ); + $object->Load( $args{'ObjectId'} ); + unless ($object->id) { + RT->Logger->warn("Unable to load $class '$args{'ObjectId'}' for custom role " . $self->Id); + return (0, $self->loc('Unable to load [_1]', $args{'ObjectId'})) + } + + $args{'ObjectId'} = $object->id; return ( 0, $self->loc('Permission Denied') ) - unless $queue->CurrentUserHasRight('AdminCustomRoles'); + unless $object->CurrentUserHasRight('AdminCustomRoles'); + my $rec = RT::ObjectCustomRole->new( $self->CurrentUser ); $rec->LoadByCols( CustomRole => $self->id, ObjectId => $args{'ObjectId'} ); return (0, $self->loc('Custom role is not added') ) unless $rec->id; my ( $status, $delete ) = $rec->Delete; my $msg; - $msg = $self->loc("[_1] removed from queue [_2]", $self->Name, $queue->Name) if $status; + $msg = $self->loc("[_1] removed from queue [_2]", $self->Name, $object->Name) if $status; return ( $delete, $msg ); } @@ -561,6 +567,39 @@ sub SetMaxValues { return ($ok, $msg); } +=head2 LookupType + +Returns the current value of LookupType. +(In the database, LookupType is stored as varchar(255).) + +=head2 SetLookupType VALUE + + +Set LookupType to VALUE. +Returns (1, 'Status message') on success and (0, 'Error Message') on failure. +(In the database, LookupType will be stored as a varchar(255).) + +=cut + +sub SetLookupType { + my $self = shift; + my $lookup = shift; + if ( $lookup ne $self->LookupType ) { + # Okay... We need to invalidate our existing relationships + RT::ObjectCustomRole->new($self->CurrentUser)->DeleteAll( CustomRole => $self ); + } + + $self->_UnregisterAsRole; + + my ($ok, $msg) = $self->_Set(Field => 'LookupType', Value => $lookup); + + # update EquivClasses declaration + $self->_RegisterAsRole; + RT->System->CustomRoleCacheNeedsUpdate(1); + + return ($ok, $msg); +} + =head2 EntryHint Returns the current value of EntryHint. @@ -615,62 +654,65 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure. =cut -sub _SetGroupsDisabledForQueue { +sub _SetGroupsDisabledForObject { my $self = shift; my $value = shift; - my $queue = shift; + my $object = shift; - # set disabled on the queue group - my $queue_group = RT::Group->new($self->CurrentUser); - $queue_group->LoadRoleGroup( + # set disabled on the object group + my $object_group = RT::Group->new($self->CurrentUser); + $object_group->LoadRoleGroup( Name => $self->GroupType, - Object => $queue, + Object => $object, ); - if (!$queue_group->Id) { + if (!$object_group->Id) { $RT::Handle->Rollback; - $RT::Logger->error("Couldn't find role group for " . $self->GroupType . " on queue " . $queue->Id); + $RT::Logger->error("Couldn't find role group for " . $self->GroupType . " on " . ref($object) . " #" . $object->Id); return(undef); } - my ($ok, $msg) = $queue_group->SetDisabled($value); + my ($ok, $msg) = $object_group->SetDisabled($value); unless ($ok) { $RT::Handle->Rollback; $RT::Logger->error("Couldn't SetDisabled($value) on role group: $msg"); return(undef); } - # disable each existant ticket group - my $ticket_groups = RT::Groups->new($self->CurrentUser); + my $subgroup_config = $self->LookupTypeRegistration($self->LookupType, 'Subgroup'); + if ($subgroup_config) { + # disable each existant ticket group + my $groups = RT::Groups->new($self->CurrentUser); - if ($value) { - $ticket_groups->LimitToEnabled; - } - else { - $ticket_groups->LimitToDeleted; - } - - $ticket_groups->Limit(FIELD => 'Domain', OPERATOR => 'LIKE', VALUE => "RT::Ticket-Role", CASESENSITIVE => 0 ); - $ticket_groups->Limit(FIELD => 'Name', OPERATOR => '=', VALUE => $self->GroupType, CASESENSITIVE => 0); - - my $tickets = $ticket_groups->Join( - ALIAS1 => 'main', - FIELD1 => 'Instance', - TABLE2 => 'Tickets', - FIELD2 => 'Id', - ); - $ticket_groups->Limit( - ALIAS => $tickets, - FIELD => 'Queue', - VALUE => $queue->Id, - ); + if ($value) { + $groups->LimitToEnabled; + } + else { + $groups->LimitToDeleted; + } - while (my $ticket_group = $ticket_groups->Next) { - my ($ok, $msg) = $ticket_group->SetDisabled($value); - unless ($ok) { - $RT::Handle->Rollback; - $RT::Logger->error("Couldn't SetDisabled($value) ticket role group: $msg"); - return(undef); + $groups->Limit(FIELD => 'Domain', OPERATOR => 'LIKE', VALUE => $subgroup_config->{Domain}, CASESENSITIVE => 0 ); + $groups->Limit(FIELD => 'Name', OPERATOR => '=', VALUE => $self->GroupType, CASESENSITIVE => 0); + + my $objects = $groups->Join( + ALIAS1 => 'main', + FIELD1 => 'Instance', + TABLE2 => $subgroup_config->{Table}, + FIELD2 => 'Id', + ); + $groups->Limit( + ALIAS => $objects, + FIELD => $subgroup_config->{Parent}, + VALUE => $object->Id, + ); + + while (my $group = $groups->Next) { + my ($ok, $msg) = $group->SetDisabled($value); + unless ($ok) { + $RT::Handle->Rollback; + $RT::Logger->error("Couldn't SetDisabled($value) role group: $msg"); + return(undef); + } } } } @@ -753,6 +795,8 @@ sub _CoreAccessible { {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''}, EntryHint => {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, + LookupType => + {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''}, Creator => {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'}, Created => diff --git a/lib/RT/CustomRoles.pm b/lib/RT/CustomRoles.pm index f49a9f9e4d..7fdecf856c 100644 --- a/lib/RT/CustomRoles.pm +++ b/lib/RT/CustomRoles.pm @@ -156,6 +156,19 @@ sub LimitToMultipleValue { ); } +=head2 LimitToLookupType + +Takes LookupType and limits collection. + +=cut + +sub LimitToLookupType { + my $self = shift; + my $lookup = shift; + + $self->Limit( FIELD => 'LookupType', VALUE => "$lookup" ); +} + =head2 ApplySortOrder Sort custom roles according to the order provided by the object custom roles. diff --git a/lib/RT/ObjectCustomRole.pm b/lib/RT/ObjectCustomRole.pm index c66161044f..554004134b 100644 --- a/lib/RT/ObjectCustomRole.pm +++ b/lib/RT/ObjectCustomRole.pm @@ -57,11 +57,11 @@ use RT::ObjectCustomRoles; =head1 NAME -RT::ObjectCustomRole - record representing addition of a custom role to a queue +RT::ObjectCustomRole - record representing addition of a custom role to an object =head1 DESCRIPTION -This record is created if you want to add a custom role to a queue. +This record is created if you want to add a custom role to an object. Inherits methods from L<RT::Record::AddAndSort>. @@ -79,12 +79,16 @@ sub Table {'ObjectCustomRoles'} =head2 ObjectCollectionClass -Returns class name of collection of records custom roles can be added to. -Now it's only L<RT::Queue>, so 'RT::Queues' is returned. +Returns class name of collection of records this custom role can be added to +by consulting the custom role's C<LookupType>. =cut -sub ObjectCollectionClass {'RT::Queues'} +sub ObjectCollectionClass { + my $self = shift; + my %args = (@_); + return $args{'CustomRole'}->CollectionClassFromLookupType; +} =head2 CustomRoleObj @@ -100,22 +104,30 @@ sub CustomRoleObj { return $obj; } -=head2 QueueObj +=head2 Object -Returns the L<RT::Queue> object which this ObjectCustomRole is added to +Returns the object which this ObjectCustomRole is added to =cut +sub Object { + my $self = shift; + my $role = $self->CustomRoleObj; + my $class = $role->RecordClassFromLookupType; + my $object = $class->new($self->CurrentUser); + $object->Load($self->ObjectId); + return $object; +} + sub QueueObj { my $self = shift; - my $queue = RT::Queue->new($self->CurrentUser); - $queue->Load($self->ObjectId); - return $queue; + RT->Deprecated( Instead => "Object", Remove => '5.2' ); + return $self->Object(@_); } =head2 Add -Adds the custom role to the queue and creates (or re-enables) that queue's role +Adds the custom role to the object and creates (or re-enables) that object's role group. =cut @@ -132,15 +144,15 @@ sub Add { return(undef); } - my $queue = $self->QueueObj; + my $object = $self->Object; my $role = $self->CustomRoleObj; # see if we already have this role group (which can happen if you - # add a role to a queue, remove it, then add it back in) + # add a role to an object, remove it, then add it back in) my $existing = RT::Group->new($self->CurrentUser); $existing->LoadRoleGroup( Name => $role->GroupType, - Object => $queue, + Object => $object, ); if ($existing->Id) { @@ -150,7 +162,7 @@ sub Add { my $group = RT::Group->new($self->CurrentUser); my ($ok, $msg) = $group->CreateRoleGroup( Name => $role->GroupType, - Object => $queue, + Object => $object, ); unless ($ok) { @@ -168,7 +180,7 @@ sub Add { =head2 Delete -Removes the custom role from the queue and disables that queue's role group. +Removes the custom role from the object and disables that object's role group. =cut @@ -194,7 +206,7 @@ sub FindDependencies { $self->SUPER::FindDependencies($walker, $deps); $deps->Add( out => $self->CustomRoleObj ); - $deps->Add( out => $self->QueueObj ); + $deps->Add( out => $self->Object ); } sub Serialize { diff --git a/lib/RT/ObjectCustomRoles.pm b/lib/RT/ObjectCustomRoles.pm index 9baabb514b..64352fc94b 100644 --- a/lib/RT/ObjectCustomRoles.pm +++ b/lib/RT/ObjectCustomRoles.pm @@ -106,6 +106,25 @@ sub LimitToObjectId { ); } +sub LimitToLookupType { + my $self = shift; + my $lookup = shift; + + $self->{'_crs_alias'} ||= $self->Join( + ALIAS1 => 'main', + FIELD1 => 'CustomRole', + TABLE2 => 'CustomRoles', + FIELD2 => 'id', + ); + $self->Limit( + ALIAS => $self->{'_crs_alias'}, + FIELD => 'LookupType', + OPERATOR => '=', + VALUE => $lookup, + ); +} + + RT::Base->_ImportOverlays(); 1; diff --git a/lib/RT/Queue.pm b/lib/RT/Queue.pm index 8aba033035..1f3af9c9d0 100644 --- a/lib/RT/Queue.pm +++ b/lib/RT/Queue.pm @@ -481,6 +481,7 @@ sub CustomRoles { my $roles = RT::CustomRoles->new( $self->CurrentUser ); if ( $self->CurrentUserHasRight('SeeQueue') ) { $roles->LimitToObjectId( $self->Id ); + $roles->LimitToLookupType(RT::Ticket->CustomFieldLookupType); $roles->ApplySortOrder; } else { @@ -1086,6 +1087,7 @@ sub FindDependencies { # Object Custom Roles $objs = RT::ObjectCustomRoles->new( $self->CurrentUser ); $objs->LimitToObjectId($self->Id); + $objs->LimitToLookupType(RT::Ticket->CustomFieldLookupType); $deps->Add( in => $objs ); } diff --git a/lib/RT/Record/Role/LookupType.pm b/lib/RT/Record/Role/LookupType.pm index de53291252..4f9fa2ba1a 100644 --- a/lib/RT/Record/Role/LookupType.pm +++ b/lib/RT/Record/Role/LookupType.pm @@ -161,7 +161,8 @@ sub LookupTypeRegistration { my $option = shift or return %{ $REGISTRY{$class}{$path}}; - return $REGISTRY{$class}{$path}{$option}; + my $ret = $REGISTRY{$class}{$path}{$option}; + return $ret; } =head2 FriendlyLookupType diff --git a/lib/RT/Ticket.pm b/lib/RT/Ticket.pm index b609eea085..5592929bb3 100644 --- a/lib/RT/Ticket.pm +++ b/lib/RT/Ticket.pm @@ -114,6 +114,50 @@ for my $role (sort keys %ROLES) { ); } +RT::CustomRole->RegisterLookupType( + CustomFieldLookupType() => { + FriendlyName => 'Tickets', + CreateGroupPredicate => sub { + my ($object, $role) = @_; + if ($object->isa('RT::Queue')) { + # In case queue level custom role groups got deleted + # somehow. Allow to re-create them like default ones. + return $role->IsAdded($object->id); + } + elsif ($object->isa('RT::Ticket')) { + # see if the role has been applied to the ticket's queue + # need to walk around ACLs because of the common case of + # (e.g. Everyone) having the CreateTicket right but not + # ShowTicket + return $role->IsAdded($object->__Value('Queue')); + } + + return 0; + }, + AppliesToObjectPredicate => sub { + my ($object, $role) = @_; + return 0 unless $object->CurrentUserHasRight('SeeQueue'); + + # custom roles apply to queues, so canonicalize a ticket + # into its queue + if ($object->isa('RT::Ticket')) { + $object = $object->QueueObj; + } + + if ($object->isa('RT::Queue')) { + return $role->IsAdded($object->Id); + } + + return 0; + }, + Subgroup => { + Domain => 'RT::Ticket-Role', + Table => 'Tickets', + Parent => 'Queue', + }, + } +); + our %MERGE_CACHE = ( effective => {}, merged => {}, diff --git a/share/html/Admin/CustomRoles/Modify.html b/share/html/Admin/CustomRoles/Modify.html index 115a64588d..f6a73baa3d 100644 --- a/share/html/Admin/CustomRoles/Modify.html +++ b/share/html/Admin/CustomRoles/Modify.html @@ -64,6 +64,14 @@ <input class="form-control" type="text" name="Description" value="<% $Create ? "" : $RoleObj->Description || $Description || '' %>" size="60" /> </&> +<&| /Elements/LabeledValue, Label => loc('Applies To') &> + <& /Admin/Elements/SelectLookupType, + Name => "LookupType", + Object => $RoleObj, + Default => $RoleObj->LookupType || $LookupType, + &> +</&> + <&| /Elements/LabeledValue, Label => loc("Entry Hint") &> <input class="form-control" type="text" name="EntryHint" value="<% $Create ? "" : $RoleObj->EntryHint || $EntryHint || '' %>" size="60" /> </&> @@ -140,7 +148,7 @@ unless ($Create) { if ( $RoleObj->Id ) { $title = loc('Configuration for role [_1]', $RoleObj->Name ); - my @attribs = qw(Description Name EntryHint Disabled); + my @attribs = qw(Description Name EntryHint LookupType Disabled); # we just created the role if (!$id || $id eq 'new') { @@ -198,4 +206,5 @@ $SetEnabled => undef $SetMultiple => undef $Multiple => undef $Enabled => undef +$LookupType => RT::Ticket->CustomFieldLookupType </%ARGS> diff --git a/share/html/Admin/CustomRoles/Objects.html b/share/html/Admin/CustomRoles/Objects.html index c8bc2f7a27..d3e954b6d0 100644 --- a/share/html/Admin/CustomRoles/Objects.html +++ b/share/html/Admin/CustomRoles/Objects.html @@ -56,8 +56,8 @@ <h2><&|/l&>Selected objects</&></h2> <& /Elements/CollectionList, - OrderBy => 'id', - Order => 'ASC', + OrderBy => $class->isa('RT::Queue') ? ['SortOrder', 'Name'] : 'id', + Order => $class->isa('RT::Queue') ? ['ASC', 'ASC'] : 'ASC', %ARGS, Collection => $added, Rows => 0, @@ -74,8 +74,8 @@ <h2><&|/l&>Unselected objects</&></h2> <& /Elements/CollectionList, - OrderBy => 'Name', - Order => 'ASC', + OrderBy => $class->isa('RT::Queue') ? ['SortOrder', 'Name'] : 'id', + Order => $class->isa('RT::Queue') ? ['ASC', 'ASC'] : 'ASC', %ARGS, Collection => $not_added, Rows => $rows, @@ -102,6 +102,8 @@ my $role = RT::CustomRole->new( $session{'CurrentUser'} ); $role->Load($id) or Abort(loc("Could not load custom role #[_1]", $id)); $id = $role->id; +my $class = $role->RecordClassFromLookupType; + if ($role->Disabled) { Abort(loc("Cannot modify objects of disabled custom role #[_1]", $id)); } @@ -132,8 +134,12 @@ if ( $Update ) { my $added = $role->AddedTo; my $not_added = $role->NotAddedTo; -my $format = RT->Config->Get('AdminSearchResultFormat')->{'Queues'}; -my $rows = RT->Config->Get('AdminSearchResultRows')->{'Queues'} || 50; +my $collection_class = ref($added); +$collection_class =~ s/^RT:://; + +my $format = RT->Config->Get('AdminSearchResultFormat')->{$collection_class} + || '__id__,__Name__'; +my $rows = RT->Config->Get('AdminSearchResultRows')->{$collection_class} || 50; my $title = loc('Modify associated objects for [_1]', $role->Name); |