[Rt-commit] rt branch, 4.2/role-introspection, created. rt-4.1.5-246-geb0900f

Thomas Sibley trs at bestpractical.com
Thu Jan 10 18:49:56 EST 2013


The branch, 4.2/role-introspection has been created
        at  eb0900f425e3e19fe4bdf3be84e42db0222b9f97 (commit)

- Log -----------------------------------------------------------------
commit 1d35326592cd39d9aa27dd6861d4c1662563a87f
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Jan 10 12:27:34 2013 -0800

    Document the Single and Column attributes of roles

diff --git a/lib/RT/Role/Record/Roles.pm b/lib/RT/Role/Record/Roles.pm
index 903a226..1a1b01a 100644
--- a/lib/RT/Role/Record/Roles.pm
+++ b/lib/RT/Role/Record/Roles.pm
@@ -96,6 +96,20 @@ You should not include L<RT::System> itself in this list.
 
 Simply calls RegisterRole on each equivalent class.
 
+=item Single
+
+Optional.  A true value indicates that this role may only contain a single user
+as a member at any given time.  When adding a new member to a Single role, any
+existing member will be removed.  If all members are removed, L<RT/Nobody> is
+added automatically.
+
+=item Column
+
+Optional, implies Single.  Specifies a column on the announcing class into
+which the single role member's user ID is denormalized.  The column will be
+kept updated automatically as the role member changes.  This is used, for
+example, for ticket owners and makes searching simpler (among other benefits).
+
 =back
 
 =cut

commit 38174c2baa12a811c2ba63cf94c8465a3ff5aa39
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Jan 10 13:37:30 2013 -0800

    Store the original role attributes as a shallow copy
    
    This was the original intention since it leaves EquivClasses for the
    announcing class but strips it from the role attributes in the
    equivalent classes themselves.
    
    The array ref value of EquivClasses is still modified by RegisterRole to
    add RT::System, but that's OK since it is simply an implicit equivalent
    class.  It should be introspectable later rather than hidden.

