diff options
author | Ivan Kohler <ivan@freeside.biz> | 2014-05-27 15:20:05 -0700 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2014-05-30 13:00:41 -0700 |
commit | 0ea23112cfa0d82738b0f08d60d90579721b7524 (patch) | |
tree | 392dee3654d0f3839944f748819a39c8ce20192c /rt/lib/RT | |
parent | 60dd95422a1ad4724e0c5d9dd7f8e8878cd96aa8 (diff) |
rt 4.0.20 (RT#13852)
Diffstat (limited to 'rt/lib/RT')
-rw-r--r-- | rt/lib/RT/Config.pm | 13 | ||||
-rw-r--r-- | rt/lib/RT/Date.pm | 3 | ||||
-rw-r--r-- | rt/lib/RT/Generated.pm | 2 | ||||
-rw-r--r-- | rt/lib/RT/Handle.pm | 41 | ||||
-rw-r--r-- | rt/lib/RT/Interface/REST.pm | 2 | ||||
-rw-r--r-- | rt/lib/RT/Interface/Web.pm | 2 | ||||
-rw-r--r-- | rt/lib/RT/Interface/Web/Handler.pm | 2 | ||||
-rw-r--r-- | rt/lib/RT/Lifecycle.pm | 4 | ||||
-rw-r--r-- | rt/lib/RT/Shredder/Plugin/SQLDump.pm | 4 | ||||
-rw-r--r-- | rt/lib/RT/StyleGuide.pod | 207 | ||||
-rwxr-xr-x | rt/lib/RT/Template.pm | 6 | ||||
-rw-r--r-- | rt/lib/RT/Test.pm | 70 | ||||
-rwxr-xr-x | rt/lib/RT/User.pm | 24 | ||||
-rwxr-xr-x | rt/lib/RT/Users.pm | 22 |
14 files changed, 224 insertions, 178 deletions
diff --git a/rt/lib/RT/Config.pm b/rt/lib/RT/Config.pm index 18f2b7ae3..23441934f 100644 --- a/rt/lib/RT/Config.pm +++ b/rt/lib/RT/Config.pm @@ -1219,11 +1219,14 @@ sub SetFromConfig { my $entry = ${$pack}{$k}; next unless $entry; - # get entry for type we are looking for - # XXX skip references to scalars or other references. - # Otherwie 5.10 goes boom. maybe we should skip any - # reference - next if ref($entry) eq 'SCALAR' || ref($entry) eq 'REF'; + # Inlined constants are simplified in the symbol table -- + # namely, when possible, you only get a reference back in + # $entry, rather than a full GLOB. In 5.10, scalar + # constants began being inlined this way; starting in 5.20, + # list constants are also inlined. Notably, ref(GLOB) is + # undef, but inlined constants are currently either REF, + # SCALAR, or ARRAY. + next if ref($entry); my $ref_type = ref($ref); diff --git a/rt/lib/RT/Date.pm b/rt/lib/RT/Date.pm index db56cfeb9..52bdc01df 100644 --- a/rt/lib/RT/Date.pm +++ b/rt/lib/RT/Date.pm @@ -509,7 +509,8 @@ Returns new unix time. sub AddDays { my $self = shift; - my $days = shift || 1; + my $days = shift; + $days = 1 unless defined $days; return $self->AddSeconds( $days * $DAY ); } diff --git a/rt/lib/RT/Generated.pm b/rt/lib/RT/Generated.pm index 5edd7e3f8..eee892dd9 100644 --- a/rt/lib/RT/Generated.pm +++ b/rt/lib/RT/Generated.pm @@ -50,7 +50,7 @@ package RT; use warnings; use strict; -our $VERSION = '4.0.19'; +our $VERSION = '4.0.20'; diff --git a/rt/lib/RT/Handle.pm b/rt/lib/RT/Handle.pm index 4ea1576dc..e6ecdda77 100644 --- a/rt/lib/RT/Handle.pm +++ b/rt/lib/RT/Handle.pm @@ -246,7 +246,7 @@ sub CheckIntegrity { return (0, 'no nobody user', "Couldn't find Nobody user in the DB '". $self->DSN ."'"); } - return $RT::Handle->dbh; + return 1; } sub CheckCompatibility { @@ -768,9 +768,9 @@ sub InsertData { ); # Slurp in stuff to insert from the datafile. Possible things to go in here:- - our (@Groups, @Users, @ACL, @Queues, @ScripActions, @ScripConditions, + our (@Groups, @Users, @Members, @ACL, @Queues, @ScripActions, @ScripConditions, @Templates, @CustomFields, @Scrips, @Attributes, @Initial, @Final); - local (@Groups, @Users, @ACL, @Queues, @ScripActions, @ScripConditions, + local (@Groups, @Users, @Members, @ACL, @Queues, @ScripActions, @ScripConditions, @Templates, @CustomFields, @Scrips, @Attributes, @Initial, @Final); local $@; @@ -790,7 +790,9 @@ sub InsertData { $RT::Logger->debug("Creating groups..."); foreach my $item (@Groups) { my $new_entry = RT::Group->new( RT->SystemUser ); + $item->{Domain} ||= 'UserDefined'; my $member_of = delete $item->{'MemberOf'}; + my $members = delete $item->{'Members'}; my ( $return, $msg ) = $new_entry->_Create(%$item); unless ( $return ) { $RT::Logger->error( $msg ); @@ -829,6 +831,12 @@ sub InsertData { } } } + push @Members, map { +{Group => $new_entry->id, + Class => "RT::User", Name => $_} } + @{ $members->{Users} || [] }; + push @Members, map { +{Group => $new_entry->id, + Class => "RT::Group", Name => $_} } + @{ $members->{Groups} || [] }; } $RT::Logger->debug("done."); } @@ -848,6 +856,33 @@ sub InsertData { } $RT::Logger->debug("done."); } + if ( @Members ) { + $RT::Logger->debug("Adding users and groups to groups..."); + for my $item (@Members) { + my $group = RT::Group->new(RT->SystemUser); + $group->LoadUserDefinedGroup( delete $item->{Group} ); + unless ($group->Id) { + RT->Logger->error("Unable to find group '$group' to add members to"); + next; + } + + my $class = delete $item->{Class} || 'RT::User'; + my $member = $class->new( RT->SystemUser ); + $item->{Domain} = 'UserDefined' if $member->isa("RT::Group"); + $member->LoadByCols( %$item ); + unless ($member->Id) { + RT->Logger->error("Unable to find $class '".($item->{id} || $item->{Name})."' to add to ".$group->Name); + next; + } + + my ( $return, $msg) = $group->AddMember( $member->PrincipalObj->Id ); + unless ( $return ) { + $RT::Logger->error( $msg ); + } else { + $RT::Logger->debug( $return ."." ); + } + } + } if ( @Queues ) { $RT::Logger->debug("Creating queues..."); for my $item (@Queues) { diff --git a/rt/lib/RT/Interface/REST.pm b/rt/lib/RT/Interface/REST.pm index 17fe44669..06d7f83d2 100644 --- a/rt/lib/RT/Interface/REST.pm +++ b/rt/lib/RT/Interface/REST.pm @@ -328,7 +328,7 @@ sub process_attachments { Path => $tmp_fn, Type => $info->{'Content-Type'} || guess_media_type($tmp_fn), Filename => $file, - Disposition => "attachment", + Disposition => $info->{'Content-Disposition'} || "attachment", ); $new_entity->bodyhandle->{'_dirty_hack_to_save_a_ref_tmp_fh'} = $tmp_fh; $i++; diff --git a/rt/lib/RT/Interface/Web.pm b/rt/lib/RT/Interface/Web.pm index 409cbdc45..59d315431 100644 --- a/rt/lib/RT/Interface/Web.pm +++ b/rt/lib/RT/Interface/Web.pm @@ -962,7 +962,7 @@ not contain a slash-dot C</.>, and does not contain any nulls. sub ComponentPathIsSafe { my $self = shift; my $path = shift; - return $path !~ m{(?:^|/)\.} and $path !~ m{\0}; + return($path !~ m{(?:^|/)\.} and $path !~ m{\0}); } =head2 PathIsSafe diff --git a/rt/lib/RT/Interface/Web/Handler.pm b/rt/lib/RT/Interface/Web/Handler.pm index 37031b18d..07e770724 100644 --- a/rt/lib/RT/Interface/Web/Handler.pm +++ b/rt/lib/RT/Interface/Web/Handler.pm @@ -278,7 +278,7 @@ sub PSGIApp { # CGI.pm normalizes .. out of paths so when you requested # /NoAuth/../Ticket/Display.html we saw Ticket/Display.html # PSGI doesn't normalize .. so we have to deal ourselves. - if ( $req->path_info =~ m{/\.} ) { + if ( $req->path_info =~ m{(^|/)\.\.?(/|$)} ) { $RT::Logger->crit("Invalid request for ".$req->path_info." aborting"); my $res = Plack::Response->new(400); return $self->_psgi_response_cb($res->finalize,sub { $self->CleanupRequest }); diff --git a/rt/lib/RT/Lifecycle.pm b/rt/lib/RT/Lifecycle.pm index accef228f..bdb2ba6d8 100644 --- a/rt/lib/RT/Lifecycle.pm +++ b/rt/lib/RT/Lifecycle.pm @@ -298,7 +298,7 @@ sub IsActive { return 0; } -=head3 inactive +=head3 Inactive Returns an array of all inactive statuses for this lifecycle. @@ -309,7 +309,7 @@ sub Inactive { return $self->Valid('inactive'); } -=head3 is_inactive +=head3 IsInactive Takes a value and returns true if value is a valid inactive status. Otherwise, returns false. diff --git a/rt/lib/RT/Shredder/Plugin/SQLDump.pm b/rt/lib/RT/Shredder/Plugin/SQLDump.pm index cc0d4cc08..d12cf0b5c 100644 --- a/rt/lib/RT/Shredder/Plugin/SQLDump.pm +++ b/rt/lib/RT/Shredder/Plugin/SQLDump.pm @@ -89,8 +89,8 @@ sub Run my $query = $args{'Object'}->_AsInsertQuery; $query .= "\n" unless $query =~ /\n$/; - return print $fh $query or return (0, "Couldn't write to filehandle"); - return 1; + return 1 if print $fh $query; + return (0, "Couldn't write to filehandle"); } 1; diff --git a/rt/lib/RT/StyleGuide.pod b/rt/lib/RT/StyleGuide.pod index d958c87d4..8fdfc7b1e 100644 --- a/rt/lib/RT/StyleGuide.pod +++ b/rt/lib/RT/StyleGuide.pod @@ -2,6 +2,10 @@ RT::StyleGuide - RT Style Guide +=head1 CAVEATS + +This file is somewhat out of date; L<hacking> takes precedence over it. + =head1 INTRODUCTION All code and documentation that is submitted to be included in the RT @@ -92,21 +96,9 @@ versions. Examples: 1.1.0 First development release of RT 1.2 (or 2.0) 2.0.0 First release of RT 2 -Versions can be modified with a hyphen followed by some text, for -special versions, or to give extra information. Examples: - - 2.0.0-pre1 Notes that this is not final, but preview - -In perl 5.6.0, you can have versions like C<v2.0.0>, but this is not -allowed in previous versions of perl. So to convert a tuple version -string to a string to use with $VERSION, use a regular integer for -the revision, and three digits for version and subversion. Examples: +Versions may end in "rc" and a number if they are release candidates: - 1.1.6 -> 1.001006 - 2.0.0 -> 2.000000 - -This way, perl can use the version strings in greater-than and -less-than comparisons. + 2.0.0rc1 First release candiate for real 2.0.0 =head2 Comments @@ -152,14 +144,6 @@ local() may also be used on elements of arrays and hashes, though there is seldom a need to do it, and you shouldn't. -=head2 Exporting - -Do not export anything from a module by default. Feel free to put -anything you want to in @EXPORT_OK, so users of your modules can -explicitly ask for symbols (e.g., "use Something::Something qw(getFoo -setFoo)"), but do not export them by default. - - =head2 Pass by Reference Arrays and hashes should be passed to and from functions by reference @@ -185,58 +169,6 @@ Although, usually, this is better (faster, easier to read, etc.): We need to talk about Class::ReturnValue here. -=head2 Garbage Collection - -Perl does pretty good garbage collection for you. It will automatically -clean up lexical variables that have gone out of scope and objects whose -references have gone away. Normally you don't need to worry about -cleaning up after yourself, if using lexicals. - -However, some glue code, code compiled in C and linked to Perl, might -not automatically clean up for you. In such cases, clean up for -yourself. If there is a method in that glue to dispose or destruct, -then use it as appropriate. - -Also, if you have a long-running function that has a large data -structure in it, it is polite to free up the memory as soon as you are -done with it, if possible. - - my $huge_data_structure = get_huge_data_structure(); - do_something_with($huge_data_structure); - undef $huge_data_structure; - -=head2 DESTROY - -All object classes must provide a DESTROY method. If it won't do -anything, provide it anyway: - - sub DESTROY { } - - - -=head2 die() and exit() - -Don't do it. Do not die() or exit() from a web template or module. Do -not call C<kill 9, $$>. Don't do it. - -In command-line programs, do as you please. - - -=head2 shift and @_ - -Do not use @_. Use shift. shift may take more lines, but Jesse thinks it -leads to cleaner code. - - my $var = shift; # right - my($var) = @_; # ick. no - sub foo { uc $_[0] } # icky. sometimes ok. - - - my($var1, $var2) = (shift, shift); # Um, no. - - my $var1 = shift; # right - my $var2 = shift; - =head2 Method parameters If a method takes exactly one mandatory argument, the argument should be @@ -249,15 +181,17 @@ In all other cases, the method needs to take named parameters, usually using a C<%args> hash to store them: my $self = shift; - my %args = ( Name => undef, - Description => undef, - @_ ); + my %args = ( + Name => undef, + Description => undef, + @_ + ); You may specify defaults to those named parameters instead of using C<undef> above, as long as it is documented as such. It is worth noting that the existing RT codebase had not followed this -style perfectly; we are trying to fix it without breaking exsiting APIs. +style perfectly; we are trying to fix it without breaking existing APIs. =head2 Tests @@ -332,17 +266,6 @@ document, too. =over 4 -=item RT the name - -"RT" is the name of the project. "RT" is, optionally, the -specific name for the actual file distribution. That's it. - -While we sometimes use "RT2" or "RT3", that's shortand that's really -not recommended. The name of the project is "RT". - -To specify a major version, use "RT 3.0". -To specify a specific release, use "RT 3.0.12" - =item function vs. sub(routine) vs. method Just because it is the Perl Way (not necessarily right for all @@ -435,9 +358,9 @@ clear what is going on, or when it is required (such as with map() and grep()). for (@list) { - print; # OK; everyone knows this one - print uc; # wrong; few people know this - print uc $_; # better + print; # OK; everyone knows this one + print uc; # wrong; few people know this + print uc $_; # better } Note that the special variable C<_> I<should> be used when possible. @@ -448,9 +371,9 @@ C<_> for subsequent uses, is a performance hit. You should be careful that the last-tested file is what you think it is, though. if (-d $file) { # $file is a directory - # ... + # ... } elsif (-l _) { # $file is a symlink - # ... + # ... } Package names begin with a capital letter in each word, followed by @@ -461,20 +384,16 @@ lower case letters (for the most part). Multiple words should be StudlyCapped. RT::Display::Provider # good RT::CustomField # not so good, but OK -Plugin modules should begin with "RTx::", followed by the name +Plugin modules should begin with "RT::Extension::", followed by the name of the plugin. =head1 Code formatting -Use perltidy. Anything we say here is wrong if it conflicts with what -perltidy does. Your perltidyrc should read: - --lp -vt=2 -vtc=2 -nsfs -bar +When in doubt, use perltidy; RT includes a F<.perltidyrc>. =head2 Indents and Blank Space -All indents should be tabs. Set your tab stops whatever you want them -to be; I use 8 spaces per tabs. +All indents should be four spaces; hard tabs are forbidden. No space before a semicolon that closes a statement. @@ -507,15 +426,14 @@ An example: # this is my function! sub foo { - my $val = shift; - my $obj = new Constructor; - my($var1, $var2); - - $obj->SetFoo($val); - $var1 = $obj->Foo(); + my $val = shift; + my $obj = new Constructor; + my($var1, $var2); + $obj->SetFoo($val); + $var1 = $obj->Foo(); - return($val); + return($val); } print 1; @@ -555,14 +473,13 @@ the opening statement, or the opening parenthesis, whichever works best. Examples: @list = qw( - bar - baz + bar + baz ); # right if ($foo && $bar && $baz - && $buz && $xyzzy - ) { - print $foo; + && $buz && $xyzzy) { + print $foo; } Whether or not there is space following a closing parenthesis is @@ -620,26 +537,16 @@ opening curly on the first line, and the ending curly lined up with the keyword at the end. for (@list) { - print; - smell(); + print; + smell(); } -Generally, we prefer "uncuddled elses": +Generally, we prefer "cuddled elses": if ($foo) { - print; - } - else { - die; - } - -_If_ the if statement is very brief, sometimes "cuddling" the else makes code more readable. Feel free to cuddle them in that case: - - - if ($foo) { - print; + print; } else { - die; + die; } =head2 Operators @@ -678,21 +585,21 @@ normally, you should, if there is any question at all -- then it doesn't matter which you use. Use whichever is most readable and aesthetically pleasing to you at the time, and be consistent within your block of code. -Break long lines AFTER operators, except for "and", "or", "&&", "||". +Break long lines AFTER operators, except for ".", "and", "or", "&&", "||". Try to keep the two parts to a binary operator (an operator that has two operands) together when possible. - print "foo" . "bar" . "baz" - . "buz"; # wrong - print "foo" . "bar" . "baz" . - "buz"; # right + "buz"; # wrong + + print "foo" . "bar" . "baz" + . "buz"; # right print $foo unless $x == 3 && $y == - 4 && $z == 5; # wrong + 4 && $z == 5; # wrong print $foo unless $x == 3 && $y == 4 - && $z == 5; # right + && $z == 5; # right =head2 Other @@ -722,7 +629,7 @@ When making compound statements, put the primary action first. Use here-docs instead of repeated print statements. - print <<EOT; + print <<EOT; This is a whole bunch of text. I like it. I don't need to worry about messing with lots of print statements and lining them up. @@ -754,7 +661,7 @@ grep the codebase for strings to be localized The string Foo Bar Baz - + Should become <&|/l&>Foo Bar Baz</&> @@ -788,9 +695,8 @@ should become <& /Elements/TitleBoxStart, titleright => loc("RT [_1] for [_2]",$RT::VERSION, RT->Config->Get('rtname')), title => loc('Login'), &> - -=item Library code +=item Library code @@ -855,19 +761,21 @@ guide contained in this document. =item Finish it up After the code is done (possibly going through multiple code reviews), -if you do not have repository access, submit it to rt-<major-version>-bugs@fsck.com as a unified diff. From that point on, it'll be handled by someone with repository access. +if you do not have repository access, submit it to rt-bugs@fsck.com as a +unified diff. From that point on, it'll be handled by someone with +repository access. =back =head1 BUG REPORTS, PATCHES -Use rt-<major-version>-bugs@fsck.com for I<any> bug that is not -being fixed immediately. If it is not in RT, there -is a good chance it will not be dealt with. +Use rt-bugs@bestpractical.com for I<any> bug that is not being fixed +immediately. If it is not in RT, there is a good chance it will not be +dealt with. -Send patches to rt-<major-version>-bugs@fsck.com, too. Use C<diff --u> for patches. +Send patches to rt-bugs@bestpractical.com, too. Use C<diff -u> for +patches. =head1 SCHEMA DESIGN @@ -919,12 +827,3 @@ Talk about mason Talk about adding a new translation Talk more about logging - -=head1 CHANGES - - Adapted from Slash Styleguide by jesse - 20 Dec, 2002 - - -=head1 VERSION - -0.1 diff --git a/rt/lib/RT/Template.pm b/rt/lib/RT/Template.pm index d15c1cdcb..050799714 100755 --- a/rt/lib/RT/Template.pm +++ b/rt/lib/RT/Template.pm @@ -470,6 +470,12 @@ sub _ParseContentPerl { TYPE => 'STRING', SOURCE => $args{Content}, ); + my ($ok) = $template->compile; + unless ($ok) { + $RT::Logger->error("Template parsing error in @{[$self->Name]} (#@{[$self->id]}): $Text::Template::ERROR"); + return ( undef, $self->loc('Template parsing error: [_1]', $Text::Template::ERROR) ); + } + my $is_broken = 0; my $retval = $template->fill_in( HASH => $args{TemplateArgs}, diff --git a/rt/lib/RT/Test.pm b/rt/lib/RT/Test.pm index 2a1f52b90..b15c03d23 100644 --- a/rt/lib/RT/Test.pm +++ b/rt/lib/RT/Test.pm @@ -709,6 +709,39 @@ sub load_or_create_user { return $obj; } + +sub load_or_create_group { + my $self = shift; + my $name = shift; + my %args = (@_); + + my $group = RT::Group->new( RT->SystemUser ); + $group->LoadUserDefinedGroup( $name ); + unless ( $group->id ) { + my ($id, $msg) = $group->CreateUserDefinedGroup( + Name => $name, + ); + die "$msg" unless $id; + } + + if ( $args{Members} ) { + my $cur = $group->MembersObj; + while ( my $entry = $cur->Next ) { + my ($status, $msg) = $entry->Delete; + die "$msg" unless $status; + } + + foreach my $new ( @{ $args{Members} } ) { + my ($status, $msg) = $group->AddMember( + ref($new)? $new->id : $new, + ); + die "$msg" unless $status; + } + } + + return $group; +} + =head2 load_or_create_queue =cut @@ -997,6 +1030,43 @@ sub run_mailgate { $self->run_and_capture(%args); } +sub run_validator { + my $self = shift; + my %args = (check => 1, resolve => 0, force => 1, timeout => 0, @_ ); + + my $validator_path = "$RT::SbinPath/rt-validator"; + + my $cmd = $validator_path; + die "Couldn't find $cmd command" unless -f $cmd; + + my $timeout = delete $args{timeout}; + + while( my ($k,$v) = each %args ) { + next unless $v; + $cmd .= " --$k '$v'"; + } + $cmd .= ' 2>&1'; + + require IPC::Open2; + my ($child_out, $child_in); + my $pid = IPC::Open2::open2($child_out, $child_in, $cmd); + close $child_in; + + local $SIG{ALRM} = sub { kill KILL => $pid; die "Timeout!" }; + + alarm $timeout if $timeout; + my $result = eval { local $/; <$child_out> }; + warn $@ if $@; + close $child_out; + waitpid $pid, 0; + alarm 0; + + DBIx::SearchBuilder::Record::Cachable->FlushCache + if $args{'resolve'}; + + return ($?, $result); +} + sub run_and_capture { my $self = shift; my %args = @_; diff --git a/rt/lib/RT/User.pm b/rt/lib/RT/User.pm index 018ac8a62..af4a6ad99 100755 --- a/rt/lib/RT/User.pm +++ b/rt/lib/RT/User.pm @@ -957,7 +957,7 @@ sub IsPassword { my $hash = MIME::Base64::decode_base64($stored); # Decoding yields 30 byes; first 4 are the salt, the rest are substr(SHA256,0,26) my $salt = substr($hash, 0, 4, ""); - return 0 unless substr(Digest::SHA::sha256($salt . Digest::MD5::md5($value)), 0, 26) eq $hash; + return 0 unless substr(Digest::SHA::sha256($salt . Digest::MD5::md5(encode_utf8($value))), 0, 26) eq $hash; } elsif (length $stored == 32) { # Hex nonsalted-md5 return 0 unless Digest::MD5::md5_hex(encode_utf8($value)) eq $stored; @@ -1390,6 +1390,28 @@ sub SetPreferences { } } +=head2 DeletePreferences NAME/OBJ VALUE + +Delete user preferences associated with given object or name. + +=cut + +sub DeletePreferences { + my $self = shift; + my $name = _PrefName( shift ); + + return (0, $self->loc("No permission to set preferences")) + unless $self->CurrentUserCanModify('Preferences'); + + my $attr = RT::Attribute->new( $self->CurrentUser ); + $attr->LoadByNameAndObject( Object => $self, Name => $name ); + if ( $attr->Id ) { + return $attr->Delete; + } + + return (0, $self->loc("Preferences were not found")); +} + =head2 Stylesheet Returns a list of valid stylesheets take from preferences. diff --git a/rt/lib/RT/Users.pm b/rt/lib/RT/Users.pm index 1c75f4250..f377d470c 100755 --- a/rt/lib/RT/Users.pm +++ b/rt/lib/RT/Users.pm @@ -543,21 +543,31 @@ sub WhoHaveGroupRight } -=head2 WhoBelongToGroups { Groups => ARRAYREF, IncludeSubgroupMembers => 1 } +=head2 WhoBelongToGroups { Groups => ARRAYREF, IncludeSubgroupMembers => 1, IncludeUnprivileged => 0 } + +Return members who belong to any of the groups passed in the groups whose IDs +are included in the Groups arrayref. + +If IncludeSubgroupMembers is true (default) then members of any group that's a +member of one of the passed groups are returned. If it's cleared then only +direct member users are returned. + +If IncludeUnprivileged is false (default) then only privileged members are +returned; otherwise either privileged or unprivileged group members may be +returned. =cut -# XXX: should be generalized sub WhoBelongToGroups { my $self = shift; my %args = ( Groups => undef, IncludeSubgroupMembers => 1, + IncludeUnprivileged => 0, @_ ); - # Unprivileged users can't be granted real system rights. - # is this really the right thing to be saying? - $self->LimitToPrivileged(); - + if (!$args{'IncludeUnprivileged'}) { + $self->LimitToPrivileged(); + } my $group_members = $self->_JoinGroupMembers( %args ); foreach my $groupid (@{$args{'Groups'}}) { |