summaryrefslogtreecommitdiff
path: root/rt/lib/RT
diff options
context:
space:
mode:
Diffstat (limited to 'rt/lib/RT')
-rw-r--r--rt/lib/RT/Config.pm13
-rw-r--r--rt/lib/RT/Date.pm3
-rw-r--r--rt/lib/RT/Generated.pm2
-rw-r--r--rt/lib/RT/Handle.pm41
-rw-r--r--rt/lib/RT/Interface/REST.pm2
-rw-r--r--rt/lib/RT/Interface/Web.pm2
-rw-r--r--rt/lib/RT/Interface/Web/Handler.pm2
-rw-r--r--rt/lib/RT/Lifecycle.pm4
-rw-r--r--rt/lib/RT/Shredder/Plugin/SQLDump.pm4
-rw-r--r--rt/lib/RT/StyleGuide.pod207
-rwxr-xr-xrt/lib/RT/Template.pm6
-rw-r--r--rt/lib/RT/Test.pm70
-rwxr-xr-xrt/lib/RT/User.pm24
-rwxr-xr-xrt/lib/RT/Users.pm22
14 files changed, 224 insertions, 178 deletions
diff --git a/rt/lib/RT/Config.pm b/rt/lib/RT/Config.pm
index fee6c5106..62aae1c35 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'}}) {