diff --git a/lib/RT/Role/Record/Roles.pm b/lib/RT/Role/Record/Roles.pm
index 1a1b01a..8768e5c 100644
--- a/lib/RT/Role/Record/Roles.pm
+++ b/lib/RT/Role/Record/Roles.pm
@@ -131,7 +131,7 @@ sub RegisterRole {
     $role{ Single } = 1 if $role{Column};
 
     # Stash the role on ourself
-    $class->_ROLES->{ $role{Name} } = \%role;
+    $class->_ROLES->{ $role{Name} } = { %role };
 
     # Register it with any equivalent classes...
     my $equiv = delete $role{EquivClasses} || [];

commit c77b78a25c80ecfe6a72e886917240674d222aac
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Jan 10 12:44:57 2013 -0800

    Provide a method to access role attributes rather than using _ROLES directly
    
    This is a bit cleaner, documented, and doesn't let the caller change any
    attributes using the returned reference.  The next step would be to
    start using objects to represent role metadata, but that feels much
    heavier an abstraction than is needed.  A hashref is fine for a
    read-only handful of flags.

diff --git a/lib/RT/Group.pm b/lib/RT/Group.pm
index 91c92f3..aed7bf9 100644
--- a/lib/RT/Group.pm
+++ b/lib/RT/Group.pm
@@ -743,15 +743,17 @@ sub SingleMemberRoleGroup {
     my $self = shift;
     my $class = $self->RoleClass;
     return unless $class;
-    return $class->_ROLES->{$self->Type}{Single};
+    return $class->Role($self->Type)->{Single};
 }
 
 sub SingleMemberRoleGroupColumn {
     my $self = shift;
     my ($class) = $self->Domain =~ /^(.+)-Role$/;
     return unless $class;
-    return unless $class->_ROLES->{$self->Type}{Class} eq $class;
-    return $class->_ROLES->{$self->Type}{Column};
+
+    my $role = $class->Role($self->Type);
+    return unless $role->{Class} eq $class;
+    return $role->{Column};
 }
 
 sub RoleGroupObject {
diff --git a/lib/RT/Role/Record/Roles.pm b/lib/RT/Role/Record/Roles.pm
index 8768e5c..e25dd1f 100644
--- a/lib/RT/Role/Record/Roles.pm
+++ b/lib/RT/Role/Record/Roles.pm
@@ -148,6 +148,29 @@ sub RegisterRole {
     return 1;
 }
 
+=head2 Role
+
+Takes a role name; returns a hashref describing the role.  This hashref
+contains the same attributes used to register the role (see L</RegisterRole>),
+as well as some extras, including:
+
+=over
+
+=item Class
+
+The original class which announced the role.  This is set automatically by
+L</RegisterRole> and is the same across all EquivClasses.
+
+=back
+
+Returns an empty hashref if the role doesn't exist.
+
+=cut
+
+sub Role {
+    return \%{ $_[0]->_ROLES->{$_[1]} || {} };
+}
+
 =head2 Roles
 
 Returns a list of role names registered for this class.

commit 71b5186341e7b1e79e3affa942f142c711a19d7f
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Jan 10 15:17:32 2013 -0800

    Optionally filter returned role names by the presence or lack of role flags
    
    These flags are accessible via the ->Role() method as well, but this
    filtering mechanism avoids an additional map and grep on the caller
    side.

diff --git a/lib/RT/Role/Record/Roles.pm b/lib/RT/Role/Record/Roles.pm
index e25dd1f..f7506a0 100644
--- a/lib/RT/Role/Record/Roles.pm
+++ b/lib/RT/Role/Record/Roles.pm
@@ -175,9 +175,32 @@ sub Role {
 
 Returns a list of role names registered for this class.
 
+Optionally takes a hash specifying attributes the returned roles must possess
+or lack.  Testing is done on a simple truthy basis and the actual values of
+the role attributes and arguments you pass are not compared string-wise or
+numerically; they must simply evaluate to the same truthiness.
+
+For example:
+
+    # Return role names which are denormalized into a column; note that the
+    # role's Column attribute contains a string.
+    $object->Roles( Column => 1 );
+
 =cut
 
-sub Roles { sort { $a cmp $b } keys %{ shift->_ROLES } }
+sub Roles {
+    my $self = shift;
+    my %attr = @_;
+
+    return grep {
+        my $ok = 1;
+        my $role = $self->Role($_);
+        for my $k (keys %attr) {
+            $ok = 0, last if $attr{$k} xor $role->{$k};
+        }
+        $ok;
+    } sort { $a cmp $b } keys %{ $self->_ROLES };
+}
 
 {
     my %ROLES;

commit eb0900f425e3e19fe4bdf3be84e42db0222b9f97
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Jan 10 15:21:35 2013 -0800

    Introduce the ACLOnly and ACLOnlyInEquiv flags to role metadata
    
    These are advisory flags indicating when a role is only used for
    granting rights and generally shouldn't contain any members.  For
    example, the Owner and Requestor ticket roles should not contain members
    at the queue or system level.  These flags are useful in the UI when
    generating a list of selectable roles to display for objects.

diff --git a/lib/RT/Queue.pm b/lib/RT/Queue.pm
index 20bf27d..207b614 100644
--- a/lib/RT/Queue.pm
+++ b/lib/RT/Queue.pm
@@ -651,9 +651,7 @@ them, see L</Roles>.
 =cut
 
 sub ManageableRoleGroupTypes {
-    # This grep is a little hacky, but I don't want to introduce the concept of
-    # manageable vs. unmanageable roles globally (yet).
-    return grep { not /^(Requestor|Owner)$/ } shift->Roles;
+    shift->Roles( ACLOnly => 0 )
 }
 
 =head2 IsManageableRoleGroupType
@@ -665,12 +663,7 @@ Returns whether the passed-in type is a manageable role group type.
 sub IsManageableRoleGroupType {
     my $self = shift;
     my $type = shift;
-
-    for my $valid_type ($self->ManageableRoleGroupTypes) {
-        return 1 if $type eq $valid_type;
-    }
-
-    return 0;
+    return not $self->Role($type)->{ACLOnly};
 }
 
 
diff --git a/lib/RT/Role/Record/Roles.pm b/lib/RT/Role/Record/Roles.pm
index f7506a0..21efbca 100644
--- a/lib/RT/Role/Record/Roles.pm
+++ b/lib/RT/Role/Record/Roles.pm
@@ -110,6 +110,19 @@ which the single role member's user ID is denormalized.  The column will be
 kept updated automatically as the role member changes.  This is used, for
 example, for ticket owners and makes searching simpler (among other benefits).
 
+=item ACLOnly
+
+Optional.  A true value indicates this role is only used for ACLs and should
+not be populated with members.
+
+This flag is advisory only, and the Perl API still allows members to be added
+to ACLOnly roles.
+
+=item ACLOnlyInEquiv
+
+Optional.  Automatically sets the ACLOnly flag for all EquivClasses, but not
+the announcing class.
+
 =back
 
 =cut
@@ -141,6 +154,9 @@ sub RegisterRole {
         push @$equiv, "RT::System";
     }
 
+    # ... marked as "for ACLs only" if flagged as such by the announcing class
+    $role{ACLOnly} = 1 if delete $role{ACLOnlyInEquiv};
+
     $_->RegisterRole(%role) for @$equiv;
 
     # XXX TODO: Register which classes have roles on them somewhere?
@@ -182,6 +198,9 @@ numerically; they must simply evaluate to the same truthiness.
 
 For example:
 
+    # Return role names which are not only for ACL purposes
+    $object->Roles( ACLOnly => 0 );
+
     # Return role names which are denormalized into a column; note that the
     # role's Column attribute contains a string.
     $object->Roles( Column => 1 );
diff --git a/lib/RT/Ticket.pm b/lib/RT/Ticket.pm
index 4c3f44c..6a0b690 100644
--- a/lib/RT/Ticket.pm
+++ b/lib/RT/Ticket.pm
@@ -106,7 +106,8 @@ for my $role (sort keys %ROLES) {
     RT::Ticket->RegisterRole(
         Name            => $role,
         EquivClasses    => ['RT::Queue'],
-        ( $role eq "Owner" ? ( Column => "Owner") : () ),
+        ( $role eq "Owner" ? ( Column => "Owner")   : () ),
+        ( $role !~ /Cc/    ? ( ACLOnlyInEquiv => 1) : () ),
     );
 }
 

-----------------------------------------------------------------------


More information about the Rt-commit mailing list