Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/bestpractical/rt.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn M Moore <shawn@bestpractical.com>2017-04-13 19:49:27 +0300
committersunnavy <sunnavy@bestpractical.com>2022-10-19 00:25:59 +0300
commitfa751b05d04d91341e112f40b9fd629aea1b4039 (patch)
treea1c82d9f222944c13ef0141463ced1356eaeff09
parent2fe3c023215ea27710e5b8bcf7fda3a95dee272e (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.Oracle1
-rw-r--r--etc/schema.Pg1
-rw-r--r--etc/schema.SQLite1
-rw-r--r--etc/schema.mysql1
-rw-r--r--etc/upgrade/5.0.4/schema.Oracle2
-rw-r--r--etc/upgrade/5.0.4/schema.Pg2
-rw-r--r--etc/upgrade/5.0.4/schema.SQLite2
-rw-r--r--etc/upgrade/5.0.4/schema.mysql2
-rw-r--r--lib/RT/CustomRole.pm200
-rw-r--r--lib/RT/CustomRoles.pm13
-rw-r--r--lib/RT/ObjectCustomRole.pm46
-rw-r--r--lib/RT/ObjectCustomRoles.pm19
-rw-r--r--lib/RT/Queue.pm2
-rw-r--r--lib/RT/Record/Role/LookupType.pm3
-rw-r--r--lib/RT/Ticket.pm44
-rw-r--r--share/html/Admin/CustomRoles/Modify.html11
-rw-r--r--share/html/Admin/CustomRoles/Objects.html18
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);