summaryrefslogtreecommitdiff
path: root/rt/lib
diff options
context:
space:
mode:
authorIvan Kohler <ivan@freeside.biz>2013-06-04 00:16:28 -0700
committerIvan Kohler <ivan@freeside.biz>2013-06-04 00:16:28 -0700
commit7588a4ac90a9b07c08a3107cd1107d773be1c991 (patch)
tree55b8bedb5f899e705da0ba7f608267943bf89e94 /rt/lib
parent98d2b25256055abb0dfcb9f586b434474fa97afd (diff)
RT 4.0.13
Diffstat (limited to 'rt/lib')
-rw-r--r--rt/lib/RT.pm63
-rwxr-xr-xrt/lib/RT/ACE.pm5
-rwxr-xr-xrt/lib/RT/ACL.pm2
-rwxr-xr-xrt/lib/RT/Action.pm2
-rw-r--r--rt/lib/RT/Action/AutoOpen.pm2
-rwxr-xr-xrt/lib/RT/Action/Autoreply.pm4
-rw-r--r--rt/lib/RT/Action/CreateTickets.pm173
-rw-r--r--rt/lib/RT/Action/EscalatePriority.pm3
-rw-r--r--rt/lib/RT/Action/ExtractSubjectTag.pm41
-rwxr-xr-xrt/lib/RT/Action/LinearEscalate.pm2
-rwxr-xr-xrt/lib/RT/Action/Notify.pm2
-rwxr-xr-xrt/lib/RT/Action/NotifyAsComment.pm2
-rw-r--r--rt/lib/RT/Action/NotifyGroup.pm2
-rw-r--r--rt/lib/RT/Action/NotifyGroupAsComment.pm2
-rw-r--r--rt/lib/RT/Action/RecordComment.pm3
-rw-r--r--rt/lib/RT/Action/RecordCorrespondence.pm5
-rwxr-xr-xrt/lib/RT/Action/SendEmail.pm2
-rw-r--r--rt/lib/RT/Action/SetPriority.pm3
-rw-r--r--rt/lib/RT/Action/SetStatus.pm2
-rw-r--r--rt/lib/RT/Action/UserDefined.pm3
-rw-r--r--rt/lib/RT/Approval.pm2
-rw-r--r--rt/lib/RT/Approval/Rule.pm2
-rw-r--r--rt/lib/RT/Approval/Rule/Created.pm2
-rw-r--r--rt/lib/RT/Approval/Rule/NewPending.pm2
-rw-r--r--rt/lib/RT/Approval/Rule/Passed.pm2
-rw-r--r--rt/lib/RT/Approval/Rule/Rejected.pm2
-rw-r--r--rt/lib/RT/Article.pm16
-rw-r--r--rt/lib/RT/Articles.pm2
-rwxr-xr-xrt/lib/RT/Attachment.pm8
-rwxr-xr-xrt/lib/RT/Attachments.pm2
-rw-r--r--rt/lib/RT/Attribute.pm2
-rw-r--r--rt/lib/RT/Attributes.pm2
-rw-r--r--rt/lib/RT/Base.pm2
-rw-r--r--rt/lib/RT/CachedGroupMember.pm2
-rw-r--r--rt/lib/RT/CachedGroupMembers.pm2
-rw-r--r--rt/lib/RT/Class.pm6
-rw-r--r--rt/lib/RT/Classes.pm2
-rwxr-xr-xrt/lib/RT/Condition.pm2
-rw-r--r--rt/lib/RT/Condition/AnyTransaction.pm3
-rw-r--r--rt/lib/RT/Condition/BeforeDue.pm3
-rw-r--r--rt/lib/RT/Condition/CloseTicket.pm2
-rw-r--r--rt/lib/RT/Condition/Overdue.pm3
-rw-r--r--rt/lib/RT/Condition/OwnerChange.pm3
-rw-r--r--rt/lib/RT/Condition/PriorityChange.pm3
-rw-r--r--rt/lib/RT/Condition/PriorityExceeds.pm3
-rw-r--r--rt/lib/RT/Condition/QueueChange.pm3
-rw-r--r--rt/lib/RT/Condition/ReopenTicket.pm2
-rw-r--r--rt/lib/RT/Condition/StatusChange.pm3
-rw-r--r--rt/lib/RT/Condition/UserDefined.pm3
-rw-r--r--rt/lib/RT/Config.pm30
-rw-r--r--rt/lib/RT/Crypt/GnuPG.pm22
-rwxr-xr-xrt/lib/RT/CurrentUser.pm11
-rw-r--r--rt/lib/RT/CustomField.pm17
-rw-r--r--rt/lib/RT/CustomFieldValue.pm2
-rw-r--r--rt/lib/RT/CustomFieldValues.pm2
-rw-r--r--rt/lib/RT/CustomFieldValues/External.pm4
-rw-r--r--rt/lib/RT/CustomFieldValues/Groups.pm2
-rw-r--r--rt/lib/RT/CustomFields.pm2
-rw-r--r--rt/lib/RT/Dashboard.pm4
-rw-r--r--rt/lib/RT/Dashboard/Mailer.pm45
-rw-r--r--rt/lib/RT/Dashboards.pm3
-rw-r--r--rt/lib/RT/Date.pm2
-rw-r--r--rt/lib/RT/EmailParser.pm112
-rw-r--r--rt/lib/RT/Generated.pm4
-rw-r--r--rt/lib/RT/Generated.pm.in2
-rw-r--r--rt/lib/RT/Graph/Tickets.pm2
-rwxr-xr-xrt/lib/RT/Group.pm9
-rwxr-xr-xrt/lib/RT/GroupMember.pm2
-rwxr-xr-xrt/lib/RT/GroupMembers.pm2
-rwxr-xr-xrt/lib/RT/Groups.pm6
-rw-r--r--rt/lib/RT/Handle.pm37
-rw-r--r--rt/lib/RT/I18N.pm58
-rw-r--r--rt/lib/RT/I18N/cs.pm2
-rw-r--r--rt/lib/RT/I18N/i_default.pm2
-rwxr-xr-xrt/lib/RT/I18N/ru.pm2
-rw-r--r--rt/lib/RT/Installer.pm9
-rw-r--r--rt/lib/RT/Interface/CLI.pm5
-rwxr-xr-xrt/lib/RT/Interface/Email.pm45
-rwxr-xr-xrt/lib/RT/Interface/Email/Auth/GnuPG.pm2
-rw-r--r--rt/lib/RT/Interface/Email/Auth/MailFrom.pm9
-rw-r--r--rt/lib/RT/Interface/REST.pm5
-rw-r--r--rt/lib/RT/Interface/Web.pm236
-rw-r--r--rt/lib/RT/Interface/Web/Handler.pm44
-rw-r--r--rt/lib/RT/Interface/Web/Menu.pm57
-rwxr-xr-xrt/lib/RT/Interface/Web/QueryBuilder.pm2
-rwxr-xr-xrt/lib/RT/Interface/Web/QueryBuilder/Tree.pm2
-rw-r--r--rt/lib/RT/Interface/Web/Request.pm23
-rw-r--r--rt/lib/RT/Interface/Web/Session.pm10
-rw-r--r--rt/lib/RT/Lifecycle.pm142
-rw-r--r--rt/lib/RT/Link.pm45
-rw-r--r--rt/lib/RT/Links.pm2
-rw-r--r--rt/lib/RT/ObjectClass.pm2
-rw-r--r--rt/lib/RT/ObjectClasses.pm2
-rw-r--r--rt/lib/RT/ObjectCustomField.pm2
-rw-r--r--rt/lib/RT/ObjectCustomFieldValue.pm2
-rw-r--r--rt/lib/RT/ObjectCustomFieldValues.pm6
-rw-r--r--rt/lib/RT/ObjectCustomFields.pm2
-rw-r--r--rt/lib/RT/ObjectTopic.pm15
-rw-r--r--rt/lib/RT/ObjectTopics.pm2
-rw-r--r--rt/lib/RT/Plugin.pm2
-rw-r--r--rt/lib/RT/Pod/HTML.pm104
-rw-r--r--rt/lib/RT/Pod/HTMLBatch.pm48
-rw-r--r--rt/lib/RT/Pod/Search.pm48
-rw-r--r--rt/lib/RT/Principal.pm2
-rw-r--r--rt/lib/RT/Principals.pm2
-rwxr-xr-xrt/lib/RT/Queue.pm40
-rwxr-xr-xrt/lib/RT/Queues.pm2
-rwxr-xr-xrt/lib/RT/Record.pm65
-rw-r--r--rt/lib/RT/Reminders.pm12
-rw-r--r--rt/lib/RT/Report/Tickets.pm39
-rw-r--r--rt/lib/RT/Report/Tickets/Entry.pm2
-rw-r--r--rt/lib/RT/Rule.pm2
-rw-r--r--rt/lib/RT/Ruleset.pm2
-rw-r--r--rt/lib/RT/SQL.pm4
-rw-r--r--rt/lib/RT/SavedSearch.pm26
-rw-r--r--rt/lib/RT/SavedSearches.pm3
-rwxr-xr-xrt/lib/RT/Scrip.pm10
-rwxr-xr-xrt/lib/RT/ScripAction.pm2
-rwxr-xr-xrt/lib/RT/ScripActions.pm2
-rwxr-xr-xrt/lib/RT/ScripCondition.pm6
-rwxr-xr-xrt/lib/RT/ScripConditions.pm2
-rwxr-xr-xrt/lib/RT/Scrips.pm2
-rwxr-xr-xrt/lib/RT/Search.pm2
-rw-r--r--rt/lib/RT/Search/ActiveTicketsInQueue.pm3
-rw-r--r--rt/lib/RT/Search/FromSQL.pm3
-rw-r--r--rt/lib/RT/Search/Googleish.pm4
-rw-r--r--rt/lib/RT/SearchBuilder.pm4
-rw-r--r--rt/lib/RT/SharedSetting.pm6
-rw-r--r--rt/lib/RT/SharedSettings.pm3
-rw-r--r--rt/lib/RT/Shredder.pm4
-rw-r--r--rt/lib/RT/Shredder/ACE.pm2
-rw-r--r--rt/lib/RT/Shredder/Attachment.pm2
-rw-r--r--rt/lib/RT/Shredder/CachedGroupMember.pm2
-rw-r--r--rt/lib/RT/Shredder/Constants.pm2
-rw-r--r--rt/lib/RT/Shredder/CustomField.pm2
-rw-r--r--rt/lib/RT/Shredder/CustomFieldValue.pm2
-rw-r--r--rt/lib/RT/Shredder/Dependencies.pm3
-rw-r--r--rt/lib/RT/Shredder/Dependency.pm3
-rw-r--r--rt/lib/RT/Shredder/Exceptions.pm2
-rw-r--r--rt/lib/RT/Shredder/Group.pm2
-rw-r--r--rt/lib/RT/Shredder/GroupMember.pm2
-rw-r--r--rt/lib/RT/Shredder/Link.pm2
-rw-r--r--rt/lib/RT/Shredder/ObjectCustomFieldValue.pm2
-rw-r--r--rt/lib/RT/Shredder/POD.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/Attachments.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/Base.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/Base/Dump.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/Base/Search.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/Objects.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/SQLDump.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/Summary.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/Tickets.pm2
-rw-r--r--rt/lib/RT/Shredder/Plugin/Users.pm2
-rw-r--r--rt/lib/RT/Shredder/Principal.pm2
-rw-r--r--rt/lib/RT/Shredder/Queue.pm2
-rw-r--r--rt/lib/RT/Shredder/Record.pm2
-rw-r--r--rt/lib/RT/Shredder/Scrip.pm2
-rw-r--r--rt/lib/RT/Shredder/ScripAction.pm2
-rw-r--r--rt/lib/RT/Shredder/ScripCondition.pm2
-rw-r--r--rt/lib/RT/Shredder/Template.pm2
-rw-r--r--rt/lib/RT/Shredder/Ticket.pm2
-rw-r--r--rt/lib/RT/Shredder/Transaction.pm2
-rw-r--r--rt/lib/RT/Shredder/User.pm2
-rw-r--r--rt/lib/RT/Squish.pm2
-rw-r--r--rt/lib/RT/Squish/CSS.pm2
-rw-r--r--rt/lib/RT/Squish/JS.pm2
-rw-r--r--rt/lib/RT/System.pm2
-rwxr-xr-xrt/lib/RT/Template.pm6
-rwxr-xr-xrt/lib/RT/Templates.pm2
-rw-r--r--rt/lib/RT/Test.pm110
-rw-r--r--rt/lib/RT/Test/Apache.pm2
-rw-r--r--rt/lib/RT/Test/Email.pm2
-rw-r--r--rt/lib/RT/Test/GnuPG.pm7
-rw-r--r--rt/lib/RT/Test/Web.pm2
-rwxr-xr-xrt/lib/RT/Ticket.pm119
-rwxr-xr-xrt/lib/RT/Tickets.pm93
-rw-r--r--rt/lib/RT/Tickets_SQL.pm11
-rw-r--r--rt/lib/RT/Topic.pm2
-rw-r--r--rt/lib/RT/Topics.pm3
-rwxr-xr-xrt/lib/RT/Transaction.pm75
-rwxr-xr-xrt/lib/RT/Transactions.pm2
-rw-r--r--rt/lib/RT/URI.pm2
-rw-r--r--rt/lib/RT/URI/a.pm2
-rw-r--r--rt/lib/RT/URI/base.pm3
-rw-r--r--rt/lib/RT/URI/fsck_com_article.pm2
-rw-r--r--rt/lib/RT/URI/fsck_com_rt.pm2
-rw-r--r--rt/lib/RT/URI/t.pm2
-rwxr-xr-xrt/lib/RT/User.pm63
-rwxr-xr-xrt/lib/RT/Users.pm4
-rw-r--r--rt/lib/RT/Util.pm2
191 files changed, 1754 insertions, 769 deletions
diff --git a/rt/lib/RT.pm b/rt/lib/RT.pm
index 4372a564d..da60ef77d 100644
--- a/rt/lib/RT.pm
+++ b/rt/lib/RT.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -83,12 +83,56 @@ RT - Request Tracker
=head1 SYNOPSIS
-A fully featured request tracker package
+A fully featured request tracker package.
+
+This documentation describes the point-of-entry for RT's Perl API. To learn
+more about what RT is and what it can do for you, visit
+L<https://bestpractical.com/rt>.
=head1 DESCRIPTION
=head2 INITIALIZATION
+If you're using RT's Perl libraries, you need to initialize RT before using any
+of the modules.
+
+You have the option of handling the timing of config loading and the actual
+init sequence yourself with:
+
+ use RT;
+ BEGIN {
+ RT->LoadConfig;
+ RT->Init;
+ }
+
+or you can let RT do it all:
+
+ use RT -init;
+
+This second method is particular useful when writing one-liners to interact with RT:
+
+ perl -MRT=-init -e '...'
+
+The first method is necessary if you need to delay or conditionalize
+initialization or if you want to fiddle with C<< RT->Config >> between loading
+the config files and initializing the RT environment.
+
+=cut
+
+{
+ my $DID_IMPORT_INIT;
+ sub import {
+ my $class = shift;
+ my $action = shift || '';
+
+ if ($action eq "-init" and not $DID_IMPORT_INIT) {
+ $class->LoadConfig;
+ $class->Init;
+ $DID_IMPORT_INIT = 1;
+ }
+ }
+}
+
=head2 LoadConfig
Load RT's config file. First, the site configuration file
@@ -316,6 +360,16 @@ sub InitLogging {
InitSignalHandlers(%arg);
}
+{ # Work around bug in Log::Dispatch < 2.30, wherein the short forms
+ # of ->warn, ->err, and ->crit do not usefully propagate out, unlike
+ # ->warning, ->error, and ->critical
+ package Log::Dispatch;
+ no warnings 'redefine';
+ sub warn { shift->warning(@_) }
+ sub err { shift->error(@_) }
+ sub crit { shift->critical(@_) }
+}
+
sub InitSignalHandlers {
my %arg = @_;
@@ -336,6 +390,11 @@ sub InitSignalHandlers {
unshift @_, $RT::Logger, qw(level warning message);
goto &Log::Dispatch::log;
}
+ # Return value is used only by RT::Test to filter warnings from
+ # reaching the Test::NoWarnings catcher. If Log::Dispatch::log() ever
+ # starts returning 'IGNORE', we'll need to switch to something more
+ # clever. I don't expect that to happen.
+ return 'IGNORE';
};
#When we call die, trap it and log->crit with the value of the die.
diff --git a/rt/lib/RT/ACE.pm b/rt/lib/RT/ACE.pm
index ae3eda42b..c752aa2dc 100755
--- a/rt/lib/RT/ACE.pm
+++ b/rt/lib/RT/ACE.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -285,7 +285,8 @@ sub Create {
ObjectId => $args{'ObjectId'},
);
if ( $self->Id ) {
- return ( 0, $self->loc('That principal already has that right') );
+ return ( 0, $self->loc('[_1] already has that right',
+ $princ_obj->Object->Name) );
}
my $id = $self->SUPER::Create( PrincipalId => $princ_obj->id,
diff --git a/rt/lib/RT/ACL.pm b/rt/lib/RT/ACL.pm
index 49a7f1d64..d1e0df5ad 100755
--- a/rt/lib/RT/ACL.pm
+++ b/rt/lib/RT/ACL.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action.pm b/rt/lib/RT/Action.pm
index 23ff82dec..dc10d0da6 100755
--- a/rt/lib/RT/Action.pm
+++ b/rt/lib/RT/Action.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/AutoOpen.pm b/rt/lib/RT/Action/AutoOpen.pm
index 5f96e0649..8566c62d5 100644
--- a/rt/lib/RT/Action/AutoOpen.pm
+++ b/rt/lib/RT/Action/AutoOpen.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/Autoreply.pm b/rt/lib/RT/Action/Autoreply.pm
index cde874e45..89b7536fa 100755
--- a/rt/lib/RT/Action/Autoreply.pm
+++ b/rt/lib/RT/Action/Autoreply.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -87,7 +87,7 @@ sub SetRecipients {
=head2 SetReturnAddress
-Set this message\'s return address to the apropriate queue address
+Set this message's return address to the apropriate queue address
=cut
diff --git a/rt/lib/RT/Action/CreateTickets.pm b/rt/lib/RT/Action/CreateTickets.pm
index efd2bdaf6..80308020f 100644
--- a/rt/lib/RT/Action/CreateTickets.pm
+++ b/rt/lib/RT/Action/CreateTickets.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -56,14 +56,11 @@ use MIME::Entity;
=head1 NAME
- RT::Action::CreateTickets
-
-Create one or more tickets according to an externally supplied template.
-
+RT::Action::CreateTickets - Create one or more tickets according to an externally supplied template
=head1 SYNOPSIS
- ===Create-Ticket codereview
+ ===Create-Ticket: codereview
Subject: Code review for {$Tickets{'TOP'}->Subject}
Depended-On-By: TOP
Content: Someone has created a ticket. you should review and approve it,
@@ -72,18 +69,14 @@ Create one or more tickets according to an externally supplied template.
=head1 DESCRIPTION
+The CreateTickets ScripAction allows you to create automated workflows in RT,
+creating new tickets in response to actions and conditions from other
+tickets.
-Using the "CreateTickets" ScripAction and mandatory dependencies, RT now has
-the ability to model complex workflow. When a ticket is created in a queue
-that has a "CreateTickets" scripaction, that ScripAction parses its "Template"
-
-
-
-=head2 FORMAT
-
-CreateTickets uses the template as a template for an ordered set of tickets
-to create. The basic format is as follows:
+=head2 Format
+CreateTickets uses the RT template configured in the scrip as a template
+for an ordered set of tickets to create. The basic format is as follows:
===Create-Ticket: identifier
Param: Value
@@ -98,19 +91,24 @@ to create. The basic format is as follows:
Content: Blah
ENDOFCONTENT
-
-Each ===Create-Ticket: section is evaluated as its own
-Text::Template object, which means that you can embed snippets
-of perl inside the Text::Template using {} delimiters, but that
-such sections absolutely can not span a ===Create-Ticket boundary.
-
-After each ticket is created, it's stuffed into a hash called %Tickets
-so as to be available during the creation of other tickets during the
-same ScripAction, using the key 'create-identifier', where
-C<identifier> is the id you put after C<===Create-Ticket:>. The hash
+As shown, you can put one or more C<===Create-Ticket:> sections in
+a template. Each C<===Create-Ticket:> section is evaluated as its own
+L<Text::Template> object, which means that you can embed snippets
+of Perl inside the L<Text::Template> using C<{}> delimiters, but that
+such sections absolutely can not span a C<===Create-Ticket:> boundary.
+
+Note that each C<Value> must come right after the C<Param> on the same
+line. The C<Content:> param can extend over multiple lines, but the text
+of the first line must start right after C<Content:>. Don't try to start
+your C<Content:> section with a newline.
+
+After each ticket is created, it's stuffed into a hash called C<%Tickets>
+making it available during the creation of other tickets during the
+same ScripAction. The hash key for each ticket is C<create-[identifier]>,
+where C<[identifier]> is the value you put after C<===Create-Ticket:>. The hash
is prepopulated with the ticket which triggered the ScripAction as
-$Tickets{'TOP'}; you can also access that ticket using the shorthand
-TOP.
+C<$Tickets{'TOP'}>. You can also access that ticket using the shorthand
+C<TOP>.
A simple example:
@@ -121,22 +119,20 @@ A simple example:
so they can finish their work
ENDOFCONTENT
-
-
-A convoluted example
+A convoluted example:
===Create-Ticket: approval
{ # Find out who the administrators of the group called "HR"
# of which the creator of this ticket is a member
my $name = "HR";
-
+
my $groups = RT::Groups->new(RT->SystemUser);
$groups->LimitToUserDefinedGroups();
$groups->Limit(FIELD => "Name", OPERATOR => "=", VALUE => "$name");
$groups->WithMember($TransactionObj->CreatorObj->Id);
-
+
my $groupid = $groups->First->Id;
-
+
my $adminccs = RT::Users->new(RT->SystemUser);
$adminccs->WhoHaveRight(
Right => "AdminGroup",
@@ -145,10 +141,10 @@ A convoluted example
IncludeSuperusers => 0,
IncludeSubgroupMembers => 0,
);
-
- my @admins;
+
+ our @admins;
while (my $admin = $adminccs->Next) {
- push (@admins, $admin->EmailAddress);
+ push (@admins, $admin->EmailAddress);
}
}
Queue: ___Approvals
@@ -170,50 +166,51 @@ A convoluted example
Refers-To: {$Tickets{"create-approval"}->Id}
Queue: ___Approvals
Content-Type: text/plain
- Content:
- Your approval is requred for this ticket, too.
+ Content: Your approval is requred for this ticket, too.
ENDOFCONTENT
-
-=head2 Acceptable fields
-A complete list of acceptable fields for this beastie:
+As shown above, you can include a block with Perl code to set up some
+values for the new tickets. If you want to access a variable in the
+template section after the block, you must scope it with C<our> rather
+than C<my>. Just as with other RT templates, you can also include
+Perl code in the template sections using C<{}>.
+=head2 Acceptable Fields
+
+A complete list of acceptable fields:
* Queue => Name or id# of a queue
Subject => A text string
- ! Status => A valid status. defaults to 'new'
+ ! Status => A valid status. Defaults to 'new'
Due => Dates can be specified in seconds since the epoch
to be handled literally or in a semi-free textual
format which RT will attempt to parse.
-
-
-
- Starts =>
- Started =>
- Resolved =>
- Owner => Username or id of an RT user who can and should own
+ Starts =>
+ Started =>
+ Resolved =>
+ Owner => Username or id of an RT user who can and should own
this ticket; forces the owner if necessary
+ Requestor => Email address
- + Cc => Email address
- + AdminCc => Email address
+ + Cc => Email address
+ + AdminCc => Email address
+ RequestorGroup => Group name
+ CcGroup => Group name
+ AdminCcGroup => Group name
- TimeWorked =>
- TimeEstimated =>
- TimeLeft =>
- InitialPriority =>
- FinalPriority =>
- Type =>
- +! DependsOn =>
+ TimeWorked =>
+ TimeEstimated =>
+ TimeLeft =>
+ InitialPriority =>
+ FinalPriority =>
+ Type =>
+ +! DependsOn =>
+! DependedOnBy =>
+! RefersTo =>
- +! ReferredToBy =>
+ +! ReferredToBy =>
+! Members =>
- +! MemberOf =>
- Content => content. Can extend to multiple lines. Everything
+ +! MemberOf =>
+ Content => Content. Can extend to multiple lines. Everything
within a template after a Content: header is treated
- as content until we hit a line containing only
+ as content until we hit a line containing only
ENDOFCONTENT
ContentType => the content-type of the Content field. Defaults to
'text/plain'
@@ -225,31 +222,22 @@ A complete list of acceptable fields for this beastie:
CF-name => custom field value
CustomField-name => custom field value
-Fields marked with an * are required.
+Fields marked with an C<*> are required.
-Fields marked with a + may have multiple values, simply
+Fields marked with a C<+> may have multiple values, simply
by repeating the fieldname on a new line with an additional value.
-Fields marked with a ! are postponed to be processed after all
-tickets in the same actions are created. Except for 'Status', those
-field can also take a ticket name within the same action (i.e.
-the identifiers after ===Create-Ticket), instead of raw Ticket ID
+Fields marked with a C<!> have processing postponed until after all
+tickets in the same actions are created. Except for C<Status>, those
+fields can also take a ticket name within the same action (i.e.
+the identifiers after C<===Create-Ticket:>), instead of raw ticket ID
numbers.
-When parsed, field names are converted to lowercase and have -s stripped.
-Refers-To, RefersTo, refersto, refers-to and r-e-f-er-s-tO will all
-be treated as the same thing.
-
-
+When parsed, field names are converted to lowercase and have hyphens stripped.
+C<Refers-To>, C<RefersTo>, C<refersto>, C<refers-to> and C<r-e-f-er-s-tO> will
+all be treated as the same thing.
-
-=head1 AUTHOR
-
-Jesse Vincent <jesse@bestpractical.com>
-
-=head1 SEE ALSO
-
-perl(1).
+=head1 METHODS
=cut
@@ -537,12 +525,16 @@ sub UpdateByTemplate {
return @results;
}
-=head2 Parse TEMPLATE_CONTENT, DEFAULT_QUEUE, DEFAULT_REQEUESTOR ACTIVE
+=head2 Parse
+
+Takes (in order) template content, a default queue, a default requestor, and
+active (a boolean flag).
-Parse a template from TEMPLATE_CONTENT
+Parses a template in the template content, defaulting queue and requestor if
+unspecified in the template to the values provided as arguments.
-If $active is set to true, then we'll use Text::Template to parse the templates,
-allowing you to embed active perl in your templates.
+If the active flag is true, then we'll use L<Text::Template> to parse the
+templates, allowing you to embed active Perl in your templates.
=cut
@@ -576,9 +568,9 @@ sub Parse {
Parses mulitline templates. Things like:
- ===Create-Ticket ...
+ ===Create-Ticket: ...
-Takes the same arguments as Parse
+Takes the same arguments as L</Parse>.
=cut
@@ -834,9 +826,10 @@ sub ParseLines {
}
-=head2 _ParseXSVTemplate
+=head2 _ParseXSVTemplate
-Parses a tab or comma delimited template. Should only ever be called by Parse
+Parses a tab or comma delimited template. Should only ever be called by
+L</Parse>.
=cut
diff --git a/rt/lib/RT/Action/EscalatePriority.pm b/rt/lib/RT/Action/EscalatePriority.pm
index cb19b4f41..1300b4fe3 100644
--- a/rt/lib/RT/Action/EscalatePriority.pm
+++ b/rt/lib/RT/Action/EscalatePriority.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -78,6 +78,7 @@ package RT::Action::EscalatePriority;
use base 'RT::Action';
use strict;
+use warnings;
#Do what we need to do and send it out.
diff --git a/rt/lib/RT/Action/ExtractSubjectTag.pm b/rt/lib/RT/Action/ExtractSubjectTag.pm
index a4d6458cb..6a3898e74 100644
--- a/rt/lib/RT/Action/ExtractSubjectTag.pm
+++ b/rt/lib/RT/Action/ExtractSubjectTag.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -46,9 +46,48 @@
#
# END BPS TAGGED BLOCK }}}
+=head1 NAME
+
+ RT::Action::ExtractSubjectTag
+
+=head1 DESCRIPTION
+
+ExtractSubjectTag is a ScripAction which allows ticket bonding between
+two RT instances or between RT and other Ticket systems like Siebel
+or Remedy.
+
+By default this ScripAction is set up to run on every transaction on
+every Correspondence.
+
+One can configure this ScripActions behaviour by changing the
+global C<$ExtractSubjectTagMatch> in C<RT_Config.pm>.
+
+If a transaction's subject matches this regexp, we append the match
+tag to the ticket's current subject. This helps ensure that
+further communication on the ticket will include the remote
+system's subject tag.
+
+If you modify this code, be careful not to remove the code where it
+ensures that it only examines remote systems' tags.
+
+=head1 EXAMPLE
+
+As an example, Siebel will set their subject tag to something
+like:
+
+ B<[SR ID:1-554]>
+
+To record this tag in the local ticket's subject, we need to change
+ExtractSubjectTagMatch to something like:
+
+ Set($ExtractSubjectTagMatch, qr/\[[^\]]+[#:][0-9-]+\]/);
+
+=cut
+
package RT::Action::ExtractSubjectTag;
use base 'RT::Action';
use strict;
+use warnings;
sub Describe {
my $self = shift;
diff --git a/rt/lib/RT/Action/LinearEscalate.pm b/rt/lib/RT/Action/LinearEscalate.pm
index 0a0825e82..13913e6cd 100755
--- a/rt/lib/RT/Action/LinearEscalate.pm
+++ b/rt/lib/RT/Action/LinearEscalate.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/Notify.pm b/rt/lib/RT/Action/Notify.pm
index f1aef4092..3553cbc39 100755
--- a/rt/lib/RT/Action/Notify.pm
+++ b/rt/lib/RT/Action/Notify.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/NotifyAsComment.pm b/rt/lib/RT/Action/NotifyAsComment.pm
index b62f55599..0016a364a 100755
--- a/rt/lib/RT/Action/NotifyAsComment.pm
+++ b/rt/lib/RT/Action/NotifyAsComment.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/NotifyGroup.pm b/rt/lib/RT/Action/NotifyGroup.pm
index 5e7076f39..1dece60a3 100644
--- a/rt/lib/RT/Action/NotifyGroup.pm
+++ b/rt/lib/RT/Action/NotifyGroup.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/NotifyGroupAsComment.pm b/rt/lib/RT/Action/NotifyGroupAsComment.pm
index 151189033..cf6952aff 100644
--- a/rt/lib/RT/Action/NotifyGroupAsComment.pm
+++ b/rt/lib/RT/Action/NotifyGroupAsComment.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/RecordComment.pm b/rt/lib/RT/Action/RecordComment.pm
index 62832a5f4..a384af347 100644
--- a/rt/lib/RT/Action/RecordComment.pm
+++ b/rt/lib/RT/Action/RecordComment.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Action::RecordComment;
use base 'RT::Action';
use strict;
+use warnings;
=head1 NAME
diff --git a/rt/lib/RT/Action/RecordCorrespondence.pm b/rt/lib/RT/Action/RecordCorrespondence.pm
index 2faa56019..cc21503de 100644
--- a/rt/lib/RT/Action/RecordCorrespondence.pm
+++ b/rt/lib/RT/Action/RecordCorrespondence.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,12 +49,13 @@
package RT::Action::RecordCorrespondence;
use base 'RT::Action';
use strict;
+use warnings;
=head1 NAME
RT::Action::RecordCorrespondence - An Action which can be used from an
external tool, or in any situation where a ticket transaction has not
-been started, to make a comment on the ticket.
+been started, to create a correspondence on the ticket.
=head1 SYNOPSIS
diff --git a/rt/lib/RT/Action/SendEmail.pm b/rt/lib/RT/Action/SendEmail.pm
index 1e6607eb4..0a52904dd 100755
--- a/rt/lib/RT/Action/SendEmail.pm
+++ b/rt/lib/RT/Action/SendEmail.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/SetPriority.pm b/rt/lib/RT/Action/SetPriority.pm
index 783d57dd8..2043532f7 100644
--- a/rt/lib/RT/Action/SetPriority.pm
+++ b/rt/lib/RT/Action/SetPriority.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -50,6 +50,7 @@ package RT::Action::SetPriority;
use base 'RT::Action';
use strict;
+use warnings;
#Do what we need to do and send it out.
diff --git a/rt/lib/RT/Action/SetStatus.pm b/rt/lib/RT/Action/SetStatus.pm
index f52d401cc..be00396ce 100644
--- a/rt/lib/RT/Action/SetStatus.pm
+++ b/rt/lib/RT/Action/SetStatus.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Action/UserDefined.pm b/rt/lib/RT/Action/UserDefined.pm
index 1bad2bedd..b259323d7 100644
--- a/rt/lib/RT/Action/UserDefined.pm
+++ b/rt/lib/RT/Action/UserDefined.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -50,6 +50,7 @@ package RT::Action::UserDefined;
use base 'RT::Action';
use strict;
+use warnings;
=head2 Prepare
diff --git a/rt/lib/RT/Approval.pm b/rt/lib/RT/Approval.pm
index 6a519c1f7..dc60222a8 100644
--- a/rt/lib/RT/Approval.pm
+++ b/rt/lib/RT/Approval.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Approval/Rule.pm b/rt/lib/RT/Approval/Rule.pm
index 85526c1d8..6892f41ec 100644
--- a/rt/lib/RT/Approval/Rule.pm
+++ b/rt/lib/RT/Approval/Rule.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Approval/Rule/Created.pm b/rt/lib/RT/Approval/Rule/Created.pm
index cd4519c2e..8fcaeb273 100644
--- a/rt/lib/RT/Approval/Rule/Created.pm
+++ b/rt/lib/RT/Approval/Rule/Created.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Approval/Rule/NewPending.pm b/rt/lib/RT/Approval/Rule/NewPending.pm
index d2ba3ac4e..97d3cfbb5 100644
--- a/rt/lib/RT/Approval/Rule/NewPending.pm
+++ b/rt/lib/RT/Approval/Rule/NewPending.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Approval/Rule/Passed.pm b/rt/lib/RT/Approval/Rule/Passed.pm
index 000a8dc62..acc49161f 100644
--- a/rt/lib/RT/Approval/Rule/Passed.pm
+++ b/rt/lib/RT/Approval/Rule/Passed.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Approval/Rule/Rejected.pm b/rt/lib/RT/Approval/Rule/Rejected.pm
index b22df5c2d..0a025684f 100644
--- a/rt/lib/RT/Approval/Rule/Rejected.pm
+++ b/rt/lib/RT/Approval/Rule/Rejected.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Article.pm b/rt/lib/RT/Article.pm
index 678aa1177..ec1ae3cae 100644
--- a/rt/lib/RT/Article.pm
+++ b/rt/lib/RT/Article.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -399,9 +399,8 @@ sub AddLink {
# Check that we're actually getting a valid URI
my $uri_obj = RT::URI->new( $self->CurrentUser );
- $uri_obj->FromURI( $args{'Target'}||$args{'Base'} );
- unless ( $uri_obj->Resolver && $uri_obj->Scheme ) {
- my $msg = $self->loc( "Couldn't resolve '[_1]' into a Link.", $args{'Target'} );
+ unless ( $uri_obj->FromURI( $args{'Target'}||$args{'Base'} )) {
+ my $msg = $self->loc( "Couldn't resolve '[_1]' into a Link.", $args{'Target'} || $args{'Base'} );
$RT::Logger->warning( $msg );
return( 0, $msg );
}
@@ -611,15 +610,6 @@ sub CustomFieldLookupType {
"RT::Class-RT::Article";
}
-# _LookupId is the id of the toplevel type object the customfield is joined to
-# in this case, that's an RT::Class.
-
-sub _LookupId {
- my $self = shift;
- return $self->ClassObj->id;
-
-}
-
=head2 LoadByInclude Field Value
Takes the name of a form field from "Include Article"
diff --git a/rt/lib/RT/Articles.pm b/rt/lib/RT/Articles.pm
index 47d0ebea2..d69eabf82 100644
--- a/rt/lib/RT/Articles.pm
+++ b/rt/lib/RT/Articles.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Attachment.pm b/rt/lib/RT/Attachment.pm
index f1d9a6342..54217b32b 100755
--- a/rt/lib/RT/Attachment.pm
+++ b/rt/lib/RT/Attachment.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -266,7 +266,7 @@ sub ParentObj {
=head2 Children
Returns an L<RT::Attachments> object which is preloaded with
-all attachments objects with this attachment\'s Id as their
+all attachments objects with this attachment's Id as their
C<Parent>.
=cut
@@ -499,12 +499,14 @@ L<Email::Address> objects.
=cut
+our @ADDRESS_HEADERS = qw(From To Cc Bcc RT-Send-Cc RT-Send-Bcc);
+
sub Addresses {
my $self = shift;
my %data = ();
my $current_user_address = lc $self->CurrentUser->EmailAddress;
- foreach my $hdr (qw(From To Cc Bcc RT-Send-Cc RT-Send-Bcc)) {
+ foreach my $hdr (@ADDRESS_HEADERS) {
my @Addresses;
my $line = $self->GetHeader($hdr);
diff --git a/rt/lib/RT/Attachments.pm b/rt/lib/RT/Attachments.pm
index 2bdbc244c..5b087a493 100755
--- a/rt/lib/RT/Attachments.pm
+++ b/rt/lib/RT/Attachments.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Attribute.pm b/rt/lib/RT/Attribute.pm
index cd0b54e33..10971a279 100644
--- a/rt/lib/RT/Attribute.pm
+++ b/rt/lib/RT/Attribute.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Attributes.pm b/rt/lib/RT/Attributes.pm
index fcbd0b1b4..9c18c1a0f 100644
--- a/rt/lib/RT/Attributes.pm
+++ b/rt/lib/RT/Attributes.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Base.pm b/rt/lib/RT/Base.pm
index 2aae60e9e..403c318b4 100644
--- a/rt/lib/RT/Base.pm
+++ b/rt/lib/RT/Base.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/CachedGroupMember.pm b/rt/lib/RT/CachedGroupMember.pm
index 4c05852de..b334d4d6c 100644
--- a/rt/lib/RT/CachedGroupMember.pm
+++ b/rt/lib/RT/CachedGroupMember.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/CachedGroupMembers.pm b/rt/lib/RT/CachedGroupMembers.pm
index f76fc5dac..4d8f356fb 100644
--- a/rt/lib/RT/CachedGroupMembers.pm
+++ b/rt/lib/RT/CachedGroupMembers.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Class.pm b/rt/lib/RT/Class.pm
index 3906b9fed..dfe8eb386 100644
--- a/rt/lib/RT/Class.pm
+++ b/rt/lib/RT/Class.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -94,7 +94,7 @@ $RIGHTS = {
AdminClass => 'Modify metadata and custom fields for this class', #loc_pair
AdminTopics => 'Modify topic hierarchy associated with this class', #loc_pair
ShowACL => 'Display Access Control List', #loc_pair
- ModifyACL => 'Modify Access Control List', #loc_pair
+ ModifyACL => 'Create, modify and delete Access Control List entries', #loc_pair
DeleteArticle => 'Delete articles in this class', #loc_pair
};
@@ -218,7 +218,7 @@ sub ValidateName {
return undef unless ($newval);
my $obj = RT::Class->new($RT::SystemUser);
$obj->Load($newval);
- return undef if ( $obj->Id );
+ return undef if $obj->id && ( !$self->id || $self->id != $obj->id );
return $self->SUPER::ValidateName($newval);
}
diff --git a/rt/lib/RT/Classes.pm b/rt/lib/RT/Classes.pm
index 37dc411e8..60122c7eb 100644
--- a/rt/lib/RT/Classes.pm
+++ b/rt/lib/RT/Classes.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Condition.pm b/rt/lib/RT/Condition.pm
index f50d64d51..07518151f 100755
--- a/rt/lib/RT/Condition.pm
+++ b/rt/lib/RT/Condition.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Condition/AnyTransaction.pm b/rt/lib/RT/Condition/AnyTransaction.pm
index 73eea2b9e..2c9129c0f 100644
--- a/rt/lib/RT/Condition/AnyTransaction.pm
+++ b/rt/lib/RT/Condition/AnyTransaction.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -50,6 +50,7 @@ package RT::Condition::AnyTransaction;
use base 'RT::Condition';
use strict;
+use warnings;
=head2 IsApplicable
diff --git a/rt/lib/RT/Condition/BeforeDue.pm b/rt/lib/RT/Condition/BeforeDue.pm
index 11c40e6f5..8df73cacd 100644
--- a/rt/lib/RT/Condition/BeforeDue.pm
+++ b/rt/lib/RT/Condition/BeforeDue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -52,6 +52,7 @@ use base 'RT::Condition';
use RT::Date;
use strict;
+use warnings;
sub IsApplicable {
my $self = shift;
diff --git a/rt/lib/RT/Condition/CloseTicket.pm b/rt/lib/RT/Condition/CloseTicket.pm
index 60d5bbe26..bdeaf2d5d 100644
--- a/rt/lib/RT/Condition/CloseTicket.pm
+++ b/rt/lib/RT/Condition/CloseTicket.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Condition/Overdue.pm b/rt/lib/RT/Condition/Overdue.pm
index 3bf79a117..547aea25b 100644
--- a/rt/lib/RT/Condition/Overdue.pm
+++ b/rt/lib/RT/Condition/Overdue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -59,6 +59,7 @@ Returns true if the ticket we're operating on is overdue
package RT::Condition::Overdue;
use base 'RT::Condition';
use strict;
+use warnings;
=head2 IsApplicable
diff --git a/rt/lib/RT/Condition/OwnerChange.pm b/rt/lib/RT/Condition/OwnerChange.pm
index 4643791e3..85005482c 100644
--- a/rt/lib/RT/Condition/OwnerChange.pm
+++ b/rt/lib/RT/Condition/OwnerChange.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Condition::OwnerChange;
use base 'RT::Condition';
use strict;
+use warnings;
=head2 IsApplicable
diff --git a/rt/lib/RT/Condition/PriorityChange.pm b/rt/lib/RT/Condition/PriorityChange.pm
index aa00e609d..a600453a3 100644
--- a/rt/lib/RT/Condition/PriorityChange.pm
+++ b/rt/lib/RT/Condition/PriorityChange.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Condition::PriorityChange;
use base 'RT::Condition';
use strict;
+use warnings;
=head2 IsApplicable
diff --git a/rt/lib/RT/Condition/PriorityExceeds.pm b/rt/lib/RT/Condition/PriorityExceeds.pm
index 17943cf51..a28d6df15 100644
--- a/rt/lib/RT/Condition/PriorityExceeds.pm
+++ b/rt/lib/RT/Condition/PriorityExceeds.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Condition::PriorityExceeds;
use base 'RT::Condition';
use strict;
+use warnings;
=head2 IsApplicable
diff --git a/rt/lib/RT/Condition/QueueChange.pm b/rt/lib/RT/Condition/QueueChange.pm
index 69eea18d8..ba7a8a495 100644
--- a/rt/lib/RT/Condition/QueueChange.pm
+++ b/rt/lib/RT/Condition/QueueChange.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Condition::QueueChange;
use base 'RT::Condition';
use strict;
+use warnings;
=head2 IsApplicable
diff --git a/rt/lib/RT/Condition/ReopenTicket.pm b/rt/lib/RT/Condition/ReopenTicket.pm
index 70722218f..a057e401d 100644
--- a/rt/lib/RT/Condition/ReopenTicket.pm
+++ b/rt/lib/RT/Condition/ReopenTicket.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Condition/StatusChange.pm b/rt/lib/RT/Condition/StatusChange.pm
index 10d882e8f..e84915d19 100644
--- a/rt/lib/RT/Condition/StatusChange.pm
+++ b/rt/lib/RT/Condition/StatusChange.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Condition::StatusChange;
use base 'RT::Condition';
use strict;
+use warnings;
=head2 DESCRIPTION
diff --git a/rt/lib/RT/Condition/UserDefined.pm b/rt/lib/RT/Condition/UserDefined.pm
index 8ed5e5c15..1abee67f2 100644
--- a/rt/lib/RT/Condition/UserDefined.pm
+++ b/rt/lib/RT/Condition/UserDefined.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Condition::UserDefined;
use base 'RT::Condition';
use strict;
+use warnings;
=head2 IsApplicable
diff --git a/rt/lib/RT/Config.pm b/rt/lib/RT/Config.pm
index 014c76468..0c04b9191 100644
--- a/rt/lib/RT/Config.pm
+++ b/rt/lib/RT/Config.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -303,15 +303,6 @@ our %META = (
},
# User overridable options for RT at a glance
- DefaultSummaryRows => {
- Section => 'RT at a glance', #loc
- Overridable => 1,
- SortOrder => 1,
- Widget => '/Widgets/Form/Integer',
- WidgetArguments => {
- Description => 'Number of search results', #loc
- },
- },
HomePageRefreshInterval => {
Section => 'RT at a glance', #loc
Overridable => 1,
@@ -446,10 +437,13 @@ our %META = (
Description => 'Date format', #loc
Callback => sub { my $ret = { Values => [], ValuesLabel => {}};
my $date = RT::Date->new($HTML::Mason::Commands::session{'CurrentUser'});
- $date->Set;
+ $date->SetToNow;
foreach my $value ($date->Formatters) {
push @{$ret->{Values}}, $value;
- $ret->{ValuesLabel}{$value} = $date->$value();
+ $ret->{ValuesLabel}{$value} = $date->Get(
+ Format => $value,
+ Timezone => 'user',
+ );
}
return $ret;
},
@@ -1215,7 +1209,7 @@ sub SetFromConfig {
# if the entry has a trailing '::' then
# it is a link to another name space
if ( substr( $k, -2 ) eq '::') {
- $name = $self->__GetNameByRef( $ref, $k );
+ $name = $self->__GetNameByRef( $ref, $pack eq 'main::'? $k : $pack.$k );
return $name if $name;
}
@@ -1230,13 +1224,19 @@ sub SetFromConfig {
# Otherwie 5.10 goes boom. maybe we should skip any
# reference
next if ref($entry) eq 'SCALAR' || ref($entry) eq 'REF';
- my $entry_ref = *{$entry}{ ref($ref) };
+
+ my $ref_type = ref($ref);
+
+ # regex/arrayref/hashref/coderef are stored in SCALAR glob
+ $ref_type = 'SCALAR' if $ref_type eq 'REF';
+
+ my $entry_ref = *{$entry}{ $ref_type };
next unless $entry_ref;
# if references are equal then we've found
if ( $entry_ref == $ref ) {
$last_pack = $pack;
- return ( $REF_SYMBOLS{ ref($ref) } || '*' ) . $pack . $k;
+ return ( $REF_SYMBOLS{ $ref_type } || '*' ) . $pack . $k;
}
}
return '';
diff --git a/rt/lib/RT/Crypt/GnuPG.pm b/rt/lib/RT/Crypt/GnuPG.pm
index 233047820..6164a4241 100644
--- a/rt/lib/RT/Crypt/GnuPG.pm
+++ b/rt/lib/RT/Crypt/GnuPG.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -905,11 +905,25 @@ sub FindProtectedParts {
# sense) unnecessarily applies a base64 transfer encoding to PGP
# mail (whose content is already base64-encoded).
if ( $entity->bodyhandle->is_encoded and $entity->head->mime_encoding ) {
- pipe( my ($read_decoded, $write_decoded) );
my $decoder = MIME::Decoder->new( $entity->head->mime_encoding );
if ($decoder) {
- eval { $decoder->decode($io, $write_decoded) };
- $io = $read_decoded;
+ local $@;
+ eval {
+ my $buf = '';
+ open my $fh, '>', \$buf
+ or die "Couldn't open scalar for writing: $!";
+ binmode $fh, ":raw";
+ $decoder->decode($io, $fh);
+ close $fh or die "Couldn't close scalar: $!";
+
+ open $fh, '<', \$buf
+ or die "Couldn't re-open scalar for reading: $!";
+ binmode $fh, ":raw";
+ $io = $fh;
+ 1;
+ } or do {
+ $RT::Logger->error("Couldn't decode body: $@");
+ }
}
}
diff --git a/rt/lib/RT/CurrentUser.pm b/rt/lib/RT/CurrentUser.pm
index 7d24779bf..fa0d4ca7a 100755
--- a/rt/lib/RT/CurrentUser.pm
+++ b/rt/lib/RT/CurrentUser.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -240,9 +240,12 @@ sub loc {
my $handle = $self->LanguageHandle;
if (@_ == 1) {
- # pre-scan the lexicon hashes to return _AUTO keys verbatim,
- # to keep locstrings containing '[' and '~' from tripping over Maketext
- return $_[0] unless grep exists $_->{$_[0]}, @{ $handle->_lex_refs };
+ # If we have no [_1] replacements, and the key does not appear
+ # in the lexicon, unescape (using ~) and return it verbatim, as
+ # an optimization.
+ my $unescaped = $_[0];
+ $unescaped =~ s!~(.)!$1!g;
+ return $unescaped unless grep exists $_->{$_[0]}, @{ $handle->_lex_refs };
}
return $handle->maketext(@_);
diff --git a/rt/lib/RT/CustomField.pm b/rt/lib/RT/CustomField.pm
index 8d16c1fe1..01b4970c4 100644
--- a/rt/lib/RT/CustomField.pm
+++ b/rt/lib/RT/CustomField.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -710,7 +710,7 @@ sub ValidateValuesClass {
my $self = shift;
my $class = shift;
- return 1 if !defined $class || $class eq 'RT::CustomFieldValues';
+ return 1 if !$class || $class eq 'RT::CustomFieldValues';
return 1 if grep $class eq $_, RT->Config->Get('CustomFieldValuesSources');
return undef;
}
@@ -1556,9 +1556,8 @@ sub _CanonicalizeValueDate {
my $DateObj = RT::Date->new( $self->CurrentUser );
$DateObj->Set( Format => 'unknown',
Value => $args->{'Content'},
- Timezone => 'UTC',
);
- $args->{'Content'} = $DateObj->Date( Timezone => 'UTC' );
+ $args->{'Content'} = $DateObj->Date( Timezone => 'user' );
}
=head2 MatchPattern STRING
@@ -1666,14 +1665,13 @@ sub ValuesForObject {
my $object = shift;
my $values = RT::ObjectCustomFieldValues->new($self->CurrentUser);
- unless ($self->CurrentUserHasRight('SeeCustomField')) {
+ unless ($self->id and $self->CurrentUserHasRight('SeeCustomField')) {
# Return an empty object if they have no rights to see
+ $values->Limit( FIELD => "id", VALUE => 0, SUBCLAUSE => "ACL" );
return ($values);
}
-
-
+
$values->LimitToCustomField($self->Id);
- $values->LimitToEnabled();
$values->LimitToObject($object);
return ($values);
@@ -1690,6 +1688,7 @@ Examples:
'RT::Queue-RT::Ticket-RT::Transaction' => "Ticket Transactions", # loc
'RT::User' => "Users", # loc
'RT::Group' => "Groups", # loc
+ 'RT::Queue' => "Queues", # loc
This is a class method.
@@ -2103,6 +2102,8 @@ sub _CoreAccessible {
{read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''},
Repeated =>
{read => 1, write => 1, sql_type => 5, length => 6, is_blob => 0, is_numeric => 1, type => 'smallint(6)', default => '0'},
+ ValuesClass =>
+ {read => 1, write => 1, sql_type => 12, length => 64, is_blob => 0, is_numeric => 0, type => 'varchar(64)', default => ''},
BasedOn =>
{read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
Description =>
diff --git a/rt/lib/RT/CustomFieldValue.pm b/rt/lib/RT/CustomFieldValue.pm
index 26df55ae4..6dffc3455 100644
--- a/rt/lib/RT/CustomFieldValue.pm
+++ b/rt/lib/RT/CustomFieldValue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/CustomFieldValues.pm b/rt/lib/RT/CustomFieldValues.pm
index 90a163702..e3380b7e5 100644
--- a/rt/lib/RT/CustomFieldValues.pm
+++ b/rt/lib/RT/CustomFieldValues.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/CustomFieldValues/External.pm b/rt/lib/RT/CustomFieldValues/External.pm
index 61125146f..e6bf2f87d 100644
--- a/rt/lib/RT/CustomFieldValues/External.pm
+++ b/rt/lib/RT/CustomFieldValues/External.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -82,7 +82,7 @@ C<sortorder>.
=head1 SEE ALSO
-L<docs/extending/external_custom_fields.pod>
+F<docs/extending/external_custom_fields.pod>
=cut
diff --git a/rt/lib/RT/CustomFieldValues/Groups.pm b/rt/lib/RT/CustomFieldValues/Groups.pm
index 2519e2917..feeeadbd7 100644
--- a/rt/lib/RT/CustomFieldValues/Groups.pm
+++ b/rt/lib/RT/CustomFieldValues/Groups.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/CustomFields.pm b/rt/lib/RT/CustomFields.pm
index d4a5bc740..017018ef4 100644
--- a/rt/lib/RT/CustomFields.pm
+++ b/rt/lib/RT/CustomFields.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Dashboard.pm b/rt/lib/RT/Dashboard.pm
index 2e2bbc489..349864e12 100644
--- a/rt/lib/RT/Dashboard.pm
+++ b/rt/lib/RT/Dashboard.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -109,7 +109,7 @@ An object of this class is called "dashboard"
=cut
-sub ObjectName { "dashboard" }
+sub ObjectName { "dashboard" } # loc
sub SaveAttribute {
my $self = shift;
diff --git a/rt/lib/RT/Dashboard/Mailer.pm b/rt/lib/RT/Dashboard/Mailer.pm
index 40b53b111..9d28c4942 100644
--- a/rt/lib/RT/Dashboard/Mailer.pm
+++ b/rt/lib/RT/Dashboard/Mailer.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -59,6 +59,7 @@ use RT::Dashboard;
use RT::Interface::Web::Handler;
use RT::Interface::Web;
use File::Temp 'tempdir';
+use HTML::Scrubber;
sub MailDashboards {
my $self = shift;
@@ -248,6 +249,8 @@ SUMMARY
}
}
+ $content = ScrubContent($content);
+
$RT::Logger->debug("Got ".length($content)." characters of output.");
$content = HTML::RewriteAttributes::Links->rewrite(
@@ -393,7 +396,7 @@ sub BuildEmail {
Type => $mimetype,
Encoding => $encoding,
Disposition => 'inline',
- Name => $filename,
+ Name => RT::Interface::Email::EncodeToMIME( String => $filename ),
'Content-Id' => $cid_of{$uri},
);
@@ -408,9 +411,9 @@ sub BuildEmail {
);
my $entity = MIME::Entity->build(
- From => $args{From},
- To => $args{To},
- Subject => $args{Subject},
+ From => Encode::encode_utf8($args{From}),
+ To => Encode::encode_utf8($args{To}),
+ Subject => RT::Interface::Email::EncodeToMIME( String => $args{Subject} ),
Type => "multipart/mixed",
);
@@ -463,6 +466,33 @@ sub BuildEmail {
}
{
+ my $scrubber;
+
+ sub _scrubber {
+ unless ($scrubber) {
+ $scrubber = HTML::Scrubber->new;
+ # Allow everything by default, except JS attributes ...
+ $scrubber->default(
+ 1 => {
+ '*' => 1,
+ map { ("on$_" => 0) }
+ qw(blur change click dblclick error focus keydown keypress keyup load
+ mousedown mousemove mouseout mouseover mouseup reset select submit unload)
+ }
+ );
+ # ... and <script>s
+ $scrubber->deny('script');
+ }
+ return $scrubber;
+ }
+
+ sub ScrubContent {
+ my $content = shift;
+ return _scrubber->scrub($content);
+ }
+}
+
+{
my %cache;
sub HourDowDomIn {
@@ -560,8 +590,9 @@ sub GetResource {
{
package RT::Dashboard::FakeRequest;
sub new { bless {}, shift }
- sub header_out { shift }
- sub headers_out { shift }
+ sub header_out { return undef }
+ sub headers_out { wantarray ? () : {} }
+ sub err_headers_out { wantarray ? () : {} }
sub content_type {
my $self = shift;
$self->{content_type} = shift if @_;
diff --git a/rt/lib/RT/Dashboards.pm b/rt/lib/RT/Dashboards.pm
index 5d10205a3..f9cbbe877 100644
--- a/rt/lib/RT/Dashboards.pm
+++ b/rt/lib/RT/Dashboards.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -70,6 +70,7 @@ package RT::Dashboards;
use RT::Dashboard;
use strict;
+use warnings;
use base 'RT::SharedSettings';
sub RecordClass {
diff --git a/rt/lib/RT/Date.pm b/rt/lib/RT/Date.pm
index 442c7701d..031f9c8d4 100644
--- a/rt/lib/RT/Date.pm
+++ b/rt/lib/RT/Date.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/EmailParser.pm b/rt/lib/RT/EmailParser.pm
index dd73d9049..19dc2c9e8 100644
--- a/rt/lib/RT/EmailParser.pm
+++ b/rt/lib/RT/EmailParser.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -131,8 +131,6 @@ sub SmartParseMIMEEntityFromScalar {
}
};
- $self->RescueOutlook;
-
#If for some reason we weren't able to parse the message using a temp file
# try it with a scalar
if ( $@ || !$self->Entity ) {
@@ -286,7 +284,7 @@ sub _PostProcessNewEntity {
Takes a hashref object containing QueueObj, Head and CurrentUser objects.
Returns a list of all email addresses in the To and Cc
-headers b<except> the current Queue\'s email addresses, the CurrentUser\'s
+headers b<except> the current Queue's email addresses, the CurrentUser's
email address and anything that the RT->Config->Get('RTAddressRegexp') matches.
=cut
@@ -568,50 +566,90 @@ return 1 if it does find the problem in the entity and get it fixed.
sub RescueOutlook {
my $self = shift;
my $mime = $self->Entity();
- return unless $mime;
-
- my $mailer = $mime->head->get('X-Mailer');
- # 12.0 is outlook 2007, 14.0 is 2010
- if ( $mailer && $mailer =~ /Microsoft(?:.*?)Outlook 1[2-4]\./ ) {
- my $text_part;
- if ( $mime->head->get('Content-Type') =~ m{multipart/mixed} ) {
- my $first = $mime->parts(0);
- if ( $first && $first->head->get('Content-Type') =~ m{multipart/alternative} )
+ return unless $mime && $self->LooksLikeMSEmail($mime);
+
+ my $text_part;
+ if ( $mime->head->get('Content-Type') =~ m{multipart/mixed} ) {
+ my $first = $mime->parts(0);
+ if ( $first && $first->head->get('Content-Type') =~ m{multipart/alternative} )
+ {
+ my $inner_first = $first->parts(0);
+ if ( $inner_first && $inner_first->head->get('Content-Type') =~ m{text/plain} )
{
- my $inner_first = $first->parts(0);
- if ( $inner_first && $inner_first->head->get('Content-Type') =~ m{text/plain} )
- {
- $text_part = $inner_first;
- }
+ $text_part = $inner_first;
}
}
- elsif ( $mime->head->get('Content-Type') =~ m{multipart/alternative} ) {
- my $first = $mime->parts(0);
- if ( $first && $first->head->get('Content-Type') =~ m{text/plain} ) {
- $text_part = $first;
- }
+ }
+ elsif ( $mime->head->get('Content-Type') =~ m{multipart/alternative} ) {
+ my $first = $mime->parts(0);
+ if ( $first && $first->head->get('Content-Type') =~ m{text/plain} ) {
+ $text_part = $first;
}
+ }
- if ($text_part) {
-
- # use the unencoded string
- my $content = $text_part->bodyhandle->as_string;
- if ( $content =~ s/\n\n/\n/g ) {
- # only write only if we did change the content
- if ( my $io = $text_part->open("w") ) {
- $io->print($content);
- $io->close;
- return 1;
- }
- else {
- $RT::Logger->error("can't write to body");
- }
+ # Add base64 since we've seen examples of double newlines with
+ # this type too. Need an example of a multi-part base64 to
+ # handle that permutation if it exists.
+ elsif ( $mime->head->get('Content-Transfer-Encoding') =~ m{base64} ) {
+ $text_part = $mime; # Assuming single part, already decoded.
+ }
+
+ if ($text_part) {
+
+ # use the unencoded string
+ my $content = $text_part->bodyhandle->as_string;
+ if ( $content =~ s/\n\n/\n/g ) {
+
+ # Outlook puts a space on extra newlines, remove it
+ $content =~ s/\ +$//mg;
+
+ # only write only if we did change the content
+ if ( my $io = $text_part->open("w") ) {
+ $io->print($content);
+ $io->close;
+ $RT::Logger->debug(
+ "Removed extra newlines from MS Outlook message.");
+ return 1;
+ }
+ else {
+ $RT::Logger->error("Can't write to body to fix newlines");
}
}
}
+
return;
}
+=head1 LooksLikeMSEmail
+
+Try to determine if the current email may have
+come from MS Outlook or gone through Exchange, and therefore
+may have extra newlines added.
+
+=cut
+
+sub LooksLikeMSEmail {
+ my $self = shift;
+ my $mime = shift;
+
+ my $mailer = $mime->head->get('X-Mailer');
+
+ # 12.0 is outlook 2007, 14.0 is 2010
+ return 1 if ( $mailer && $mailer =~ /Microsoft(?:.*?)Outlook 1[2-4]\./ );
+
+ if ( RT->Config->Get('CheckMoreMSMailHeaders') ) {
+
+ # Check for additional headers that might
+ # indicate this came from Outlook or through Exchange.
+ # A sample we received had the headers X-MS-Has-Attach: and
+ # X-MS-Tnef-Correlator: and both had no value.
+
+ my @tags = $mime->head->tags();
+ return 1 if grep { /^X-MS-/ } @tags;
+ }
+
+ return 0; # Doesn't look like MS email.
+}
sub DESTROY {
my $self = shift;
diff --git a/rt/lib/RT/Generated.pm b/rt/lib/RT/Generated.pm
index 907ea77f6..4f74ea984 100644
--- a/rt/lib/RT/Generated.pm
+++ b/rt/lib/RT/Generated.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -50,7 +50,7 @@ package RT;
use warnings;
use strict;
-our $VERSION = '4.0.8';
+our $VERSION = '4.0.13';
diff --git a/rt/lib/RT/Generated.pm.in b/rt/lib/RT/Generated.pm.in
index ac15bdea4..91aa84073 100644
--- a/rt/lib/RT/Generated.pm.in
+++ b/rt/lib/RT/Generated.pm.in
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Graph/Tickets.pm b/rt/lib/RT/Graph/Tickets.pm
index b839824f9..753ff20e7 100644
--- a/rt/lib/RT/Graph/Tickets.pm
+++ b/rt/lib/RT/Graph/Tickets.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Group.pm b/rt/lib/RT/Group.pm
index b367b2f96..d4d2802ad 100755
--- a/rt/lib/RT/Group.pm
+++ b/rt/lib/RT/Group.pm
@@ -3,7 +3,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -51,7 +51,7 @@
=head1 NAME
- RT::Group - RT\'s group object
+ RT::Group - RT's group object
=head1 SYNOPSIS
@@ -529,8 +529,9 @@ sub _ValidateUserDefinedName {
my $dupcheck = RT::Group->new(RT->SystemUser);
$dupcheck->LoadUserDefinedGroup($value);
- return (0, $self->loc("Group name '[_1]' is already in use", $value))
- if $dupcheck->id;
+ if ( $dupcheck->id && ( !$self->id || $self->id != $dupcheck->id ) ) {
+ return ( 0, $self->loc( "Group name '[_1]' is already in use", $value ) );
+ }
return 1;
}
diff --git a/rt/lib/RT/GroupMember.pm b/rt/lib/RT/GroupMember.pm
index 8df4a73c4..e3c5e1dda 100755
--- a/rt/lib/RT/GroupMember.pm
+++ b/rt/lib/RT/GroupMember.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/GroupMembers.pm b/rt/lib/RT/GroupMembers.pm
index 0b56c027b..52244bd09 100755
--- a/rt/lib/RT/GroupMembers.pm
+++ b/rt/lib/RT/GroupMembers.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Groups.pm b/rt/lib/RT/Groups.pm
index 578109c4f..e7734e095 100755
--- a/rt/lib/RT/Groups.pm
+++ b/rt/lib/RT/Groups.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -392,7 +392,7 @@ sub ForWhichCurrentUserHasRight {
=head2 LimitToEnabled
-Only find items that haven\'t been disabled
+Only find items that haven't been disabled
=cut
@@ -450,7 +450,7 @@ sub Next {
sub _DoSearch {
my $self = shift;
- #unless we really want to find disabled rows, make sure we\'re only finding enabled ones.
+ #unless we really want to find disabled rows, make sure we're only finding enabled ones.
unless($self->{'find_disabled_rows'}) {
$self->LimitToEnabled();
}
diff --git a/rt/lib/RT/Handle.pm b/rt/lib/RT/Handle.pm
index 03c262bba..b449d2037 100644
--- a/rt/lib/RT/Handle.pm
+++ b/rt/lib/RT/Handle.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -262,17 +262,19 @@ sub CheckCompatibility {
unless $version;
($version) = $version =~ /^(\d+\.\d+)/;
- return (0, "RT is unsupported on MySQL versions before 4.0.x, it's $version")
- if $version < 4;
+ return (0, "RT is unsupported on MySQL versions before 4.1. Your version is $version.")
+ if $version < 4.1;
# MySQL must have InnoDB support
- my $innodb = ($dbh->selectrow_array("show variables like 'have_innodb'"))[1];
- if ( lc $innodb eq "no" ) {
+ local $dbh->{FetchHashKeyName} = 'NAME_lc';
+ my $innodb = lc($dbh->selectall_hashref("SHOW ENGINES", "engine")->{InnoDB}{support} || "no");
+ if ( $innodb eq "no" ) {
return (0, "RT requires that MySQL be compiled with InnoDB table support.\n".
- "See http://dev.mysql.com/doc/mysql/en/InnoDB.html");
- } elsif ( lc $innodb eq "disabled" ) {
+ "See <http://dev.mysql.com/doc/mysql/en/innodb-storage-engine.html>\n".
+ "and check that there are no 'skip-innodb' lines in your my.cnf.");
+ } elsif ( $innodb eq "disabled" ) {
return (0, "RT requires that MySQL InnoDB table support be enabled.\n".
- "Remove the 'skip-innodb' line from your my.cnf file, restart MySQL, and try again.\n");
+ "Remove the 'skip-innodb' or 'innodb = OFF' line from your my.cnf file, restart MySQL, and try again.\n");
}
if ( $state eq 'post' ) {
@@ -280,14 +282,19 @@ sub CheckCompatibility {
unless ( $create_table =~ /(?:ENGINE|TYPE)\s*=\s*InnoDB/i ) {
return (0, "RT requires that all its tables be of InnoDB type. Upgrade RT tables.");
}
- }
- if ( $version >= 4.1 && $state eq 'post' ) {
- my $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Attachments")->[1];
+
+ $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Attachments")->[1];
unless ( $create_table =~ /\bContent\b[^,]*BLOB/i ) {
return (0, "RT since version 3.8 has new schema for MySQL versions after 4.1.0\n"
."Follow instructions in the UPGRADING.mysql file.");
}
}
+
+ my $max_packet = ($dbh->selectrow_array("show variables like 'max_allowed_packet'"))[1];
+ if ($state =~ /^(create|post)$/ and $max_packet <= (1024 * 1024)) {
+ my $max_packet = sprintf("%.1fM", $max_packet/1024/1024);
+ warn "max_allowed_packet is set to $max_packet, which limits the maximum attachment or email size that RT can process. Consider adjusting MySQL's max_allowed_packet setting.\n";
+ }
}
return (1)
}
@@ -578,7 +585,13 @@ sub cmp_version($$) {
return $a[$i] <=> $b[$i] if $a[$i] <=> $b[$i];
}
return 0;
-}}
+}
+
+sub version_words {
+ return keys %word;
+}
+
+}
=head2 InsertInitialData
diff --git a/rt/lib/RT/I18N.pm b/rt/lib/RT/I18N.pm
index e453cfa04..0e75b9f3b 100644
--- a/rt/lib/RT/I18N.pm
+++ b/rt/lib/RT/I18N.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -209,16 +209,27 @@ sub SetMIMEEntityToEncoding {
# do the same for parts first of all
SetMIMEEntityToEncoding( $_, $enc, $preserve_words ) foreach $entity->parts;
- my $charset = _FindOrGuessCharset($entity) or return;
+ my $head = $entity->head;
+
+ my $charset = _FindOrGuessCharset($entity);
+ if ( $charset ) {
+ unless( Encode::find_encoding($charset) ) {
+ $RT::Logger->warning("Encoding '$charset' is not supported");
+ $charset = undef;
+ }
+ }
+ unless ( $charset ) {
+ $head->replace( "X-RT-Original-Content-Type" => $head->mime_attr('Content-Type') );
+ $head->mime_attr('Content-Type' => 'application/octet-stream');
+ return;
+ }
SetMIMEHeadToEncoding(
- $entity->head,
+ $head,
_FindOrGuessCharset($entity, 1) => $enc,
$preserve_words
);
- my $head = $entity->head;
-
# If this is a textual entity, we'd need to preserve its original encoding
$head->replace( "X-RT-Original-Encoding" => $charset )
if $head->mime_attr('content-type.charset') or IsTextualContentType($head->mime_type);
@@ -293,18 +304,30 @@ sub DecodeMIMEWordsToEncoding {
$str = MIME::Field::ParamVal->parse($str)->stringify;
}
+ # Pre-parse by removing all whitespace between encoded words
+ my $encoded_word = qr/
+ =\? # =?
+ ([^?]+?) # charset
+ (?:\*[^?]+)? # optional '*language'
+ \? # ?
+ ([QqBb]) # encoding
+ \? # ?
+ ([^?]+) # encoded string
+ \?= # ?=
+ /x;
+ $str =~ s/($encoded_word)\s+(?=$encoded_word)/$1/g;
+
+ # Also merge quoted-printable sections together, in case multiple
+ # octets of a single encoded character were split between chunks.
+ # Though not valid according to RFC 2047, this has been seen in the
+ # wild.
+ 1 while $str =~ s/(=\?[^?]+\?[Qq]\?)([^?]+)\?=\1([^?]+)\?=/$1$2$3?=/i;
+
# XXX TODO: use decode('MIME-Header', ...) and Encode::Alias to replace our
# custom MIME word decoding and charset canonicalization. We can't do this
# until we parse before decode, instead of the other way around.
my @list = $str =~ m/(.*?) # prefix
- =\? # =?
- ([^?]+?) # charset
- (?:\*[^?]+)? # optional '*language'
- \? # ?
- ([QqBb]) # encoding
- \? # ?
- ([^?]+) # encoded string
- \?= # ?=
+ $encoded_word
([^=]*) # trailing
/xgcs;
@@ -336,7 +359,14 @@ sub DecodeMIMEWordsToEncoding {
# now we have got a decoded subject, try to convert into the encoding
if ( $charset ne $to_charset || $charset =~ /^utf-?8(?:-strict)?$/i ) {
- Encode::from_to( $enc_str, $charset, $to_charset );
+ if ( Encode::find_encoding($charset) ) {
+ Encode::from_to( $enc_str, $charset, $to_charset );
+ } else {
+ $RT::Logger->warning("Charset '$charset' is not supported");
+ $enc_str =~ s/[^[:print:]]/\357\277\275/g;
+ Encode::from_to( $enc_str, 'UTF-8', $to_charset )
+ unless $to_charset eq 'utf-8';
+ }
}
# XXX TODO: RT doesn't currently do the right thing with mime-encoded headers
diff --git a/rt/lib/RT/I18N/cs.pm b/rt/lib/RT/I18N/cs.pm
index 58631b624..faea9d70b 100644
--- a/rt/lib/RT/I18N/cs.pm
+++ b/rt/lib/RT/I18N/cs.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/I18N/i_default.pm b/rt/lib/RT/I18N/i_default.pm
index c220bc04f..2b48c629c 100644
--- a/rt/lib/RT/I18N/i_default.pm
+++ b/rt/lib/RT/I18N/i_default.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/I18N/ru.pm b/rt/lib/RT/I18N/ru.pm
index 1635a1862..a98636f19 100755
--- a/rt/lib/RT/I18N/ru.pm
+++ b/rt/lib/RT/I18N/ru.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Installer.pm b/rt/lib/RT/Installer.pm
index d12abb678..d876e10aa 100644
--- a/rt/lib/RT/Installer.pm
+++ b/rt/lib/RT/Installer.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -97,6 +97,7 @@ my %Meta = (
},
},
DatabaseAdmin => {
+ SkipWrite => 1,
Widget => '/Widgets/Form/String',
WidgetArguments => {
Default => 1,
@@ -106,6 +107,7 @@ my %Meta = (
},
},
DatabaseAdminPassword => {
+ SkipWrite => 1,
Widget => '/Widgets/Form/String',
WidgetArguments => {
Description => 'DBA password', #loc
@@ -149,6 +151,7 @@ my %Meta = (
},
},
Password => {
+ SkipWrite => 1,
Widget => '/Widgets/Form/String',
WidgetArguments => {
Description => 'Administrative password', #loc
@@ -274,10 +277,10 @@ sub SaveConfig {
$RT::Installer->{InstallConfig}{rtname};
if ( open my $fh, '>', $file ) {
- for ( keys %{ $RT::Installer->{InstallConfig} } ) {
+ for ( sort keys %{ $RT::Installer->{InstallConfig} } ) {
# we don't want to store root's password in config.
- next if $_ eq 'Password';
+ next if $class->Meta($_) and $class->Meta($_)->{SkipWrite};
$RT::Installer->{InstallConfig}{$_} = ''
unless defined $RT::Installer->{InstallConfig}{$_};
diff --git a/rt/lib/RT/Interface/CLI.pm b/rt/lib/RT/Interface/CLI.pm
index bcdc13cdf..c1a6f4fe8 100644
--- a/rt/lib/RT/Interface/CLI.pm
+++ b/rt/lib/RT/Interface/CLI.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -48,6 +48,7 @@
package RT::Interface::CLI;
use strict;
+use warnings;
use RT;
use base 'Exporter';
@@ -92,7 +93,7 @@ our @EXPORT_OK = qw(CleanEnv GetCurrentUser GetMessageContent debug loc);
=head2 CleanEnv
-Removes some of the nastiest nasties from the user\'s environment.
+Removes some of the nastiest nasties from the user's environment.
=cut
diff --git a/rt/lib/RT/Interface/Email.pm b/rt/lib/RT/Interface/Email.pm
index dda6f704a..ab319e665 100755
--- a/rt/lib/RT/Interface/Email.pm
+++ b/rt/lib/RT/Interface/Email.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -149,6 +149,9 @@ sub CheckForSuspiciousSender {
my ( $From, $junk ) = ParseSenderAddressFromHead($head);
+ # If unparseable (non-ASCII), $From can come back undef
+ return undef if not defined $From;
+
if ( ( $From =~ /^mailer-daemon\@/i )
or ( $From =~ /^postmaster\@/i )
or ( $From eq "" ))
@@ -222,8 +225,8 @@ add 'In-Reply-To' field to the error that points to this message.
=item Attach - optional text that attached to the error as 'message/rfc822' part.
-=item LogLevel - log level under which we should write explanation message into the
-log, by default we log it as critical.
+=item LogLevel - log level under which we should write the subject and
+explanation message into the log, by default we log it as critical.
=back
@@ -244,7 +247,7 @@ sub MailError {
$RT::Logger->log(
level => $args{'LogLevel'},
- message => $args{'Explanation'}
+ message => "$args{Subject}: $args{'Explanation'}",
) if $args{'LogLevel'};
# the colons are necessary to make ->build include non-standard headers
@@ -1059,7 +1062,7 @@ sub CreateUser {
Takes a hash containing QueueObj, Head and CurrentUser objects.
Returns a list of all email addresses in the To and Cc
-headers b<except> the current Queue\'s email addresses, the CurrentUser\'s
+headers b<except> the current Queue's email addresses, the CurrentUser's
email address and anything that the configuration sub RT::IsRTAddress matches.
=cut
@@ -1101,23 +1104,34 @@ sub IgnoreCcAddress {
=head2 ParseSenderAddressFromHead HEAD
-Takes a MIME::Header object. Returns a tuple: (user@host, friendly name)
-of the From (evaluated in order of Reply-To:, From:, Sender)
+Takes a MIME::Header object. Returns (user@host, friendly name, errors)
+where the first two values are the From (evaluated in order of
+Reply-To:, From:, Sender).
+
+A list of error messages may be returned even when a Sender value is
+found, since it could be a parse error for another (checked earlier)
+sender field. In this case, the errors aren't fatal, but may be useful
+to investigate the parse failure.
=cut
sub ParseSenderAddressFromHead {
my $head = shift;
+ my @sender_headers = ('Reply-To', 'From', 'Sender');
+ my @errors; # Accumulate any errors
#Figure out who's sending this message.
- foreach my $header ('Reply-To', 'From', 'Sender') {
+ foreach my $header ( @sender_headers ) {
my $addr_line = $head->get($header) || next;
my ($addr, $name) = ParseAddressFromHeader( $addr_line );
# only return if the address is not empty
- return ($addr, $name) if $addr;
+ return ($addr, $name, @errors) if $addr;
+
+ chomp $addr_line;
+ push @errors, "$header: $addr_line";
}
- return (undef, undef);
+ return (undef, undef, @errors);
}
=head2 ParseErrorsToAddressFromHead HEAD
@@ -1445,6 +1459,7 @@ sub Gateway {
}
@mail_plugins = grep !$skip_plugin{"$_"}, @mail_plugins;
$parser->_DecodeBodies;
+ $parser->RescueOutlook;
$parser->_PostProcessNewEntity;
my $head = $Message->head;
@@ -1476,6 +1491,10 @@ sub Gateway {
$args{'ticket'} ||= ExtractTicketId( $Message );
+ # ExtractTicketId may have been overridden, and edited the Subject
+ my $NewSubject = $Message->head->get('Subject');
+ chomp $NewSubject;
+
$SystemTicket = RT::Ticket->new( RT->SystemUser );
$SystemTicket->Load( $args{'ticket'} ) if ( $args{'ticket'} ) ;
if ( $SystemTicket->id ) {
@@ -1560,9 +1579,11 @@ sub Gateway {
);
}
+ $head->replace('X-RT-Interface' => 'Email');
+
my ( $id, $Transaction, $ErrStr ) = $Ticket->Create(
Queue => $SystemQueueObj->Id,
- Subject => $Subject,
+ Subject => $NewSubject,
Requestor => \@Requestors,
Cc => \@Cc,
MIMEObj => $Message
@@ -1615,7 +1636,7 @@ sub Gateway {
#Warn the sender that we couldn't actually submit the comment.
MailError(
To => $ErrorsTo,
- Subject => "Message not recorded: $Subject",
+ Subject => "Message not recorded ($method): $Subject",
Explanation => $msg,
MIMEObj => $Message
);
diff --git a/rt/lib/RT/Interface/Email/Auth/GnuPG.pm b/rt/lib/RT/Interface/Email/Auth/GnuPG.pm
index 87a523dad..c14bcf074 100755
--- a/rt/lib/RT/Interface/Email/Auth/GnuPG.pm
+++ b/rt/lib/RT/Interface/Email/Auth/GnuPG.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Interface/Email/Auth/MailFrom.pm b/rt/lib/RT/Interface/Email/Auth/MailFrom.pm
index e733bdaae..bfe493958 100644
--- a/rt/lib/RT/Interface/Email/Auth/MailFrom.pm
+++ b/rt/lib/RT/Interface/Email/Auth/MailFrom.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -66,9 +66,12 @@ sub GetCurrentUser {
# We don't need to do any external lookups
- my ( $Address, $Name ) = ParseSenderAddressFromHead( $args{'Message'}->head );
+ my ( $Address, $Name, @errors ) = ParseSenderAddressFromHead( $args{'Message'}->head );
+ $RT::Logger->warning("Failed to parse ".join(', ', @errors))
+ if @errors;
+
unless ( $Address ) {
- $RT::Logger->error("Couldn't find sender's address");
+ $RT::Logger->error("Couldn't parse or find sender's address");
return ( $args{'CurrentUser'}, -1 );
}
diff --git a/rt/lib/RT/Interface/REST.pm b/rt/lib/RT/Interface/REST.pm
index aed8f39a2..5f8ff99b7 100644
--- a/rt/lib/RT/Interface/REST.pm
+++ b/rt/lib/RT/Interface/REST.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -58,8 +58,7 @@ sub custom_field_spec {
my $self = shift;
my $capture = shift;
- my $CF_char = '[\sa-z0-9_ :()/-]';
- my $CF_name = $CF_char . '+';
+ my $CF_name = '[^,]+';
$CF_name = '(' . $CF_name . ')' if $capture;
my $new_style = 'CF\.\{'.$CF_name.'\}';
diff --git a/rt/lib/RT/Interface/Web.pm b/rt/lib/RT/Interface/Web.pm
index 745a6f1e3..bdad21350 100644
--- a/rt/lib/RT/Interface/Web.pm
+++ b/rt/lib/RT/Interface/Web.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -266,6 +266,7 @@ sub HandleRequest {
# make user info up to date
$HTML::Mason::Commands::session{'CurrentUser'}
->Load( $HTML::Mason::Commands::session{'CurrentUser'}->id );
+ undef $HTML::Mason::Commands::session{'CurrentUser'}->{'LangHandle'};
}
else {
$HTML::Mason::Commands::session{'CurrentUser'} = RT::CurrentUser->new();
@@ -285,6 +286,10 @@ sub HandleRequest {
# Process per-page authentication callbacks
$HTML::Mason::Commands::m->callback( %$ARGS, CallbackName => 'Auth', CallbackPage => '/autohandler' );
+ if ( $ARGS->{'NotMobile'} ) {
+ $HTML::Mason::Commands::session{'NotMobile'} = 1;
+ }
+
unless ( _UserLoggedIn() ) {
_ForceLogout();
@@ -302,10 +307,14 @@ sub HandleRequest {
$m->out("\n$msg\n") if $msg;
$m->abort;
}
- # Specially handle /index.html so that we get a nicer URL
- elsif ( $m->request_comp->path eq '/index.html' ) {
- my $next = SetNextPage($ARGS);
- $m->comp('/NoAuth/Login.html', next => $next, actions => [$msg]);
+ # Specially handle /index.html and /m/index.html so that we get a nicer URL
+ elsif ( $m->request_comp->path =~ m{^(/m)?/index\.html$} ) {
+ my $mobile = $1 ? 1 : 0;
+ my $next = SetNextPage($ARGS);
+ $m->comp('/NoAuth/Login.html',
+ next => $next,
+ actions => [$msg],
+ mobile => $mobile);
$m->abort;
}
else {
@@ -325,7 +334,7 @@ sub HandleRequest {
ShowRequestedPage($ARGS);
LogRecordedSQLStatements(RequestData => {
- Path => $HTML::Mason::Commands::m->request_comp->path,
+ Path => $HTML::Mason::Commands::m->request_path,
});
# Process per-page final cleanup callbacks
@@ -436,6 +445,10 @@ sub TangentForLogin {
my $ARGS = shift;
my $hash = SetNextPage($ARGS);
my %query = (@_, next => $hash);
+
+ $query{mobile} = 1
+ if $HTML::Mason::Commands::m->request_comp->path =~ m{^/m(/|$)};
+
my $login = RT->Config->Get('WebURL') . 'NoAuth/Login.html?';
$login .= $HTML::Mason::Commands::m->comp('/Elements/QueryString', %query);
Redirect($login);
@@ -563,6 +576,7 @@ sub MaybeRejectPrivateComponentRequest {
/ # leading slash
( Elements |
_elements | # mobile UI
+ Callbacks |
Widgets |
autohandler | # requesting this directly is suspicious
l (_unsafe)? ) # loc component
@@ -792,7 +806,7 @@ sub LoadSessionFromCookie {
my $SessionCookie = ( $cookies{$cookiename} ? $cookies{$cookiename}->value : undef );
tie %HTML::Mason::Commands::session, 'RT::Interface::Web::Session', $SessionCookie;
unless ( $SessionCookie && $HTML::Mason::Commands::session{'_session_id'} eq $SessionCookie ) {
- undef $cookies{$cookiename};
+ InstantiateNewSession();
}
if ( int RT->Config->Get('AutoLogoff') ) {
my $now = int( time / 60 );
@@ -877,6 +891,38 @@ sub Redirect {
$HTML::Mason::Commands::m->abort;
}
+=head2 CacheControlExpiresHeaders
+
+set both Cache-Control and Expires http headers
+
+=cut
+
+sub CacheControlExpiresHeaders {
+ my %args = @_;
+
+ my $Visibility = 'private';
+ if ( ! defined $args{Time} ) {
+ $args{Time} = 0;
+ } elsif ( $args{Time} eq 'no-cache' ) {
+ $args{Time} = 0;
+ } elsif ( $args{Time} eq 'forever' ) {
+ $args{Time} = 30 * 24 * 60 * 60;
+ $Visibility = 'public';
+ }
+
+ my $CacheControl = $args{Time}
+ ? sprintf "max-age=%d, %s", $args{Time}, $Visibility
+ : 'no-cache'
+ ;
+ $HTML::Mason::Commands::r->headers_out->{'Cache-Control'} = $CacheControl;
+
+ my $expires = RT::Date->new(RT->SystemUser);
+ $expires->SetToNow;
+ $expires->AddSeconds( $args{Time} ) if $args{Time};
+
+ $HTML::Mason::Commands::r->headers_out->{'Expires'} = $expires->RFC2616;
+}
+
=head2 StaticFileHeaders
Send the browser a few headers to try to get it to (somewhat agressively)
@@ -889,16 +935,12 @@ This routine could really use _accurate_ heuristics. (XXX TODO)
sub StaticFileHeaders {
my $date = RT::Date->new(RT->SystemUser);
- # make cache public
- $HTML::Mason::Commands::r->headers_out->{'Cache-Control'} = 'max-age=259200, public';
-
# remove any cookie headers -- if it is cached publicly, it
# shouldn't include anyone's cookie!
delete $HTML::Mason::Commands::r->err_headers_out->{'Set-Cookie'};
# Expire things in a month.
- $date->Set( Value => time + 30 * 24 * 60 * 60 );
- $HTML::Mason::Commands::r->headers_out->{'Expires'} = $date->RFC2616;
+ CacheControlExpiresHeaders( Time => 'forever' );
# if we set 'Last-Modified' then browser request a comp using 'If-Modified-Since'
# request, but we don't handle it and generate full reply again
@@ -912,15 +954,15 @@ sub StaticFileHeaders {
Takes C<PATH> and returns a boolean indicating that the user-specified partial
component path is safe.
-Currently "safe" means that the path does not start with a dot (C<.>) and does
-not contain a slash-dot C</.>.
+Currently "safe" means that the path does not start with a dot (C<.>), does
+not contain a slash-dot C</.>, and does not contain any nulls.
=cut
sub ComponentPathIsSafe {
my $self = shift;
my $path = shift;
- return $path !~ m{(?:^|/)\.};
+ return $path !~ m{(?:^|/)\.} and $path !~ m{\0};
}
=head2 PathIsSafe
@@ -1187,32 +1229,31 @@ sub ValidateWebConfig {
return if $_has_validated_web_config;
$_has_validated_web_config = 1;
- if (!$ENV{'rt.explicit_port'} && $ENV{SERVER_PORT} != RT->Config->Get('WebPort')) {
- $RT::Logger->warn("The actual SERVER_PORT ($ENV{SERVER_PORT}) does NOT match the configured WebPort ($RT::WebPort). Perhaps you should Set(\$WebPort, $ENV{SERVER_PORT}); in RT_SiteConfig.pm, otherwise your internal links may be broken.");
- }
-
- if ($ENV{HTTP_HOST}) {
- # match "example.com" or "example.com:80"
- my ($host) = $ENV{HTTP_HOST} =~ /^(.*?)(:\d+)?$/;
+ my $port = $ENV{SERVER_PORT};
+ my $host = $ENV{HTTP_X_FORWARDED_HOST} || $ENV{HTTP_X_FORWARDED_SERVER}
+ || $ENV{HTTP_HOST} || $ENV{SERVER_NAME};
+ ($host, $port) = ($1, $2) if $host =~ /^(.*?):(\d+)$/;
- if ($host ne RT->Config->Get('WebDomain')) {
- $RT::Logger->warn("The actual HTTP_HOST ($host) does NOT match the configured WebDomain ($RT::WebDomain). Perhaps you should Set(\$WebDomain, '$host'); in RT_SiteConfig.pm, otherwise your internal links may be broken.");
- }
+ if ( $port != RT->Config->Get('WebPort') and not $ENV{'rt.explicit_port'}) {
+ $RT::Logger->warn("The requested port ($port) does NOT match the configured WebPort ($RT::WebPort). "
+ ."Perhaps you should Set(\$WebPort, $port); in RT_SiteConfig.pm, "
+ ."otherwise your internal links may be broken.");
}
- else {
- if ($ENV{SERVER_NAME} ne RT->Config->Get('WebDomain')) {
- $RT::Logger->warn("The actual SERVER_NAME ($ENV{SERVER_NAME}) does NOT match the configured WebDomain ($RT::WebDomain). Perhaps you should Set(\$WebDomain, '$ENV{SERVER_NAME}'); in RT_SiteConfig.pm, otherwise your internal links may be broken.");
- }
+
+ if ( $host ne RT->Config->Get('WebDomain') ) {
+ $RT::Logger->warn("The requested host ($host) does NOT match the configured WebDomain ($RT::WebDomain). "
+ ."Perhaps you should Set(\$WebDomain, '$host'); in RT_SiteConfig.pm, "
+ ."otherwise your internal links may be broken.");
}
- #i don't understand how this was ever expected to work
- # (even without our dum double // hack)??
- #if ($ENV{SCRIPT_NAME} ne RT->Config->Get('WebPath')) {
- ( my $WebPath = RT->Config->Get('WebPath') ) =~ s(/+)(/)g;
- ( my $script_name = $ENV{SCRIPT_NAME} ) =~ s(/+)(/)g;
- my $script_name_prefix = substr($script_name, 0, length($WebPath));
- if ( $script_name_prefix ne $WebPath ) {
- $RT::Logger->warn("The actual SCRIPT_NAME ($script_name) does NOT match the configured WebPath ($WebPath). Perhaps you should Set(\$WebPath, '$script_name_prefix'); in RT_SiteConfig.pm, otherwise your internal links may be broken.");
+ # Unfortunately, there is no reliable way to get the _path_ that was
+ # requested at the proxy level; simply disable this warning if we're
+ # proxied and there's a mismatch.
+ my $proxied = $ENV{HTTP_X_FORWARDED_HOST} || $ENV{HTTP_X_FORWARDED_SERVER};
+ if ($ENV{SCRIPT_NAME} ne RT->Config->Get('WebPath') and not $proxied) {
+ $RT::Logger->warn("The requested path ($ENV{SCRIPT_NAME}) does NOT match the configured WebPath ($RT::WebPath). "
+ ."Perhaps you should Set(\$WebPath, '$ENV{SCRIPT_NAME}'); in RT_SiteConfig.pm, "
+ ."otherwise your internal links may be broken.");
}
}
@@ -1286,16 +1327,18 @@ sub IsCompCSRFWhitelisted {
# record.
delete $args{id};
- # If they have a valid results= from MaybeRedirectForResults, that's
- # also fine.
- delete $args{results} if $args{results}
- and $HTML::Mason::Commands::session{"Actions"}->{$args{results}};
+ # If they have a results= from MaybeRedirectForResults, that's also fine.
+ delete $args{results};
# The homepage refresh, which uses the Refresh header, doesn't send
# a referer in most browsers; whitelist the one parameter it reloads
# with, HomeRefreshInterval, which is safe
delete $args{HomeRefreshInterval};
+ # The NotMobile flag is fine for any page; it's only used to toggle a flag
+ # in the session related to which interface you get.
+ delete $args{NotMobile};
+
# If there are no arguments, then it's likely to be an idempotent
# request, which are not susceptible to CSRF
return 1 if !%args;
@@ -1711,6 +1754,7 @@ sub CreateTicket {
Cc => $ARGS{'Cc'},
Body => $sigless,
Type => $ARGS{'ContentType'},
+ Interface => RT::Interface::Web::MobileClient() ? 'Mobile' : 'Web',
);
if ( $ARGS{'Attachments'} ) {
@@ -1929,6 +1973,7 @@ sub ProcessUpdateMessage {
Subject => $args{ARGSRef}->{'UpdateSubject'},
Body => $args{ARGSRef}->{'UpdateContent'},
Type => $args{ARGSRef}->{'UpdateContentType'},
+ Interface => RT::Interface::Web::MobileClient() ? 'Mobile' : 'Web',
);
$Message->head->replace( 'Message-ID' => Encode::encode_utf8(
@@ -2067,11 +2112,13 @@ sub MakeMIMEEntity {
Body => undef,
AttachmentFieldName => undef,
Type => undef,
+ Interface => 'API',
@_,
);
my $Message = MIME::Entity->build(
Type => 'multipart/mixed',
"Message-Id" => Encode::encode_utf8( RT::Interface::Email::GenMessageId ),
+ "X-RT-Interface" => $args{Interface},
map { $_ => Encode::encode_utf8( $args{ $_} ) }
grep defined $args{$_}, qw(Subject From Cc)
);
@@ -2113,8 +2160,9 @@ sub MakeMIMEEntity {
$Message->head->set( 'Subject' => $filename );
}
- # Attachment parts really shouldn't get a Message-ID
+ # Attachment parts really shouldn't get a Message-ID or "interface"
$Message->head->delete('Message-ID');
+ $Message->head->delete('X-RT-Interface');
}
}
@@ -2126,6 +2174,37 @@ sub MakeMIMEEntity {
}
+sub ProcessAttachments {
+ my %args = (
+ ARGSRef => {},
+ @_
+ );
+
+ my $ARGSRef = $args{ARGSRef} || {};
+ # deal with deleting uploaded attachments
+ foreach my $key ( keys %$ARGSRef ) {
+ if ( $key =~ m/^DeleteAttach-(.+)$/ ) {
+ delete $session{'Attachments'}{$1};
+ }
+ $session{'Attachments'} = { %{ $session{'Attachments'} || {} } };
+ }
+
+ # store the uploaded attachment in session
+ if ( defined $ARGSRef->{'Attach'} && length $ARGSRef->{'Attach'} )
+ { # attachment?
+ my $attachment = MakeMIMEEntity( AttachmentFieldName => 'Attach' );
+
+ my $file_path = Encode::decode_utf8("$ARGSRef->{'Attach'}");
+ $session{'Attachments'} =
+ { %{ $session{'Attachments'} || {} }, $file_path => $attachment, };
+ }
+
+ # delete temporary storage entry to make WebUI clean
+ unless ( keys %{ $session{'Attachments'} } and $ARGSRef->{'UpdateAttach'} )
+ {
+ delete $session{'Attachments'};
+ }
+}
=head2 ParseDateToISO
@@ -2220,19 +2299,8 @@ sub ProcessACLs {
# Check if we want to grant rights to a previously rights-less user
for my $type (qw(user group)) {
- my $key = "AddPrincipalForRights-$type";
-
- next unless $ARGSref->{$key};
-
- my $principal;
- if ( $type eq 'user' ) {
- $principal = RT::User->new( $session{'CurrentUser'} );
- $principal->LoadByCol( Name => $ARGSref->{$key} );
- }
- else {
- $principal = RT::Group->new( $session{'CurrentUser'} );
- $principal->LoadUserDefinedGroup( $ARGSref->{$key} );
- }
+ my $principal = _ParseACLNewPrincipal($ARGSref, $type)
+ or next;
unless ($principal->PrincipalId) {
push @results, loc("Couldn't load the specified principal");
@@ -2332,7 +2400,34 @@ sub ProcessACLs {
return (@results);
}
+=head2 _ParseACLNewPrincipal
+
+Takes a hashref of C<%ARGS> and a principal type (C<user> or C<group>). Looks
+for the presence of rights being added on a principal of the specified type,
+and returns undef if no new principal is being granted rights. Otherwise loads
+up an L<RT::User> or L<RT::Group> object and returns it. Note that the object
+may not be successfully loaded, and you should check C<->id> yourself.
+
+=cut
+
+sub _ParseACLNewPrincipal {
+ my $ARGSref = shift;
+ my $type = lc shift;
+ my $key = "AddPrincipalForRights-$type";
+
+ return unless $ARGSref->{$key};
+ my $principal;
+ if ( $type eq 'user' ) {
+ $principal = RT::User->new( $session{'CurrentUser'} );
+ $principal->LoadByCol( Name => $ARGSref->{$key} );
+ }
+ elsif ( $type eq 'group' ) {
+ $principal = RT::Group->new( $session{'CurrentUser'} );
+ $principal->LoadUserDefinedGroup( $ARGSref->{$key} );
+ }
+ return $principal;
+}
=head2 UpdateRecordObj ( ARGSRef => \%ARGS, Object => RT::Record, AttributesRef => \@attribs)
@@ -2542,12 +2637,17 @@ sub ProcessTicketReminders {
Format => 'unknown',
Value => $args->{'NewReminder-Due'}
);
- my ( $add_id, $msg, $txnid ) = $Ticket->Reminders->Add(
+ my ( $add_id, $msg ) = $Ticket->Reminders->Add(
Subject => $args->{'NewReminder-Subject'},
Owner => $args->{'NewReminder-Owner'},
Due => $due_obj->ISO
);
- push @results, loc("Reminder '[_1]' added", $args->{'NewReminder-Subject'});
+ if ( $add_id ) {
+ push @results, loc("Reminder '[_1]' added", $args->{'NewReminder-Subject'});
+ }
+ else {
+ push @results, $msg;
+ }
}
return @results;
}
@@ -3010,6 +3110,24 @@ sub ProcessRecordLinks {
return (@results);
}
+=head2 ProcessTransactionSquelching
+
+Takes a hashref of the submitted form arguments, C<%ARGS>.
+
+Returns a hash of squelched addresses.
+
+=cut
+
+sub ProcessTransactionSquelching {
+ my $args = shift;
+ my %checked = map { $_ => 1 } grep { defined }
+ ( ref $args->{'TxnSendMailTo'} eq "ARRAY" ? @{$args->{'TxnSendMailTo'}} :
+ defined $args->{'TxnSendMailTo'} ? ($args->{'TxnSendMailTo'}) :
+ () );
+ my %squelched = map { $_ => 1 } grep { not $checked{$_} } split /,/, ($args->{'TxnRecipients'}||'');
+ return %squelched;
+}
+
=head2 _UploadedFile ( $arg );
Takes a CGI parameter name; if a file is uploaded under that name,
@@ -3235,9 +3353,9 @@ our @SCRUBBER_ALLOWED_TAGS = qw(
);
our %SCRUBBER_ALLOWED_ATTRIBUTES = (
- # Match http, ftp and relative urls
+ # Match http, https, ftp, mailto and relative urls
# XXX: we also scrub format strings with this module then allow simple config options
- href => qr{^(?:http:|ftp:|https:|/|__Web(?:Path|BaseURL|URL)__)}i,
+ href => qr{^(?:https?:|ftp:|mailto:|/|__Web(?:Path|BaseURL|URL)__)}i,
face => 1,
size => 1,
target => 1,
diff --git a/rt/lib/RT/Interface/Web/Handler.pm b/rt/lib/RT/Interface/Web/Handler.pm
index a740167c6..a1784c2cc 100644
--- a/rt/lib/RT/Interface/Web/Handler.pm
+++ b/rt/lib/RT/Interface/Web/Handler.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -205,10 +205,44 @@ sub CleanupRequest {
sub HTML::Mason::Exception::as_rt_error {
my ($self) = @_;
- $RT::Logger->error( $self->full_message );
+ $RT::Logger->error( $self->as_text );
return "An internal RT error has occurred. Your administrator can find more details in RT's log files.";
}
+=head1 CheckModPerlHandler
+
+Make sure we're not running with SetHandler perl-script.
+
+=cut
+
+sub CheckModPerlHandler{
+ my $self = shift;
+ my $env = shift;
+
+ # Plack::Handler::Apache2 masks MOD_PERL, so use MOD_PERL_API_VERSION
+ return unless( $env->{'MOD_PERL_API_VERSION'}
+ and $env->{'MOD_PERL_API_VERSION'} == 2);
+
+ my $handler = $env->{'psgi.input'}->handler;
+
+ return unless defined $handler && $handler eq 'perl-script';
+
+ $RT::Logger->critical(<<MODPERL);
+RT has problems when SetHandler is set to perl-script.
+Change SetHandler in your in httpd.conf to:
+
+ SetHandler modperl
+
+For a complete example mod_perl configuration, see:
+
+https://bestpractical.com/rt/docs/@{[$RT::VERSION =~ /^(\d\.\d)/]}/web_deployment.html#mod_perl-2.xx
+MODPERL
+
+ my $res = Plack::Response->new(500);
+ $res->content_type("text/plain");
+ $res->body("Server misconfiguration; see error log for details");
+ return $res;
+}
# PSGI App
@@ -231,6 +265,12 @@ sub PSGIApp {
return sub {
my $env = shift;
+
+ {
+ my $res = $self->CheckModPerlHandler($env);
+ return $self->_psgi_response_cb( $res->finalize ) if $res;
+ }
+
RT::ConnectToDatabase() unless RT->InstallMode;
my $req = Plack::Request->new($env);
diff --git a/rt/lib/RT/Interface/Web/Menu.pm b/rt/lib/RT/Interface/Web/Menu.pm
index 045df1fa0..e4e08d63b 100644
--- a/rt/lib/RT/Interface/Web/Menu.pm
+++ b/rt/lib/RT/Interface/Web/Menu.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -314,4 +314,59 @@ sub children {
return wantarray ? @kids : \@kids;
}
+=head2 add_after
+
+Called on a child, inserts a new menu item after it and shifts any other
+menu items at this level to the right.
+
+L<child> by default would insert at the end of the list of children, unless you
+did manual sort_order calculations.
+
+Takes all the regular arguments to L<child>.
+
+=cut
+
+sub add_after { shift->_insert_sibling("after", @_) }
+
+=head2 add_before
+
+Called on a child, inserts a new menu item at the child's location and shifts
+the child and the other menu items at this level to the right.
+
+L<child> by default would insert at the end of the list of children, unless you
+did manual sort_order calculations.
+
+Takes all the regular arguments to L<child>.
+
+=cut
+
+sub add_before { shift->_insert_sibling("before", @_) }
+
+sub _insert_sibling {
+ my $self = shift;
+ my $where = shift;
+ my $parent = $self->parent;
+ my $sort_order;
+ for my $contemporary ($parent->children) {
+ if ( $contemporary->key eq $self->key ) {
+ if ($where eq "before") {
+ # Bump the current child and the following
+ $sort_order = $contemporary->sort_order;
+ }
+ elsif ($where eq "after") {
+ # Leave the current child along, bump the rest
+ $sort_order = $contemporary->sort_order + 1;
+ next;
+ }
+ else {
+ # never set $sort_order, act no differently than ->child()
+ }
+ }
+ if ( $sort_order ) {
+ $contemporary->sort_order( $contemporary->sort_order + 1 );
+ }
+ }
+ $parent->child( @_, sort_order => $sort_order );
+}
+
1;
diff --git a/rt/lib/RT/Interface/Web/QueryBuilder.pm b/rt/lib/RT/Interface/Web/QueryBuilder.pm
index 79a0b9718..546427833 100755
--- a/rt/lib/RT/Interface/Web/QueryBuilder.pm
+++ b/rt/lib/RT/Interface/Web/QueryBuilder.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm b/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm
index 2cfc88998..9bbd876e5 100755
--- a/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm
+++ b/rt/lib/RT/Interface/Web/QueryBuilder/Tree.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Interface/Web/Request.pm b/rt/lib/RT/Interface/Web/Request.pm
index d0865117d..cdd4594d6 100644
--- a/rt/lib/RT/Interface/Web/Request.pm
+++ b/rt/lib/RT/Interface/Web/Request.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -142,6 +142,10 @@ sub callback {
}
return @rv;
}
+
+sub clear_callback_cache {
+ %cache = %called = ();
+}
}
=head2 request_path
@@ -165,4 +169,21 @@ sub request_path {
return $path;
}
+=head2 abort
+
+Logs any recorded SQL statements for this request before calling the standard
+abort.
+
+=cut
+
+sub abort {
+ my $self = shift;
+ RT::Interface::Web::LogRecordedSQLStatements(
+ RequestData => {
+ Path => $self->request_path,
+ },
+ );
+ return $self->SUPER::abort(@_);
+}
+
1;
diff --git a/rt/lib/RT/Interface/Web/Session.pm b/rt/lib/RT/Interface/Web/Session.pm
index c5b88f127..4edd9bd2e 100644
--- a/rt/lib/RT/Interface/Web/Session.pm
+++ b/rt/lib/RT/Interface/Web/Session.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -207,8 +207,8 @@ sub _ClearOldDir {
foreach my $id( @{ $self->Ids } ) {
if( int $older_than ) {
- my $ctime = (stat(File::Spec->catfile($dir,$id)))[9];
- if( $ctime > $now - $older_than ) {
+ my $mtime = (stat(File::Spec->catfile($dir,$id)))[9];
+ if( $mtime > $now - $older_than ) {
$RT::Logger->debug("skipped session '$id', isn't old");
next;
}
@@ -224,6 +224,10 @@ sub _ClearOldDir {
tied(%session)->delete;
$RT::Logger->info("successfuly deleted session '$id'");
}
+
+ my $lock = Apache::Session::Lock::File->new;
+ $lock->clean( $dir, $older_than );
+
return;
}
diff --git a/rt/lib/RT/Lifecycle.pm b/rt/lib/RT/Lifecycle.pm
index 056599edb..c90528258 100644
--- a/rt/lib/RT/Lifecycle.pm
+++ b/rt/lib/RT/Lifecycle.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -411,8 +411,8 @@ sub Transitions {
return %{ $self->{'data'}{'transitions'} || {} }
unless @_;
- my $status = shift;
- return @{ $self->{'data'}{'transitions'}{ $status || '' } || [] };
+ my $status = shift || '';
+ return @{ $self->{'data'}{'transitions'}{ lc $status } || [] };
}
=head1 IsTransition
@@ -439,8 +439,8 @@ be checked on the ticket.
sub CheckRight {
my $self = shift;
- my $from = shift;
- my $to = shift;
+ my $from = lc shift;
+ my $to = lc shift;
if ( my $rights = $self->{'data'}{'rights'} ) {
my $check =
$rights->{ $from .' -> '. $to }
@@ -536,10 +536,11 @@ pairs:
sub Actions {
my $self = shift;
my $from = shift || return ();
+ $from = lc $from;
$self->FillCache unless keys %LIFECYCLES_CACHE;
- my @res = grep $_->{'from'} eq $from || ( $_->{'from'} eq '*' && $_->{'to'} ne $from ),
+ my @res = grep lc $_->{'from'} eq $from || ( $_->{'from'} eq '*' && lc $_->{'to'} ne $from ),
@{ $self->{'data'}{'actions'} };
# skip '* -> x' if there is '$from -> x'
@@ -633,6 +634,13 @@ sub ForLocalization {
sub loc { return RT->SystemUser->loc( @_ ) }
+sub CanonicalCase {
+ my $self = shift;
+ my ($status) = @_;
+ return undef unless defined $status;
+ return($self->{data}{canonical_case}{lc $status} || lc $status);
+}
+
sub FillCache {
my $self = shift;
@@ -647,45 +655,123 @@ sub FillCache {
active => [],
inactive => [],
);
- foreach my $lifecycle ( values %LIFECYCLES_CACHE ) {
- my @res;
+ foreach my $name ( keys %LIFECYCLES_CACHE ) {
+ next if $name eq "__maps__";
+ my $lifecycle = $LIFECYCLES_CACHE{$name};
+
+ my @statuses;
+ $lifecycle->{canonical_case} = {};
foreach my $type ( qw(initial active inactive) ) {
- push @{ $all{ $type } }, @{ $lifecycle->{ $type } || [] };
- push @res, @{ $lifecycle->{ $type } || [] };
+ for my $status (@{ $lifecycle->{ $type } || [] }) {
+ if (exists $lifecycle->{canonical_case}{lc $status}) {
+ warn "Duplicate status @{[lc $status]} in lifecycle $name";
+ } else {
+ $lifecycle->{canonical_case}{lc $status} = $status;
+ }
+ push @{ $all{ $type } }, $status;
+ push @statuses, $status;
+ }
+ }
+
+ # Lower-case for consistency
+ # ->{actions} are handled below
+ for my $state (keys %{ $lifecycle->{defaults} || {} }) {
+ my $status = $lifecycle->{defaults}{$state};
+ warn "Nonexistant status @{[lc $status]} in default states in $name lifecycle"
+ unless $lifecycle->{canonical_case}{lc $status};
+ $lifecycle->{defaults}{$state} =
+ $lifecycle->{canonical_case}{lc $status} || lc $status;
+ }
+ for my $from (keys %{ $lifecycle->{transitions} || {} }) {
+ warn "Nonexistant status @{[lc $from]} in transitions in $name lifecycle"
+ unless $from eq '' or $lifecycle->{canonical_case}{lc $from};
+ for my $status ( @{delete($lifecycle->{transitions}{$from}) || []} ) {
+ warn "Nonexistant status @{[lc $status]} in transitions in $name lifecycle"
+ unless $lifecycle->{canonical_case}{lc $status};
+ push @{ $lifecycle->{transitions}{lc $from} },
+ $lifecycle->{canonical_case}{lc $status} || lc $status;
+ }
+ }
+ for my $schema (keys %{ $lifecycle->{rights} || {} }) {
+ my ($from, $to) = split /\s*->\s*/, $schema, 2;
+ unless ($from and $to) {
+ warn "Invalid right transition $schema in $name lifecycle";
+ next;
+ }
+ warn "Nonexistant status @{[lc $from]} in right transition in $name lifecycle"
+ unless $from eq '*' or $lifecycle->{canonical_case}{lc $from};
+ warn "Nonexistant status @{[lc $to]} in right transition in $name lifecycle"
+ unless $to eq '*' or $lifecycle->{canonical_case}{lc $to};
+ $lifecycle->{rights}{lc($from) . " -> " .lc($to)}
+ = delete $lifecycle->{rights}{$schema};
}
my %seen;
- @res = grep !$seen{ lc $_ }++, @res;
- $lifecycle->{''} = \@res;
+ @statuses = grep !$seen{ $_ }++, @statuses;
+ $lifecycle->{''} = \@statuses;
unless ( $lifecycle->{'transitions'}{''} ) {
- $lifecycle->{'transitions'}{''} = [ grep $_ ne 'deleted', @res ];
+ $lifecycle->{'transitions'}{''} = [ grep $_ ne 'deleted', @statuses ];
}
- }
- foreach my $type ( qw(initial active inactive), '' ) {
- my %seen;
- @{ $all{ $type } } = grep !$seen{ lc $_ }++, @{ $all{ $type } };
- push @{ $all{''} }, @{ $all{ $type } } if $type;
- }
- $LIFECYCLES_CACHE{''} = \%all;
- foreach my $lifecycle ( values %LIFECYCLES_CACHE ) {
- my @res;
+ my @actions;
if ( ref $lifecycle->{'actions'} eq 'HASH' ) {
foreach my $k ( sort keys %{ $lifecycle->{'actions'} } ) {
- push @res, $k, $lifecycle->{'actions'}{ $k };
+ push @actions, $k, $lifecycle->{'actions'}{ $k };
}
} elsif ( ref $lifecycle->{'actions'} eq 'ARRAY' ) {
- @res = @{ $lifecycle->{'actions'} };
+ @actions = @{ $lifecycle->{'actions'} };
}
- my @tmp = splice @res;
- while ( my ($transition, $info) = splice @tmp, 0, 2 ) {
+ $lifecycle->{'actions'} = [];
+ while ( my ($transition, $info) = splice @actions, 0, 2 ) {
my ($from, $to) = split /\s*->\s*/, $transition, 2;
- push @res, { %$info, from => $from, to => $to };
+ unless ($from and $to) {
+ warn "Invalid action status change $transition in $name lifecycle";
+ next;
+ }
+ warn "Nonexistant status @{[lc $from]} in action in $name lifecycle"
+ unless $from eq '*' or $lifecycle->{canonical_case}{lc $from};
+ warn "Nonexistant status @{[lc $to]} in action in $name lifecycle"
+ unless $to eq '*' or $lifecycle->{canonical_case}{lc $to};
+ push @{ $lifecycle->{'actions'} },
+ { %$info,
+ from => ($lifecycle->{canonical_case}{lc $from} || lc $from),
+ to => ($lifecycle->{canonical_case}{lc $to} || lc $to), };
}
- $lifecycle->{'actions'} = \@res;
}
+
+ # Lower-case the transition maps
+ for my $mapname (keys %{ $LIFECYCLES_CACHE{'__maps__'} || {} }) {
+ my ($from, $to) = split /\s*->\s*/, $mapname, 2;
+ unless ($from and $to) {
+ warn "Invalid lifecycle mapping $mapname";
+ next;
+ }
+ warn "Nonexistant lifecycle $from in $mapname lifecycle map"
+ unless $LIFECYCLES_CACHE{$from};
+ warn "Nonexistant lifecycle $to in $mapname lifecycle map"
+ unless $LIFECYCLES_CACHE{$to};
+ my $map = delete $LIFECYCLES_CACHE{'__maps__'}{$mapname};
+ $LIFECYCLES_CACHE{'__maps__'}{"$from -> $to"} = $map;
+ for my $status (keys %{ $map }) {
+ warn "Nonexistant status @{[lc $status]} in $from in $mapname lifecycle map"
+ if $LIFECYCLES_CACHE{$from}
+ and not $LIFECYCLES_CACHE{$from}{canonical_case}{lc $status};
+ warn "Nonexistant status @{[lc $map->{$status}]} in $to in $mapname lifecycle map"
+ if $LIFECYCLES_CACHE{$to}
+ and not $LIFECYCLES_CACHE{$to}{canonical_case}{lc $map->{$status}};
+ $map->{lc $status} = lc delete $map->{$status};
+ }
+ }
+
+ foreach my $type ( qw(initial active inactive), '' ) {
+ my %seen;
+ @{ $all{ $type } } = grep !$seen{ $_ }++, @{ $all{ $type } };
+ push @{ $all{''} }, @{ $all{ $type } } if $type;
+ }
+ $LIFECYCLES_CACHE{''} = \%all;
+
return;
}
diff --git a/rt/lib/RT/Link.pm b/rt/lib/RT/Link.pm
index b26f5643c..7a277473f 100644
--- a/rt/lib/RT/Link.pm
+++ b/rt/lib/RT/Link.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -96,33 +96,17 @@ sub Create {
@_ );
my $base = RT::URI->new( $self->CurrentUser );
- $base->FromURI( $args{'Base'} );
-
- unless ( $base->Resolver && $base->Scheme ) {
- my $msg = $self->loc("Couldn't resolve base '[_1]' into a URI.",
- $args{'Base'});
+ unless ($base->FromURI( $args{'Base'} )) {
+ my $msg = $self->loc("Couldn't resolve base '[_1]' into a URI.", $args{'Base'});
$RT::Logger->warning( "$self $msg" );
-
- if (wantarray) {
- return(undef, $msg);
- } else {
- return (undef);
- }
+ return wantarray ? (undef, $msg) : undef;
}
my $target = RT::URI->new( $self->CurrentUser );
- $target->FromURI( $args{'Target'} );
-
- unless ( $target->Resolver ) {
- my $msg = $self->loc("Couldn't resolve target '[_1]' into a URI.",
- $args{'Target'});
+ unless ($target->FromURI( $args{'Target'} )) {
+ my $msg = $self->loc("Couldn't resolve target '[_1]' into a URI.", $args{'Target'});
$RT::Logger->warning( "$self $msg" );
-
- if (wantarray) {
- return(undef, $msg);
- } else {
- return (undef);
- }
+ return wantarray ? (undef, $msg) : undef;
}
my $base_id = 0;
@@ -186,22 +170,21 @@ sub LoadByParams {
@_ );
my $base = RT::URI->new($self->CurrentUser);
- $base->FromURI( $args{'Base'} );
+ $base->FromURI( $args{'Base'} )
+ or return (0, $self->loc("Couldn't parse Base URI: [_1]", $args{Base}));
my $target = RT::URI->new($self->CurrentUser);
- $target->FromURI( $args{'Target'} );
-
- unless ($base->Resolver && $target->Resolver) {
- return ( 0, $self->loc("Couldn't load link") );
- }
-
+ $target->FromURI( $args{'Target'} )
+ or return (0, $self->loc("Couldn't parse Target URI: [_1]", $args{Target}));
my ( $id, $msg ) = $self->LoadByCols( Base => $base->URI,
Type => $args{'Type'},
Target => $target->URI );
unless ($id) {
- return ( 0, $self->loc("Couldn't load link") );
+ return ( 0, $self->loc("Couldn't load link: [_1]", $msg) );
+ } else {
+ return ($id, $msg);
}
}
diff --git a/rt/lib/RT/Links.pm b/rt/lib/RT/Links.pm
index ccc72d749..af36a5bdc 100644
--- a/rt/lib/RT/Links.pm
+++ b/rt/lib/RT/Links.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/ObjectClass.pm b/rt/lib/RT/ObjectClass.pm
index e1c66da0f..684af132d 100644
--- a/rt/lib/RT/ObjectClass.pm
+++ b/rt/lib/RT/ObjectClass.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/ObjectClasses.pm b/rt/lib/RT/ObjectClasses.pm
index ac95adef5..01cf77f8e 100644
--- a/rt/lib/RT/ObjectClasses.pm
+++ b/rt/lib/RT/ObjectClasses.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/ObjectCustomField.pm b/rt/lib/RT/ObjectCustomField.pm
index 61bc35532..e7f350a5a 100644
--- a/rt/lib/RT/ObjectCustomField.pm
+++ b/rt/lib/RT/ObjectCustomField.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/ObjectCustomFieldValue.pm b/rt/lib/RT/ObjectCustomFieldValue.pm
index 98714a048..63da581ce 100644
--- a/rt/lib/RT/ObjectCustomFieldValue.pm
+++ b/rt/lib/RT/ObjectCustomFieldValue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/ObjectCustomFieldValues.pm b/rt/lib/RT/ObjectCustomFieldValues.pm
index dad4a6917..a1d5391f8 100644
--- a/rt/lib/RT/ObjectCustomFieldValues.pm
+++ b/rt/lib/RT/ObjectCustomFieldValues.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -139,7 +139,7 @@ sub _DoSearch {
my $self = shift;
# unless we really want to find disabled rows,
- # make sure we\'re only finding enabled ones.
+ # make sure we're only finding enabled ones.
unless ( $self->{'find_expired_rows'} ) {
$self->LimitToEnabled();
}
@@ -151,7 +151,7 @@ sub _DoCount {
my $self = shift;
# unless we really want to find disabled rows,
- # make sure we\'re only finding enabled ones.
+ # make sure we're only finding enabled ones.
unless ( $self->{'find_expired_rows'} ) {
$self->LimitToEnabled();
}
diff --git a/rt/lib/RT/ObjectCustomFields.pm b/rt/lib/RT/ObjectCustomFields.pm
index 98649498f..5bdc069ba 100644
--- a/rt/lib/RT/ObjectCustomFields.pm
+++ b/rt/lib/RT/ObjectCustomFields.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/ObjectTopic.pm b/rt/lib/RT/ObjectTopic.pm
index ae5abb35c..8ca01ae9d 100644
--- a/rt/lib/RT/ObjectTopic.pm
+++ b/rt/lib/RT/ObjectTopic.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -46,18 +46,10 @@
#
# END BPS TAGGED BLOCK }}}
-# Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
-# WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.
-#
-# !! DO NOT EDIT THIS FILE !!
-#
-
-
=head1 NAME
RT::ObjectTopic
-
=head1 SYNOPSIS
=head1 DESCRIPTION
@@ -66,8 +58,11 @@ RT::ObjectTopic
=cut
-no warnings 'redefine';
package RT::ObjectTopic;
+use strict;
+use warnings;
+no warnings 'redefine';
+
use RT::Record;
use RT::Topic;
diff --git a/rt/lib/RT/ObjectTopics.pm b/rt/lib/RT/ObjectTopics.pm
index 1ffb146b5..bdcff7755 100644
--- a/rt/lib/RT/ObjectTopics.pm
+++ b/rt/lib/RT/ObjectTopics.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Plugin.pm b/rt/lib/RT/Plugin.pm
index 10eb83797..1f97ec22d 100644
--- a/rt/lib/RT/Plugin.pm
+++ b/rt/lib/RT/Plugin.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Pod/HTML.pm b/rt/lib/RT/Pod/HTML.pm
index 8ddce42d1..689606323 100644
--- a/rt/lib/RT/Pod/HTML.pm
+++ b/rt/lib/RT/Pod/HTML.pm
@@ -1,9 +1,59 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
+# <sales@bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+
use strict;
use warnings;
package RT::Pod::HTML;
use base 'Pod::Simple::XHTML';
+use HTML::Entities qw//;
+
sub new {
my $self = shift->SUPER::new(@_);
$self->index(1);
@@ -11,6 +61,11 @@ sub new {
return $self;
}
+sub decode_entities {
+ my $self = shift;
+ return HTML::Entities::decode_entities($_[0]);
+}
+
sub perldoc_url_prefix { "http://metacpan.org/module/" }
sub html_header { '' }
@@ -20,8 +75,22 @@ sub html_footer {
return '<a href="./' . $toc . '">&larr; Back to index</a>';
}
-sub start_Verbatim { $_[0]{'scratch'} = "<pre>" }
-sub end_Verbatim { $_[0]{'scratch'} .= "</pre>"; $_[0]->emit; }
+sub start_F {
+ $_[0]{'scratch_F'} = $_[0]{'scratch'};
+ $_[0]{'scratch'} = "";
+}
+sub end_F {
+ my $self = shift;
+ my $text = $self->{scratch};
+ my $file = $self->decode_entities($text);
+
+ if (my $local = $self->resolve_local_link($file)) {
+ $text = qq[<a href="$local">$text</a>];
+ }
+
+ $self->{'scratch'} = delete $self->{scratch_F};
+ $self->{'scratch'} .= "<i>$text</i>";
+}
sub _end_head {
my $self = shift;
@@ -38,6 +107,17 @@ sub resolve_pod_page_link {
return $self->SUPER::resolve_pod_page_link(@_)
unless $self->batch_mode and $name;
+ my $local = $self->resolve_local_link($name, $section);
+
+ return $local
+ ? $local
+ : $self->SUPER::resolve_pod_page_link(@_);
+}
+
+sub resolve_local_link {
+ my $self = shift;
+ my ($name, $section) = @_;
+
$section = defined $section
? '#' . $self->idify($section, 1)
: '';
@@ -48,18 +128,28 @@ sub resolve_pod_page_link {
map { $self->encode_entities($_) }
split /::/, $name;
}
- elsif ($name =~ /^rt-/) {
+ elsif ($name =~ /^rt[-_]/) {
$local = $self->encode_entities($name);
}
+ elsif ($name eq "RT_Config" or $name eq "RT_Config.pm") {
+ $local = "RT_Config";
+ }
+ # These matches handle links that look like filenames, such as those we
+ # parse out of F<> tags.
+ elsif ( $name =~ m{^(?:lib/)(RT/[\w/]+?)\.pm$}
+ or $name =~ m{^(?:docs/)(.+?)\.pod$})
+ {
+ $local = join "/",
+ map { $self->encode_entities($_) }
+ split /\//, $1;
+ }
if ($local) {
# Resolve links correctly by going up
my $depth = $self->batch_mode_current_level - 1;
- return join "/",
- ($depth ? ".." x $depth : ()),
- "$local.html$section";
+ return ($depth ? "../" x $depth : "") . "$local.html$section";
} else {
- return $self->SUPER::resolve_pod_page_link(@_)
+ return;
}
}
diff --git a/rt/lib/RT/Pod/HTMLBatch.pm b/rt/lib/RT/Pod/HTMLBatch.pm
index 8d1b67f34..f41a43acb 100644
--- a/rt/lib/RT/Pod/HTMLBatch.pm
+++ b/rt/lib/RT/Pod/HTMLBatch.pm
@@ -1,3 +1,51 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
+# <sales@bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+
use strict;
use warnings;
diff --git a/rt/lib/RT/Pod/Search.pm b/rt/lib/RT/Pod/Search.pm
index d6ddd2daf..29e7d437c 100644
--- a/rt/lib/RT/Pod/Search.pm
+++ b/rt/lib/RT/Pod/Search.pm
@@ -1,3 +1,51 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
+# <sales@bestpractical.com>
+#
+# (Except where explicitly superseded by other copyright notices)
+#
+#
+# LICENSE:
+#
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+#
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+#
+#
+# CONTRIBUTION SUBMISSION POLICY:
+#
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+#
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+#
+# END BPS TAGGED BLOCK }}}
+
use strict;
use warnings;
diff --git a/rt/lib/RT/Principal.pm b/rt/lib/RT/Principal.pm
index 0ee03f112..175f1b003 100644
--- a/rt/lib/RT/Principal.pm
+++ b/rt/lib/RT/Principal.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Principals.pm b/rt/lib/RT/Principals.pm
index 69e49ef15..9cf8cbb39 100644
--- a/rt/lib/RT/Principals.pm
+++ b/rt/lib/RT/Principals.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Queue.pm b/rt/lib/RT/Queue.pm
index a942bb6d7..ee68b8195 100755
--- a/rt/lib/RT/Queue.pm
+++ b/rt/lib/RT/Queue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -263,14 +263,10 @@ sub Lifecycle {
sub SetLifecycle {
my $self = shift;
- my $value = shift;
+ my $value = shift || 'default';
- if ( $value && $value ne 'default' ) {
- return (0, $self->loc('[_1] is not valid lifecycle', $value ))
- unless $self->ValidateLifecycle( $value );
- } else {
- $value = undef;
- }
+ return ( 0, $self->loc( '[_1] is not a valid lifecycle', $value ) )
+ unless $self->ValidateLifecycle($value);
return $self->_Set( Field => 'Lifecycle', Value => $value, @_ );
}
@@ -410,12 +406,10 @@ sub Create {
return ($val, $msg) unless $val;
}
- if ( $args{'Lifecycle'} && $args{'Lifecycle'} ne 'default' ) {
- return ( 0, $self->loc('Invalid lifecycle name') )
- unless $self->ValidateLifecycle( $args{'Lifecycle'} );
- } else {
- $args{'Lifecycle'} = undef;
- }
+ $args{'Lifecycle'} ||= 'default';
+
+ return ( 0, $self->loc('[_1] is not a valid lifecycle', $args{'Lifecycle'} ) )
+ unless $self->ValidateLifecycle( $args{'Lifecycle'} );
my %attrs = map {$_ => 1} $self->ReadableAttributes;
@@ -871,7 +865,7 @@ PrinicpalId The RT::Principal id of the user or group that's being added as a wa
Email The email address of the new watcher. If a user with this
email address can't be found, a new nonprivileged user will be created.
-If the watcher you\'re trying to set has an RT account, set the Owner parameter to their User Id. Otherwise, set the Email parameter to their Email address.
+If the watcher you're trying to set has an RT account, set the Owner parameter to their User Id. Otherwise, set the Email parameter to their Email address.
Returns a tuple of (status/id, message).
@@ -971,7 +965,8 @@ sub _AddWatcher {
if ( $group->HasMember( $principal)) {
- return ( 0, $self->loc('That principal is already a [_1] for this queue', $args{'Type'}) );
+ return ( 0, $self->loc('[_1] is already a [_2] for this queue',
+ $principal->Object->Name, $args{'Type'}) );
}
@@ -979,7 +974,8 @@ sub _AddWatcher {
unless ($m_id) {
$RT::Logger->error("Failed to add ".$principal->Id." as a member of group ".$group->Id.": ".$m_msg);
- return ( 0, $self->loc('Could not make that principal a [_1] for this queue', $args{'Type'}) );
+ return ( 0, $self->loc('Could not make [_1] a [_2] for this queue',
+ $principal->Object->Name, $args{'Type'}) );
}
return ( 1, $self->loc("Added [_1] to members of [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
}
@@ -1051,8 +1047,8 @@ sub DeleteWatcher {
# see if this user is already a watcher.
unless ( $group->HasMember($principal)) {
- return ( 0,
- $self->loc('That principal is not a [_1] for this queue', $args{'Type'}) );
+ return ( 0, $self->loc('[_1] is not a [_2] for this queue',
+ $principal->Object->Name, $args{'Type'}) );
}
my ($m_id, $m_msg) = $group->_DeleteMember($principal->Id);
@@ -1060,7 +1056,8 @@ sub DeleteWatcher {
$RT::Logger->error("Failed to delete ".$principal->Id.
" as a member of group ".$group->Id.": ".$m_msg);
- return ( 0, $self->loc('Could not remove that principal as a [_1] for this queue', $args{'Type'}) );
+ return ( 0, $self->loc('Could not remove [_1] as a [_2] for this queue',
+ $principal->Object->Name, $args{'Type'}) );
}
return ( 1, $self->loc("Removed [_1] from members of [_2] for this queue.", $principal->Object->Name, $args{'Type'} ));
@@ -1236,6 +1233,7 @@ sub _Set {
unless ( $self->CurrentUserHasRight('AdminQueue') ) {
return ( 0, $self->loc('Permission Denied') );
}
+ RT->System->QueueCacheNeedsUpdate(1);
return ( $self->SUPER::_Set(@_) );
}
@@ -1560,7 +1558,7 @@ sub _CoreAccessible {
SubjectTag =>
{read => 1, write => 1, sql_type => 12, length => 120, is_blob => 0, is_numeric => 0, type => 'varchar(120)', default => ''},
Lifecycle =>
- {read => 1, write => 1, sql_type => 12, length => 32, is_blob => 0, is_numeric => 0, type => 'varchar(32)', default => ''},
+ {read => 1, write => 1, sql_type => 12, length => 32, is_blob => 0, is_numeric => 0, type => 'varchar(32)', default => 'default'},
InitialPriority =>
{read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
FinalPriority =>
diff --git a/rt/lib/RT/Queues.pm b/rt/lib/RT/Queues.pm
index feb349176..45cb686e0 100755
--- a/rt/lib/RT/Queues.pm
+++ b/rt/lib/RT/Queues.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Record.pm b/rt/lib/RT/Record.pm
index 313888cbc..6601a0df2 100755
--- a/rt/lib/RT/Record.pm
+++ b/rt/lib/RT/Record.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -501,19 +501,24 @@ sub _Set {
# $ret is a Class::ReturnValue object. as such, in a boolean context, it's a bool
# we want to change the standard "success" message
if ($status) {
- $msg =
- $self->loc(
- "[_1] changed from [_2] to [_3]",
- $self->loc( $args{'Field'} ),
- ( $old_val ? '"' . $old_val . '"' : $self->loc("(no value)") ),
- '"' . $self->__Value( $args{'Field'}) . '"'
- );
- } else {
-
- $msg = $self->CurrentUser->loc_fuzzy($msg);
+ if ($self->SQLType( $args{'Field'}) =~ /text/) {
+ $msg = $self->loc(
+ "[_1] updated",
+ $self->loc( $args{'Field'} ),
+ );
+ } else {
+ $msg = $self->loc(
+ "[_1] changed from [_2] to [_3]",
+ $self->loc( $args{'Field'} ),
+ ( $old_val ? '"' . $old_val . '"' : $self->loc("(no value)") ),
+ '"' . $self->__Value( $args{'Field'}) . '"',
+ );
+ }
+ } else {
+ $msg = $self->CurrentUser->loc_fuzzy($msg);
}
- return wantarray ? ($status, $msg) : $ret;
+ return wantarray ? ($status, $msg) : $ret;
}
@@ -888,6 +893,8 @@ sub Update {
$value =~ s/\r\n/\n/gs;
+ my $truncated_value = $self->TruncateValue($attribute, $value);
+
# If Queue is 'General', we want to resolve the queue name for
# the object.
@@ -902,8 +909,12 @@ sub Update {
my $name = $self->$object->Name;
next if $name eq $value || $name eq ($value || 0);
};
- next if $value eq $self->$attribute();
- next if ($value || 0) eq $self->$attribute();
+
+ my $current = $self->$attribute();
+ # RT::Queue->Lifecycle returns a Lifecycle object instead of name
+ $current = eval { $current->Name } if ref $current;
+ next if $truncated_value eq $current;
+ next if ( $truncated_value || 0 ) eq $current;
};
$new_values{$attribute} = $value;
@@ -1418,7 +1429,7 @@ sub _AddLink {
Delete a link. takes a paramhash of Base, Target and Type.
Either Base or Target must be null. The null value will
-be replaced with this ticket\'s id
+be replaced with this ticket's id
=cut
@@ -1633,29 +1644,37 @@ sub CustomFields {
$cfs->SetContextObject( $self );
# XXX handle multiple types properly
$cfs->LimitToLookupType( $self->CustomFieldLookupType );
- $cfs->LimitToGlobalOrObjectId(
- $self->_LookupId( $self->CustomFieldLookupType )
- );
+ $cfs->LimitToGlobalOrObjectId( $self->CustomFieldLookupId );
$cfs->ApplySortOrder;
return $cfs;
}
-# TODO: This _only_ works for RT::Class classes. it doesn't work, for example,
-# for RT::IR classes.
+# TODO: This _only_ works for RT::Foo classes. it doesn't work, for
+# example, for RT::IR::Foo classes.
-sub _LookupId {
+sub CustomFieldLookupId {
my $self = shift;
- my $lookup = shift;
+ my $lookup = shift || $self->CustomFieldLookupType;
my @classes = ($lookup =~ /RT::(\w+)-/g);
+ # Work on "RT::Queue", for instance
+ return $self->Id unless @classes;
+
my $object = $self;
+ # Save a ->Load call by not calling ->FooObj->Id, just ->Foo
+ my $final = shift @classes;
foreach my $class (reverse @classes) {
my $method = "${class}Obj";
$object = $object->$method;
}
- return $object->Id;
+ my $id = $object->$final;
+ unless (defined $id) {
+ my $method = "${final}Obj";
+ $id = $object->$method->Id;
+ }
+ return $id;
}
diff --git a/rt/lib/RT/Reminders.pm b/rt/lib/RT/Reminders.pm
index 2b663256a..42f4e1d2f 100644
--- a/rt/lib/RT/Reminders.pm
+++ b/rt/lib/RT/Reminders.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -116,6 +116,16 @@ sub Add {
@_
);
+ my $ticket = RT::Ticket->new($self->CurrentUser);
+ $ticket->Load($self->Ticket);
+ if ( !$ticket->id ) {
+ return ( 0, $self->loc( "Failed to load ticket [_1]", $self->Ticket ) );
+ }
+
+ if ( $ticket->Status eq 'deleted' ) {
+ return ( 0, $self->loc("Can't link to a deleted ticket") );
+ }
+
my $reminder = RT::Ticket->new($self->CurrentUser);
my ( $status, $msg ) = $reminder->Create(
Subject => $args{'Subject'},
diff --git a/rt/lib/RT/Report/Tickets.pm b/rt/lib/RT/Report/Tickets.pm
index de40dbdd4..b73bbaaa3 100644
--- a/rt/lib/RT/Report/Tickets.pm
+++ b/rt/lib/RT/Report/Tickets.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -57,22 +57,27 @@ use warnings;
sub Groupings {
my $self = shift;
my %args = (@_);
- my @fields = map {$_, $_} qw(
- Status
- Queue
- );
-
- foreach my $type ( qw(Owner Creator LastUpdatedBy Requestor Cc AdminCc Watcher) ) {
- push @fields, $type.' '.$_, $type.'.'.$_ foreach qw(
- Name EmailAddress RealName NickName Organization Lang City Country Timezone
- );
+ my @fields =
+ map { $self->CurrentUser->loc($_), $_ } qw( Status Queue ); # loc_qw
+
+ foreach my $type ( qw(Owner Creator LastUpdatedBy Requestor Cc AdminCc Watcher) ) { # loc_qw
+ for my $field (
+ qw( Name EmailAddress RealName NickName Organization Lang City Country Timezone ) # loc_qw
+ )
+ {
+ push @fields,
+ $self->CurrentUser->loc($type) . ' '
+ . $self->CurrentUser->loc($field), $type . '.' . $field;
+ }
}
- for my $field (qw(Due Resolved Created LastUpdated Started Starts Told)) {
- for my $frequency (qw(Hourly Daily Monthly Annually)) {
- my $item = $field.$frequency;
- push @fields, $item, $item;
+ for my $field (qw(Due Resolved Created LastUpdated Started Starts Told)) { # loc_qw
+ for my $frequency (qw(Hourly Daily Monthly Annually)) { # loc_qw
+ push @fields,
+ $self->CurrentUser->loc($field)
+ . $self->CurrentUser->loc($frequency),
+ $field . $frequency;
}
}
@@ -93,7 +98,11 @@ sub Groupings {
}
$CustomFields->LimitToGlobal;
while ( my $CustomField = $CustomFields->Next ) {
- push @fields, "Custom field '". $CustomField->Name ."'", "CF.{". $CustomField->id ."}";
+ push @fields, $self->CurrentUser->loc(
+ "Custom field '[_1]'",
+ $CustomField->Name
+ ),
+ "CF.{" . $CustomField->id . "}";
}
}
return @fields;
diff --git a/rt/lib/RT/Report/Tickets/Entry.pm b/rt/lib/RT/Report/Tickets/Entry.pm
index 87754c47d..eb3899319 100644
--- a/rt/lib/RT/Report/Tickets/Entry.pm
+++ b/rt/lib/RT/Report/Tickets/Entry.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Rule.pm b/rt/lib/RT/Rule.pm
index b007a4e9b..c5c8b0920 100644
--- a/rt/lib/RT/Rule.pm
+++ b/rt/lib/RT/Rule.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Ruleset.pm b/rt/lib/RT/Ruleset.pm
index de3983f6b..26227b759 100644
--- a/rt/lib/RT/Ruleset.pm
+++ b/rt/lib/RT/Ruleset.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/SQL.pm b/rt/lib/RT/SQL.pm
index 22def2688..15715a762 100644
--- a/rt/lib/RT/SQL.pm
+++ b/rt/lib/RT/SQL.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -69,7 +69,7 @@ my @tokens = qw[VALUE AGGREGATOR OPERATOR OPEN_PAREN CLOSE_PAREN KEYWORD];
use Regexp::Common qw /delimited/;
my $re_aggreg = qr[(?i:AND|OR)];
my $re_delim = qr[$RE{delimited}{-delim=>qq{\'\"}}];
-my $re_value = qr[[+-]?\d+|NULL|$re_delim];
+my $re_value = qr[[+-]?\d+|(?i:NULL)|$re_delim];
my $re_keyword = qr[[{}\w\.]+|$re_delim];
my $re_op = qr[=|!=|>=|<=|>|<|(?i:IS NOT)|(?i:IS)|(?i:NOT LIKE)|(?i:LIKE)|(?i:NOT STARTSWITH)|(?i:STARTSWITH)|(?i:NOT ENDSWITH)|(?i:ENDSWITH)]; # long to short
my $re_open_paren = qr[\(];
diff --git a/rt/lib/RT/SavedSearch.pm b/rt/lib/RT/SavedSearch.pm
index f7695d6f0..7c4df8b76 100644
--- a/rt/lib/RT/SavedSearch.pm
+++ b/rt/lib/RT/SavedSearch.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -77,7 +77,7 @@ An object of this class is called "search"
=cut
-sub ObjectName { "search" }
+sub ObjectName { "search" } # loc
sub PostLoad {
my $self = shift;
@@ -115,6 +115,28 @@ sub UpdateAttribute {
return ($status, $msg);
}
+=head2 RT::SavedSearch->EscapeDescription STRING
+
+This is a class method because system-level saved searches aren't true
+C<RT::SavedSearch> objects but direct C<RT::Attribute> objects.
+
+Returns C<STRING> with all square brackets except those in C<[_1]> escaped,
+ready for passing as the first argument to C<loc()>.
+
+=cut
+
+sub EscapeDescription {
+ my $self = shift;
+ my $desc = shift;
+ if ($desc) {
+ # We only use [_1] in saved search descriptions, so let's escape other "["
+ # and "]" unless they are escaped already.
+ $desc =~ s/(?<!~)\[(?!_1\])/~[/g;
+ $desc =~ s/(?<!~)(?<!\[_1)\]/~]/g;
+ }
+ return $desc;
+}
+
=head2 Type
Returns the type of this search, e.g. 'Ticket'. Useful for denoting the
diff --git a/rt/lib/RT/SavedSearches.pm b/rt/lib/RT/SavedSearches.pm
index 15c90dcb0..af8f48265 100644
--- a/rt/lib/RT/SavedSearches.pm
+++ b/rt/lib/RT/SavedSearches.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -70,6 +70,7 @@ package RT::SavedSearches;
use RT::SavedSearch;
use strict;
+use warnings;
use base 'RT::SharedSettings';
sub RecordClass {
diff --git a/rt/lib/RT/Scrip.pm b/rt/lib/RT/Scrip.pm
index 8f97e747f..5fa7165b1 100755
--- a/rt/lib/RT/Scrip.pm
+++ b/rt/lib/RT/Scrip.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -233,7 +233,7 @@ sub QueueObj {
=head2 ActionObj
-Retuns an RT::Action object with this Scrip\'s Action
+Retuns an RT::Action object with this Scrip's Action
=cut
@@ -285,7 +285,7 @@ sub LoadModules {
=head2 TemplateObj
-Retuns an RT::Template object with this Scrip\'s Template
+Retuns an RT::Template object with this Scrip's Template
=cut
@@ -362,7 +362,7 @@ sub Apply {
=head2 IsApplicable
-Calls the Condition object\'s IsApplicable method
+Calls the Condition object's IsApplicable method
Upon success, returns the applicable Transaction object.
Otherwise, undef is returned.
@@ -633,7 +633,7 @@ sub CompileCheck {
do {
no strict 'vars';
- eval "sub { $code }";
+ eval "sub { $code \n }";
};
next if !$@;
diff --git a/rt/lib/RT/ScripAction.pm b/rt/lib/RT/ScripAction.pm
index 13ab47e03..44f9bd83c 100755
--- a/rt/lib/RT/ScripAction.pm
+++ b/rt/lib/RT/ScripAction.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/ScripActions.pm b/rt/lib/RT/ScripActions.pm
index 322f7fcc6..a3a162253 100755
--- a/rt/lib/RT/ScripActions.pm
+++ b/rt/lib/RT/ScripActions.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/ScripCondition.pm b/rt/lib/RT/ScripCondition.pm
index 4156b69f2..e7e4652c9 100755
--- a/rt/lib/RT/ScripCondition.pm
+++ b/rt/lib/RT/ScripCondition.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -185,7 +185,7 @@ sub LoadCondition {
=head2 Describe
-Helper method to call the condition module\'s Describe method.
+Helper method to call the condition module's Describe method.
=cut
@@ -198,7 +198,7 @@ sub Describe {
=head2 IsApplicable
-Helper method to call the condition module\'s IsApplicable method.
+Helper method to call the condition module's IsApplicable method.
=cut
diff --git a/rt/lib/RT/ScripConditions.pm b/rt/lib/RT/ScripConditions.pm
index 145d94d6b..66684972d 100755
--- a/rt/lib/RT/ScripConditions.pm
+++ b/rt/lib/RT/ScripConditions.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Scrips.pm b/rt/lib/RT/Scrips.pm
index fa33f7ec7..af8323e33 100755
--- a/rt/lib/RT/Scrips.pm
+++ b/rt/lib/RT/Scrips.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Search.pm b/rt/lib/RT/Search.pm
index 7bf2f4a17..7ec50de88 100755
--- a/rt/lib/RT/Search.pm
+++ b/rt/lib/RT/Search.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Search/ActiveTicketsInQueue.pm b/rt/lib/RT/Search/ActiveTicketsInQueue.pm
index 8a9711854..da1cdb646 100644
--- a/rt/lib/RT/Search/ActiveTicketsInQueue.pm
+++ b/rt/lib/RT/Search/ActiveTicketsInQueue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -66,6 +66,7 @@ Find all active tickets in the queue named in the argument passed in
package RT::Search::ActiveTicketsInQueue;
use strict;
+use warnings;
use base qw(RT::Search);
diff --git a/rt/lib/RT/Search/FromSQL.pm b/rt/lib/RT/Search/FromSQL.pm
index fe0d874a4..4cb17f5e5 100644
--- a/rt/lib/RT/Search/FromSQL.pm
+++ b/rt/lib/RT/Search/FromSQL.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -66,6 +66,7 @@ Find all tickets described by the SQL statement passed as an argument
package RT::Search::FromSQL;
use strict;
+use warnings;
use base qw(RT::Search);
=head2 Describe
diff --git a/rt/lib/RT/Search/Googleish.pm b/rt/lib/RT/Search/Googleish.pm
index 1b4071f4d..f8465f00e 100644
--- a/rt/lib/RT/Search/Googleish.pm
+++ b/rt/lib/RT/Search/Googleish.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -203,7 +203,7 @@ our @GUESS = (
[ 40 => sub { return "status" if /^((in)?active|any)$/i } ],
[ 50 => sub {
my $q = RT::Queue->new( $_[2] );
- return "queue" if $q->Load($_) and $q->Id
+ return "queue" if $q->Load($_) and $q->Id and not $q->Disabled
}],
[ 60 => sub {
my $u = RT::User->new( $_[2] );
diff --git a/rt/lib/RT/SearchBuilder.pm b/rt/lib/RT/SearchBuilder.pm
index 4278f7587..adc8a98d7 100644
--- a/rt/lib/RT/SearchBuilder.pm
+++ b/rt/lib/RT/SearchBuilder.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -279,7 +279,7 @@ sub Limit {
|(NOT\s*)?(STARTS|ENDS)WITH
|(NOT\s*)?MATCHES
|IS(\s*NOT)?
- |IN
+ |(NOT\s*)?IN
|\@\@)$/ix) {
$RT::Logger->crit("Possible SQL injection attack: $ARGS{FIELD} $ARGS{OPERATOR}");
$self->SUPER::Limit(
diff --git a/rt/lib/RT/SharedSetting.pm b/rt/lib/RT/SharedSetting.pm
index 833308c12..3467167cc 100644
--- a/rt/lib/RT/SharedSetting.pm
+++ b/rt/lib/RT/SharedSetting.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -210,11 +210,11 @@ sub Save {
$self->{'Attribute'} = $object->Attributes->WithId($att_id);
$self->{'Id'} = $att_id;
$self->{'Privacy'} = $privacy;
- return ( 1, $self->loc( "Saved [_1] [_2]", $self->ObjectName, $name ) );
+ return ( 1, $self->loc( "Saved [_1] [_2]", $self->loc( $self->ObjectName ), $name ) );
}
else {
$RT::Logger->error($self->ObjectName . " save failure: $att_msg");
- return ( 0, $self->loc("Failed to create [_1] attribute", $self->ObjectName) );
+ return ( 0, $self->loc("Failed to create [_1] attribute", $self->loc( $self->ObjectName ) ) );
}
}
diff --git a/rt/lib/RT/SharedSettings.pm b/rt/lib/RT/SharedSettings.pm
index c2c9abeb8..6e7ec3b19 100644
--- a/rt/lib/RT/SharedSettings.pm
+++ b/rt/lib/RT/SharedSettings.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -70,6 +70,7 @@ package RT::SharedSettings;
use RT::SharedSetting;
use strict;
+use warnings;
use base 'RT::Base';
sub new {
diff --git a/rt/lib/RT/Shredder.pm b/rt/lib/RT/Shredder.pm
index 4f96e162d..bebd599b4 100644
--- a/rt/lib/RT/Shredder.pm
+++ b/rt/lib/RT/Shredder.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -720,7 +720,7 @@ sub GetFileName
=head4 StoragePath
Returns an absolute path to the storage dir. See
-L<CONFIGURATION/$ShredderStoragePath>.
+L</$ShredderStoragePath>.
See also description of the L</GetFileName> method.
diff --git a/rt/lib/RT/Shredder/ACE.pm b/rt/lib/RT/Shredder/ACE.pm
index e2fa75060..7a50d9a90 100644
--- a/rt/lib/RT/Shredder/ACE.pm
+++ b/rt/lib/RT/Shredder/ACE.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Attachment.pm b/rt/lib/RT/Shredder/Attachment.pm
index aa59bf644..9cd40884d 100644
--- a/rt/lib/RT/Shredder/Attachment.pm
+++ b/rt/lib/RT/Shredder/Attachment.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/CachedGroupMember.pm b/rt/lib/RT/Shredder/CachedGroupMember.pm
index f5542a2a1..9f1668f9e 100644
--- a/rt/lib/RT/Shredder/CachedGroupMember.pm
+++ b/rt/lib/RT/Shredder/CachedGroupMember.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Constants.pm b/rt/lib/RT/Shredder/Constants.pm
index ba160ce5e..b09b52f7d 100644
--- a/rt/lib/RT/Shredder/Constants.pm
+++ b/rt/lib/RT/Shredder/Constants.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/CustomField.pm b/rt/lib/RT/Shredder/CustomField.pm
index 43b759ea1..8c7dc2210 100644
--- a/rt/lib/RT/Shredder/CustomField.pm
+++ b/rt/lib/RT/Shredder/CustomField.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/CustomFieldValue.pm b/rt/lib/RT/Shredder/CustomFieldValue.pm
index 769336c27..9a9d36967 100644
--- a/rt/lib/RT/Shredder/CustomFieldValue.pm
+++ b/rt/lib/RT/Shredder/CustomFieldValue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Dependencies.pm b/rt/lib/RT/Shredder/Dependencies.pm
index 4b03cca2e..9364887fc 100644
--- a/rt/lib/RT/Shredder/Dependencies.pm
+++ b/rt/lib/RT/Shredder/Dependencies.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Shredder::Dependencies;
use strict;
+use warnings;
use RT::Shredder::Exceptions;
use RT::Shredder::Constants;
use RT::Shredder::Dependency;
diff --git a/rt/lib/RT/Shredder/Dependency.pm b/rt/lib/RT/Shredder/Dependency.pm
index 7300bee6c..280077132 100644
--- a/rt/lib/RT/Shredder/Dependency.pm
+++ b/rt/lib/RT/Shredder/Dependency.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::Shredder::Dependency;
use strict;
+use warnings;
use RT::Shredder::Constants;
use RT::Shredder::Exceptions;
diff --git a/rt/lib/RT/Shredder/Exceptions.pm b/rt/lib/RT/Shredder/Exceptions.pm
index b6a44b6ef..8c1d6ed4c 100644
--- a/rt/lib/RT/Shredder/Exceptions.pm
+++ b/rt/lib/RT/Shredder/Exceptions.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Group.pm b/rt/lib/RT/Shredder/Group.pm
index 0736793f2..bbf84ab88 100644
--- a/rt/lib/RT/Shredder/Group.pm
+++ b/rt/lib/RT/Shredder/Group.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/GroupMember.pm b/rt/lib/RT/Shredder/GroupMember.pm
index 5f06fae0b..a7e0b427f 100644
--- a/rt/lib/RT/Shredder/GroupMember.pm
+++ b/rt/lib/RT/Shredder/GroupMember.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Link.pm b/rt/lib/RT/Shredder/Link.pm
index 94beb8658..a4429100e 100644
--- a/rt/lib/RT/Shredder/Link.pm
+++ b/rt/lib/RT/Shredder/Link.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm b/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm
index 6bd236cef..7612f4ade 100644
--- a/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm
+++ b/rt/lib/RT/Shredder/ObjectCustomFieldValue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/POD.pm b/rt/lib/RT/Shredder/POD.pm
index 8dc320eba..6cc869503 100644
--- a/rt/lib/RT/Shredder/POD.pm
+++ b/rt/lib/RT/Shredder/POD.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin.pm b/rt/lib/RT/Shredder/Plugin.pm
index ad9af6ac6..60ba333c2 100644
--- a/rt/lib/RT/Shredder/Plugin.pm
+++ b/rt/lib/RT/Shredder/Plugin.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/Attachments.pm b/rt/lib/RT/Shredder/Plugin/Attachments.pm
index 0eaeeaf2d..f0f64a192 100644
--- a/rt/lib/RT/Shredder/Plugin/Attachments.pm
+++ b/rt/lib/RT/Shredder/Plugin/Attachments.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/Base.pm b/rt/lib/RT/Shredder/Plugin/Base.pm
index d9610d4d8..0adadfd1e 100644
--- a/rt/lib/RT/Shredder/Plugin/Base.pm
+++ b/rt/lib/RT/Shredder/Plugin/Base.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/Base/Dump.pm b/rt/lib/RT/Shredder/Plugin/Base/Dump.pm
index d4705b73e..903a962b8 100644
--- a/rt/lib/RT/Shredder/Plugin/Base/Dump.pm
+++ b/rt/lib/RT/Shredder/Plugin/Base/Dump.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/Base/Search.pm b/rt/lib/RT/Shredder/Plugin/Base/Search.pm
index eb28ba67c..a493cd82f 100644
--- a/rt/lib/RT/Shredder/Plugin/Base/Search.pm
+++ b/rt/lib/RT/Shredder/Plugin/Base/Search.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/Objects.pm b/rt/lib/RT/Shredder/Plugin/Objects.pm
index d5a7abb2f..20905748b 100644
--- a/rt/lib/RT/Shredder/Plugin/Objects.pm
+++ b/rt/lib/RT/Shredder/Plugin/Objects.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/SQLDump.pm b/rt/lib/RT/Shredder/Plugin/SQLDump.pm
index 91c2179aa..2e7c25965 100644
--- a/rt/lib/RT/Shredder/Plugin/SQLDump.pm
+++ b/rt/lib/RT/Shredder/Plugin/SQLDump.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/Summary.pm b/rt/lib/RT/Shredder/Plugin/Summary.pm
index aa2124224..9b533bc60 100644
--- a/rt/lib/RT/Shredder/Plugin/Summary.pm
+++ b/rt/lib/RT/Shredder/Plugin/Summary.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/Tickets.pm b/rt/lib/RT/Shredder/Plugin/Tickets.pm
index 67ee4a6cb..034448723 100644
--- a/rt/lib/RT/Shredder/Plugin/Tickets.pm
+++ b/rt/lib/RT/Shredder/Plugin/Tickets.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Plugin/Users.pm b/rt/lib/RT/Shredder/Plugin/Users.pm
index 1ff2c5084..244a2621b 100644
--- a/rt/lib/RT/Shredder/Plugin/Users.pm
+++ b/rt/lib/RT/Shredder/Plugin/Users.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Principal.pm b/rt/lib/RT/Shredder/Principal.pm
index 444416467..5dc04b30b 100644
--- a/rt/lib/RT/Shredder/Principal.pm
+++ b/rt/lib/RT/Shredder/Principal.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Queue.pm b/rt/lib/RT/Shredder/Queue.pm
index 2c0d068fb..80a1c84c6 100644
--- a/rt/lib/RT/Shredder/Queue.pm
+++ b/rt/lib/RT/Shredder/Queue.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Record.pm b/rt/lib/RT/Shredder/Record.pm
index d1c74bfd3..d70bf123b 100644
--- a/rt/lib/RT/Shredder/Record.pm
+++ b/rt/lib/RT/Shredder/Record.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Scrip.pm b/rt/lib/RT/Shredder/Scrip.pm
index 0af7a03c0..74878b62b 100644
--- a/rt/lib/RT/Shredder/Scrip.pm
+++ b/rt/lib/RT/Shredder/Scrip.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/ScripAction.pm b/rt/lib/RT/Shredder/ScripAction.pm
index 62f01f840..cdad7e4d2 100644
--- a/rt/lib/RT/Shredder/ScripAction.pm
+++ b/rt/lib/RT/Shredder/ScripAction.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/ScripCondition.pm b/rt/lib/RT/Shredder/ScripCondition.pm
index b48862a42..857f0623e 100644
--- a/rt/lib/RT/Shredder/ScripCondition.pm
+++ b/rt/lib/RT/Shredder/ScripCondition.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Template.pm b/rt/lib/RT/Shredder/Template.pm
index 40a03c971..4ac6daf79 100644
--- a/rt/lib/RT/Shredder/Template.pm
+++ b/rt/lib/RT/Shredder/Template.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Ticket.pm b/rt/lib/RT/Shredder/Ticket.pm
index 312b8fd4d..2e5453666 100644
--- a/rt/lib/RT/Shredder/Ticket.pm
+++ b/rt/lib/RT/Shredder/Ticket.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/Transaction.pm b/rt/lib/RT/Shredder/Transaction.pm
index 4b23ce6c4..37e6ba5ad 100644
--- a/rt/lib/RT/Shredder/Transaction.pm
+++ b/rt/lib/RT/Shredder/Transaction.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Shredder/User.pm b/rt/lib/RT/Shredder/User.pm
index 1c46203de..6e19da789 100644
--- a/rt/lib/RT/Shredder/User.pm
+++ b/rt/lib/RT/Shredder/User.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Squish.pm b/rt/lib/RT/Squish.pm
index eb31a63a1..e64b71198 100644
--- a/rt/lib/RT/Squish.pm
+++ b/rt/lib/RT/Squish.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Squish/CSS.pm b/rt/lib/RT/Squish/CSS.pm
index 991451495..1e2a45326 100644
--- a/rt/lib/RT/Squish/CSS.pm
+++ b/rt/lib/RT/Squish/CSS.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Squish/JS.pm b/rt/lib/RT/Squish/JS.pm
index 6309d016f..4dd24b709 100644
--- a/rt/lib/RT/Squish/JS.pm
+++ b/rt/lib/RT/Squish/JS.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/System.pm b/rt/lib/RT/System.pm
index d9aaf1cad..cf3d2d00b 100644
--- a/rt/lib/RT/System.pm
+++ b/rt/lib/RT/System.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Template.pm b/rt/lib/RT/Template.pm
index e509454b1..fd4b511e9 100755
--- a/rt/lib/RT/Template.pm
+++ b/rt/lib/RT/Template.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -335,7 +335,7 @@ sub Parse {
my ($rv, $msg);
- if ($self->Content =~ m{^Content-Type:\s+text/html\b}im) {
+ if (not $self->IsEmpty and $self->Content =~ m{^Content-Type:\s+text/html\b}im) {
local $RT::Transaction::PreferredContentType = 'text/html';
($rv, $msg) = $self->_Parse(@_);
}
@@ -458,7 +458,7 @@ sub _ParseContentPerl {
foreach my $key ( keys %{ $args{TemplateArgs} } ) {
my $val = $args{TemplateArgs}{ $key };
next unless ref $val;
- next if ref $val =~ /^(ARRAY|HASH|SCALAR|CODE)$/;
+ next if ref($val) =~ /^(ARRAY|HASH|SCALAR|CODE)$/;
$args{TemplateArgs}{ $key } = \$val;
}
diff --git a/rt/lib/RT/Templates.pm b/rt/lib/RT/Templates.pm
index be571f096..b4da63628 100755
--- a/rt/lib/RT/Templates.pm
+++ b/rt/lib/RT/Templates.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Test.pm b/rt/lib/RT/Test.pm
index 3e7c910ec..55fd88af9 100644
--- a/rt/lib/RT/Test.pm
+++ b/rt/lib/RT/Test.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -54,12 +54,20 @@ use warnings;
use base 'Test::More';
+# We use the Test::NoWarnings catching and reporting functionality, but need to
+# wrap it in our own special handler because of the warn handler installed via
+# RT->InitLogging().
+require Test::NoWarnings;
+
+my $Test_NoWarnings_Catcher = $SIG{__WARN__};
+my $check_warnings_in_end = 1;
+
use Socket;
use File::Temp qw(tempfile);
use File::Path qw(mkpath);
use File::Spec;
-our @EXPORT = qw(is_empty diag parse_mail works fails);
+our @EXPORT = qw(is_empty diag parse_mail works fails plan done_testing);
my %tmp = (
directory => undef,
@@ -94,20 +102,27 @@ problem in Perl that hides the top-level optree from L<Devel::Cover>.
our $port;
our @SERVERS;
+BEGIN {
+ delete $ENV{$_} for qw/LANGUAGE LC_ALL LC_MESSAGES LANG/;
+ $ENV{LANG} = "C";
+};
+
sub import {
my $class = shift;
my %args = %rttest_opt = @_;
+ $rttest_opt{'nodb'} = $args{'nodb'} = 1 if $^C;
+
# Spit out a plan (if we got one) *before* we load modules
if ( $args{'tests'} ) {
- $class->builder->plan( tests => $args{'tests'} )
+ plan( tests => $args{'tests'} )
unless $args{'tests'} eq 'no_declare';
}
elsif ( exists $args{'tests'} ) {
# do nothing if they say "tests => undef" - let them make the plan
}
elsif ( $args{'skip_all'} ) {
- $class->builder->plan(skip_all => $args{'skip_all'});
+ plan(skip_all => $args{'skip_all'});
}
else {
$class->builder->no_plan unless $class->builder->has_plan;
@@ -139,7 +154,7 @@ sub import {
__reconnect_rt()
unless $args{nodb};
- RT::InitLogging();
+ __init_logging();
RT->Plugins;
@@ -168,12 +183,15 @@ sub import {
}
Test::More->export_to_level($level);
+ Test::NoWarnings->export_to_level($level);
- # blow away their diag so we can redefine it without warning
+ # Blow away symbols we redefine to avoid warnings.
# better than "no warnings 'redefine'" because we might accidentally
# suppress a mistaken redefinition
no strict 'refs';
delete ${ caller($level) . '::' }{diag};
+ delete ${ caller($level) . '::' }{plan};
+ delete ${ caller($level) . '::' }{done_testing};
__PACKAGE__->export_to_level($level);
}
@@ -280,9 +298,15 @@ Set( \$RTAddressRegexp , qr/^bad_re_that_doesnt_match\$/i);
print $config "Set( \$DatabaseName , '$dbname');\n";
print $config "Set( \$DatabaseUser , 'u${dbname}');\n";
}
+ if ( $ENV{'RT_TEST_DB_HOST'} ) {
+ print $config "Set( \$DatabaseHost , '$ENV{'RT_TEST_DB_HOST'}');\n";
+ }
if ( $args{'plugins'} ) {
print $config "Set( \@Plugins, qw(". join( ' ', @{ $args{'plugins'} } ) .") );\n";
+
+ my $plugin_data = File::Spec->rel2abs("t/data/plugins");
+ print $config qq[\$RT::PluginPath = "$plugin_data";\n];
}
if ( $INC{'Devel/Cover.pm'} ) {
@@ -421,7 +445,7 @@ sub bootstrap_db {
$RT::Handle->InsertSchema;
$RT::Handle->InsertACL unless $db_type eq 'Oracle';
- RT->InitLogging;
+ __init_logging();
__reconnect_rt();
$RT::Handle->InsertInitialData
@@ -603,6 +627,28 @@ sub __disconnect_rt {
if DBIx::SearchBuilder::Record::Cachable->can("FlushCache");
}
+sub __init_logging {
+ my $filter;
+ {
+ # We use local to ensure that the $filter we grab is from InitLogging
+ # and not the handler generated by a previous call to this function
+ # itself.
+ local $SIG{__WARN__};
+ RT::InitLogging();
+ $filter = $SIG{__WARN__};
+ }
+ $SIG{__WARN__} = sub {
+ if ($filter) {
+ my $status = $filter->(@_);
+ if ($status and $status eq 'IGNORE') {
+ return; # pretend the bad dream never happened
+ }
+ }
+ # Avoid reporting this anonymous call frame as the source of the warning.
+ goto &$Test_NoWarnings_Catcher;
+ };
+}
+
=head1 UTILITIES
@@ -1079,17 +1125,28 @@ sub clean_caught_mails {
Takes a path relative to the location of the test file that is being
run and returns a path that takes the invocation path into account.
-e.g. RT::Test::get_relocatable_dir(File::Spec->updir(), 'data', 'emails')
+e.g. C<RT::Test::get_relocatable_dir(File::Spec->updir(), 'data', 'emails')>
+
+Parent directory traversals (C<..> or File::Spec->updir()) are naively
+canonicalized based on the test file path (C<$0>) so that symlinks aren't
+followed. This is the exact opposite behaviour of most filesystems and is
+considered "wrong", however it is necessary for some subsets of tests which are
+symlinked into the testing tree.
=cut
sub get_relocatable_dir {
- (my $volume, my $directories, my $file) = File::Spec->splitpath($0);
- if (File::Spec->file_name_is_absolute($directories)) {
- return File::Spec->catdir($directories, @_);
- } else {
- return File::Spec->catdir(File::Spec->curdir(), $directories, @_);
+ my @directories = File::Spec->splitdir(
+ File::Spec->rel2abs((File::Spec->splitpath($0))[1])
+ );
+ push @directories, File::Spec->splitdir($_) for @_;
+
+ my @clean;
+ for (@directories) {
+ if ($_ eq "..") { pop @clean }
+ elsif ($_ ne ".") { push @clean, $_ }
}
+ return File::Spec->catdir(@clean);
}
=head2 get_relocatable_file
@@ -1413,6 +1470,8 @@ sub start_inline_server {
# Clear out squished CSS and JS cache, since it's retained across
# servers, since it's in-process
RT::Interface::Web->ClearSquished;
+ require RT::Interface::Web::Request;
+ RT::Interface::Web::Request->clear_callback_cache;
Test::More::ok(1, "psgi test server ok");
$TEST_APP = $self->test_app(@_);
@@ -1519,15 +1578,38 @@ sub fails {
Test::More::ok(!$_[0], $_[1] || 'This should fail');
}
+sub plan {
+ my ($cmd, @args) = @_;
+ my $builder = RT::Test->builder;
+
+ if ($cmd eq "skip_all") {
+ $check_warnings_in_end = 0;
+ } elsif ($cmd eq "tests") {
+ # Increment the test count for the warnings check
+ $args[0]++;
+ }
+ $builder->plan($cmd, @args);
+}
+
+sub done_testing {
+ my $builder = RT::Test->builder;
+
+ Test::NoWarnings::had_no_warnings();
+ $check_warnings_in_end = 0;
+
+ $builder->done_testing(@_);
+}
+
END {
my $Test = RT::Test->builder;
return if $Test->{Original_Pid} != $$;
-
# we are in END block and should protect our exit code
# so calls below may call system or kill that clobbers $?
local $?;
+ Test::NoWarnings::had_no_warnings() if $check_warnings_in_end;
+
RT::Test->stop_server(1);
# not success
diff --git a/rt/lib/RT/Test/Apache.pm b/rt/lib/RT/Test/Apache.pm
index b2733eadb..256945afe 100644
--- a/rt/lib/RT/Test/Apache.pm
+++ b/rt/lib/RT/Test/Apache.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Test/Email.pm b/rt/lib/RT/Test/Email.pm
index a8170c981..8cf683946 100644
--- a/rt/lib/RT/Test/Email.pm
+++ b/rt/lib/RT/Test/Email.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Test/GnuPG.pm b/rt/lib/RT/Test/GnuPG.pm
index 6cebb775b..ec446724e 100644
--- a/rt/lib/RT/Test/GnuPG.pm
+++ b/rt/lib/RT/Test/GnuPG.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -48,6 +48,7 @@
package RT::Test::GnuPG;
use strict;
+use warnings;
use Test::More;
use base qw(RT::Test);
use File::Temp qw(tempdir);
@@ -68,8 +69,10 @@ sub import {
$t->plan( skip_all => 'gpg executable is required.' )
unless RT::Test->find_executable('gpg');
- require RT::Crypt::GnuPG;
$class->SUPER::import(%args);
+ require RT::Crypt::GnuPG;
+ return $class->export_to_level(1)
+ if $^C;
RT::Test::diag "GnuPG --homedir " . RT->Config->Get('GnuPGOptions')->{'homedir'};
diff --git a/rt/lib/RT/Test/Web.pm b/rt/lib/RT/Test/Web.pm
index c2d9ac314..8611102c2 100644
--- a/rt/lib/RT/Test/Web.pm
+++ b/rt/lib/RT/Test/Web.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Ticket.pm b/rt/lib/RT/Ticket.pm
index 5f76e055f..4da1d483b 100755
--- a/rt/lib/RT/Ticket.pm
+++ b/rt/lib/RT/Ticket.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -54,7 +54,7 @@
=head1 DESCRIPTION
-This module lets you manipulate RT\'s ticket object.
+This module lets you manipulate RT's ticket object.
=head1 METHODS
@@ -197,8 +197,8 @@ Arguments: ARGS is a hash of named parameters. Valid parameters are:
AdminCc - A reference to a list of email addresses or Names
SquelchMailTo - A reference to a list of email addresses -
who should this ticket not mail
- Type -- The ticket\'s type. ignore this for now
- Owner -- This ticket\'s owner. either an RT::User object or this user\'s id
+ Type -- The ticket's type. ignore this for now
+ Owner -- This ticket's owner. either an RT::User object or this user's id
Subject -- A string describing the subject of the ticket
Priority -- an integer from 0 to 99
InitialPriority -- an integer from 0 to 99
@@ -207,8 +207,8 @@ Arguments: ARGS is a hash of named parameters. Valid parameters are:
TimeEstimated -- an integer. estimated time for this task in minutes
TimeWorked -- an integer. time worked so far in minutes
TimeLeft -- an integer. time remaining in minutes
- Starts -- an ISO date describing the ticket\'s start date and time in GMT
- Due -- an ISO date describing the ticket\'s due date and time in GMT
+ Starts -- an ISO date describing the ticket's start date and time in GMT
+ Due -- an ISO date describing the ticket's due date and time in GMT
MIMEObj -- a MIME::Entity object with the content of the initial ticket request.
CustomField-<n> -- a scalar or array of values for the customfield with the id <n>
@@ -299,6 +299,7 @@ sub Create {
$args{'Status'} = $cycle->DefaultOnCreate;
}
+ $args{'Status'} = lc $args{'Status'};
unless ( $cycle->IsValid( $args{'Status'} ) ) {
return ( 0, 0,
$self->loc("Status '[_1]' isn't a valid status for tickets in this queue.",
@@ -460,6 +461,11 @@ sub Create {
}
}
+ $args{'Type'} = lc $args{'Type'}
+ if $args{'Type'} =~ /^(ticket|approval|reminder)$/i;
+
+ $args{'Subject'} =~ s/\n//g;
+
$RT::Handle->BeginTransaction();
my %params = (
@@ -783,6 +789,15 @@ sub Create {
}
}
+sub SetType {
+ my $self = shift;
+ my $value = shift;
+
+ # Force lowercase on internal RT types
+ $value = lc $value
+ if $value =~ /^(ticket|approval|reminder)$/i;
+ return $self->_Set(Field => 'Type', Value => $value, @_);
+}
@@ -850,8 +865,8 @@ sub _Parse822HeadersForAttributes {
=head2 Import PARAMHASH
Import a ticket.
-Doesn\'t create a transaction.
-Doesn\'t supply queue defaults, etc.
+Doesn't create a transaction.
+Doesn't supply queue defaults, etc.
Returns: TICKETID
@@ -885,7 +900,7 @@ sub Import {
$QueueObj = RT::Queue->new(RT->SystemUser);
$QueueObj->Load( $args{'Queue'} );
- #TODO error check this and return 0 if it\'s not loading properly +++
+ #TODO error check this and return 0 if it's not loading properly +++
}
elsif ( ref( $args{'Queue'} ) eq 'RT::Queue' ) {
$QueueObj = RT::Queue->new(RT->SystemUser);
@@ -1103,7 +1118,7 @@ PrincipalId The RT::Principal id of the user or group that's being added as a wa
Email The email address of the new watcher. If a user with this
email address can't be found, a new nonprivileged user will be created.
-If the watcher you\'re trying to set has an RT account, set the PrincipalId paremeter to their User Id. Otherwise, set the Email parameter to their Email address.
+If the watcher you're trying to set has an RT account, set the PrincipalId paremeter to their User Id. Otherwise, set the Email parameter to their Email address.
=cut
@@ -1206,7 +1221,8 @@ sub _AddWatcher {
if ( $group->HasMember( $principal)) {
- return ( 0, $self->loc('That principal is already a [_1] for this ticket', $self->loc($args{'Type'})) );
+ return ( 0, $self->loc('[_1] is already a [_2] for this ticket',
+ $principal->Object->Name, $self->loc($args{'Type'})) );
}
@@ -1215,7 +1231,8 @@ sub _AddWatcher {
unless ($m_id) {
$RT::Logger->error("Failed to add ".$principal->Id." as a member of group ".$group->Id.": ".$m_msg);
- return ( 0, $self->loc('Could not make that principal a [_1] for this ticket', $self->loc($args{'Type'})) );
+ return ( 0, $self->loc('Could not make [_1] a [_2] for this ticket',
+ $principal->Object->Name, $self->loc($args{'Type'})) );
}
unless ( $args{'Silent'} ) {
@@ -1226,7 +1243,8 @@ sub _AddWatcher {
);
}
- return ( 1, $self->loc('Added principal as a [_1] for this ticket', $self->loc($args{'Type'})) );
+ return ( 1, $self->loc('Added [_1] as a [_2] for this ticket',
+ $principal->Object->Name, $self->loc($args{'Type'})) );
}
@@ -1325,8 +1343,8 @@ sub DeleteWatcher {
unless ( $group->HasMember($principal) ) {
return ( 0,
- $self->loc( 'That principal is not a [_1] for this ticket',
- $args{'Type'} ) );
+ $self->loc( '[_1] is not a [_2] for this ticket',
+ $principal->Object->Name, $args{'Type'} ) );
}
my ( $m_id, $m_msg ) = $group->_DeleteMember( $principal->Id );
@@ -1339,8 +1357,8 @@ sub DeleteWatcher {
return (0,
$self->loc(
- 'Could not remove that principal as a [_1] for this ticket',
- $args{'Type'} ) );
+ 'Could not remove [_1] as a [_2] for this ticket',
+ $principal->Object->Name, $args{'Type'} ) );
}
unless ( $args{'Silent'} ) {
@@ -1421,7 +1439,7 @@ sub UnsquelchMailTo {
=head2 RequestorAddresses
- B<Returns> String: All Ticket Requestor email addresses as a string.
+B<Returns> String: All Ticket Requestor email addresses as a string.
=cut
@@ -1794,7 +1812,7 @@ sub SetQueue {
unless ( $old_lifecycle->HasMoveMap( $new_lifecycle ) ) {
return ( 0, $self->loc("There is no mapping for statuses between these queues. Contact your system administrator.") );
}
- $new_status = $old_lifecycle->MoveMap( $new_lifecycle )->{ $self->Status };
+ $new_status = $old_lifecycle->MoveMap( $new_lifecycle )->{ lc $self->Status };
return ( 0, $self->loc("Mapping between queues' lifecycles is incomplete. Contact your system administrator.") )
unless $new_status;
}
@@ -1891,6 +1909,13 @@ sub QueueObj {
return ($self->{_queue_obj});
}
+sub SetSubject {
+ my $self = shift;
+ my $value = shift;
+ $value =~ s/\n//g;
+ return $self->_Set( Field => 'Subject', Value => $value );
+}
+
=head2 SubjectTag
Takes nothing. Returns SubjectTag for this ticket. Includes
@@ -2256,6 +2281,11 @@ sub Correspond {
my @results = $self->_RecordNote(%args);
+ unless ( $results[0] ) {
+ $RT::Handle->Rollback();
+ return @results;
+ }
+
#Set the last told date to now if this isn't mail from the requestor.
#TODO: Note that this will wrongly ack mail from any non-requestor as a "told"
unless ( $self->IsRequestor($self->CurrentUser->id) ) {
@@ -2312,6 +2342,9 @@ sub _RecordNote {
);
}
+ $args{'MIMEObj'}->head->replace('X-RT-Interface' => 'API')
+ unless $args{'MIMEObj'}->head->get('X-RT-Interface');
+
# convert text parts into utf-8
RT::I18N::SetMIMEEntityToUTF8( $args{'MIMEObj'} );
@@ -2502,7 +2535,7 @@ sub _Links {
Delete a link. takes a paramhash of Base, Target, Type, Silent,
SilentBase and SilentTarget. Either Base or Target must be null.
-The null value will be replaced with this ticket\'s id.
+The null value will be replaced with this ticket's id.
If Silent is true then no transaction would be recorded, in other
case you can control creation of transactions on both base and
@@ -2653,9 +2686,7 @@ sub __GetTicketFromURI {
# If the other URI is an RT::Ticket, we want to make sure the user
# can modify it too...
my $uri_obj = RT::URI->new( $self->CurrentUser );
- $uri_obj->FromURI( $args{'URI'} );
-
- unless ( $uri_obj->Resolver && $uri_obj->Scheme ) {
+ unless ($uri_obj->FromURI( $args{'URI'} )) {
my $msg = $self->loc( "Couldn't resolve '[_1]' into a URI.", $args{'URI'} );
$RT::Logger->warning( $msg );
return( 0, $msg );
@@ -3196,11 +3227,16 @@ sub ValidateStatus {
return 0;
}
-
+sub Status {
+ my $self = shift;
+ my $value = $self->_Value( 'Status' );
+ return $value unless $self->QueueObj;
+ return $self->QueueObj->Lifecycle->CanonicalCase( $value );
+}
=head2 SetStatus STATUS
-Set this ticket\'s status. STATUS can be one of: new, open, stalled, resolved, rejected or deleted.
+Set this ticket's status. STATUS can be one of: new, open, stalled, resolved, rejected or deleted.
Alternatively, you can pass in a list of named parameters (Status => STATUS, Force => FORCE, SetStarted => SETSTARTED ).
If FORCE is true, ignore unresolved dependencies and force a status change.
@@ -3226,7 +3262,7 @@ sub SetStatus {
my $lifecycle = $self->QueueObj->Lifecycle;
- my $new = $args{'Status'};
+ my $new = lc $args{'Status'};
unless ( $lifecycle->IsValid( $new ) ) {
return (0, $self->loc("Status '[_1]' isn't a valid status for tickets in this queue.", $self->loc($new)));
}
@@ -3274,7 +3310,7 @@ sub SetStatus {
#Actually update the status
my ($val, $msg)= $self->_Set(
Field => 'Status',
- Value => $args{Status},
+ Value => $new,
TimeTaken => 0,
CheckACL => 0,
TransactionType => 'Status',
@@ -3578,6 +3614,9 @@ sub _Set {
OldValue => $Old,
TimeTaken => $args{'TimeTaken'},
);
+ # Ensure that we can read the transaction, even if the change
+ # just made the ticket unreadable to us
+ $TransObj->{ _object_is_readable } = 1;
return ( $Trans, scalar $TransObj->BriefDescription );
}
else {
@@ -3790,37 +3829,29 @@ sub TransactionCustomFields {
}
+=head2 LoadCustomFieldByIdentifier
-=head2 CustomFieldValues
-
-# Do name => id mapping (if needed) before falling back to
-# RT::Record's CustomFieldValues
-
-See L<RT::Record>
+Finds and returns the custom field of the given name for the ticket,
+overriding L<RT::Record/LoadCustomFieldByIdentifier> to look for
+queue-specific CFs before global ones.
=cut
-sub CustomFieldValues {
+sub LoadCustomFieldByIdentifier {
my $self = shift;
my $field = shift;
- return $self->SUPER::CustomFieldValues( $field ) if !$field || $field =~ /^\d+$/;
+ return $self->SUPER::LoadCustomFieldByIdentifier($field)
+ if ref $field or $field =~ /^\d+$/;
my $cf = RT::CustomField->new( $self->CurrentUser );
$cf->SetContextObject( $self );
$cf->LoadByNameAndQueue( Name => $field, Queue => $self->Queue );
- unless ( $cf->id ) {
- $cf->LoadByNameAndQueue( Name => $field, Queue => 0 );
- }
-
- # If we didn't find a valid cfid, give up.
- return RT::ObjectCustomFieldValues->new( $self->CurrentUser ) unless $cf->id;
-
- return $self->SUPER::CustomFieldValues( $cf->id );
+ $cf->LoadByNameAndQueue( Name => $field, Queue => 0 ) unless $cf->id;
+ return $cf;
}
-
=head2 CustomFieldLookupType
Returns the RT::Ticket lookup type, which can be passed to
diff --git a/rt/lib/RT/Tickets.pm b/rt/lib/RT/Tickets.pm
index c9986f41e..06b17e263 100755
--- a/rt/lib/RT/Tickets.pm
+++ b/rt/lib/RT/Tickets.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -158,6 +158,9 @@ our %FIELD_METADATA = (
WillResolve => [ 'DATE' => 'WillResolve', ], #loc_left_pair
);
+# Lower Case version of FIELDS, for case insensitivity
+our %LOWER_CASE_FIELDS = map { ( lc($_) => $_ ) } (keys %FIELD_METADATA);
+
our %SEARCHABLE_SUBFIELDS = (
User => [qw(
EmailAddress Name RealName Nickname Organization Address1 Address2
@@ -379,7 +382,11 @@ sub _EnumLimit {
my $class = "RT::" . $meta->[1];
my $o = $class->new( $sb->CurrentUser );
$o->Load($value);
- $value = $o->Id;
+ $value = $o->Id || 0;
+ } elsif ( $field eq "Type" ) {
+ $value = lc $value if $value =~ /^(ticket|approval|reminder)$/i;
+ } elsif ($field eq "Status") {
+ $value = lc $value;
}
$sb->_SQLLimit(
FIELD => $field,
@@ -463,7 +470,7 @@ sub _LinkLimit {
my $is_local = 1;
if ( $is_null ) {
- $op = ($op =~ /^(=|IS)$/)? 'IS': 'IS NOT';
+ $op = ($op =~ /^(=|IS)$/i)? 'IS': 'IS NOT';
}
elsif ( $value =~ /\D/ ) {
$is_local = 0;
@@ -941,22 +948,23 @@ sub _WatcherLimit {
die "Invalid watcher subfield: '$rest{SUBKEY}'";
}
+ # if it's equality op and search by Email or Name then we can preload user
+ # we do it to help some DBs better estimate number of rows and get better plans
+ if ( $op =~ /^!?=$/ && (!$rest{'SUBKEY'} || $rest{'SUBKEY'} eq 'Name' || $rest{'SUBKEY'} eq 'EmailAddress') ) {
+ my $o = RT::User->new( $self->CurrentUser );
+ my $method =
+ !$rest{'SUBKEY'}
+ ? $field eq 'Owner'? 'Load' : 'LoadByEmail'
+ : $rest{'SUBKEY'} eq 'EmailAddress' ? 'LoadByEmail': 'Load';
+ $o->$method( $value );
+ $rest{'SUBKEY'} = 'id';
+ $value = $o->id || 0;
+ }
+
# Owner was ENUM field, so "Owner = 'xxx'" allowed user to
# search by id and Name at the same time, this is workaround
# to preserve backward compatibility
if ( $field eq 'Owner' ) {
- if ( $op =~ /^!?=$/ && (!$rest{'SUBKEY'} || $rest{'SUBKEY'} eq 'Name' || $rest{'SUBKEY'} eq 'EmailAddress') ) {
- my $o = RT::User->new( $self->CurrentUser );
- my $method = ($rest{'SUBKEY'}||'') eq 'EmailAddress' ? 'LoadByEmail': 'Load';
- $o->$method( $value );
- $self->_SQLLimit(
- FIELD => 'Owner',
- OPERATOR => $op,
- VALUE => $o->id,
- %rest,
- );
- return;
- }
if ( ($rest{'SUBKEY'}||'') eq 'id' ) {
$self->_SQLLimit(
FIELD => 'Owner',
@@ -972,7 +980,7 @@ sub _WatcherLimit {
my $groups = $self->_RoleGroupsJoin( Type => $type, Class => $class, New => !$type );
$self->_OpenParen;
- if ( $op =~ /^IS(?: NOT)?$/ ) {
+ if ( $op =~ /^IS(?: NOT)?$/i ) {
# is [not] empty case
my $group_members = $self->_GroupMembersJoin( GroupsAlias => $groups );
@@ -1569,6 +1577,29 @@ sub _CustomFieldLimit {
}
}
+ if ( $cf && $cf->Type =~ /^Date(?:Time)?$/ ) {
+ my $date = RT::Date->new( $self->CurrentUser );
+ $date->Set( Format => 'unknown', Value => $value );
+ if ( $date->Unix ) {
+
+ if (
+ $cf->Type eq 'Date'
+ || $value =~ /^\s*(?:today|tomorrow|yesterday)\s*$/i
+ || ( $value !~ /midnight|\d+:\d+:\d+/i
+ && $date->Time( Timezone => 'user' ) eq '00:00:00' )
+ )
+ {
+ $value = $date->Date( Timezone => 'user' );
+ }
+ else {
+ $value = $date->DateTime;
+ }
+ }
+ else {
+ $RT::Logger->warn("$value is not a valid date string");
+ }
+ }
+
my $single_value = !$cf || !$cfid || $cf->SingleValue;
my $cfkey = $cfid ? $cfid : "$queue.$field";
@@ -1664,27 +1695,12 @@ sub _CustomFieldLimit {
}
else {
# need special treatment for Date
- if ( $cf and $cf->Type eq 'DateTime' and $op eq '=' ) {
-
- if ( $value =~ /:/ ) {
- # there is time speccified.
- my $date = RT::Date->new( $self->CurrentUser );
- $date->Set( Format => 'unknown', Value => $value );
- $self->_SQLLimit(
- ALIAS => $TicketCFs,
- FIELD => 'Content',
- OPERATOR => "=",
- VALUE => $date->ISO,
- %rest,
- );
- }
- else {
+ if ( $cf and $cf->Type eq 'DateTime' and $op eq '=' && $value !~ /:/ ) {
# no time specified, that means we want everything on a
# particular day. in the database, we need to check for >
# and < the edges of that day.
my $date = RT::Date->new( $self->CurrentUser );
$date->Set( Format => 'unknown', Value => $value );
- $date->SetToMidnight( Timezone => 'server' );
my $daystart = $date->ISO;
$date->AddDay;
my $dayend = $date->ISO;
@@ -1702,14 +1718,13 @@ sub _CustomFieldLimit {
$self->_SQLLimit(
ALIAS => $TicketCFs,
FIELD => 'Content',
- OPERATOR => "<=",
+ OPERATOR => "<",
VALUE => $dayend,
%rest,
ENTRYAGGREGATOR => 'AND',
);
$self->_CloseParen;
- }
}
elsif ( $op eq '=' || $op eq '!=' || $op eq '<>' ) {
if ( length( Encode::encode_utf8($value) ) < 256 ) {
@@ -2470,7 +2485,7 @@ sub LimitType {
VALUE => $args{'VALUE'},
OPERATOR => $args{'OPERATOR'},
DESCRIPTION => join( ' ',
- $self->loc('Type'), $args{'OPERATOR'}, $args{'Limit'}, ),
+ $self->loc('Type'), $args{'OPERATOR'}, $args{'VALUE'}, ),
);
}
@@ -2533,7 +2548,7 @@ sub LimitId {
Takes a paramhash with the fields OPERATOR and VALUE.
OPERATOR is one of =, >, < or !=.
-VALUE is a value to match the ticket\'s priority against
+VALUE is a value to match the ticket's priority against
=cut
@@ -2556,7 +2571,7 @@ sub LimitPriority {
Takes a paramhash with the fields OPERATOR and VALUE.
OPERATOR is one of =, >, < or !=.
-VALUE is a value to match the ticket\'s initial priority against
+VALUE is a value to match the ticket's initial priority against
=cut
@@ -2580,7 +2595,7 @@ sub LimitInitialPriority {
Takes a paramhash with the fields OPERATOR and VALUE.
OPERATOR is one of =, >, < or !=.
-VALUE is a value to match the ticket\'s final priority against
+VALUE is a value to match the ticket's final priority against
=cut
@@ -2753,7 +2768,7 @@ sub LimitOwner {
Takes a paramhash with the fields OPERATOR, TYPE and VALUE.
OPERATOR is one of =, LIKE, NOT LIKE or !=.
- VALUE is a value to match the ticket\'s watcher email addresses against
+ VALUE is a value to match the ticket's watcher email addresses against
TYPE is the sort of watchers you want to match against. Leave it undef if you want to search all of them
diff --git a/rt/lib/RT/Tickets_SQL.pm b/rt/lib/RT/Tickets_SQL.pm
index ec1bb4997..608862a37 100644
--- a/rt/lib/RT/Tickets_SQL.pm
+++ b/rt/lib/RT/Tickets_SQL.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -57,10 +57,7 @@ use RT::SQL;
# Import configuration data from the lexcial scope of __PACKAGE__ (or
# at least where those two Subroutines are defined.)
-our (%FIELD_METADATA, %dispatch, %can_bundle);
-
-# Lower Case version of FIELDS, for case insensitivity
-my %lcfields = map { ( lc($_) => $_ ) } (keys %FIELD_METADATA);
+our (%FIELD_METADATA, %LOWER_CASE_FIELDS, %dispatch, %can_bundle);
sub _InitSQL {
my $self = shift;
@@ -193,8 +190,8 @@ sub _parser {
# normalize key and get class (type)
my $class;
- if (exists $lcfields{lc $key}) {
- $key = $lcfields{lc $key};
+ if (exists $LOWER_CASE_FIELDS{lc $key}) {
+ $key = $LOWER_CASE_FIELDS{lc $key};
$class = $FIELD_METADATA{$key}->[0];
}
die "Unknown field '$key' in '$string'" unless $class;
diff --git a/rt/lib/RT/Topic.pm b/rt/lib/RT/Topic.pm
index 3499a4d2f..3e91e9dc3 100644
--- a/rt/lib/RT/Topic.pm
+++ b/rt/lib/RT/Topic.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/Topics.pm b/rt/lib/RT/Topics.pm
index fe7c3d819..01674fb66 100644
--- a/rt/lib/RT/Topics.pm
+++ b/rt/lib/RT/Topics.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -47,6 +47,7 @@
# END BPS TAGGED BLOCK }}}
use strict;
+use warnings;
no warnings qw(redefine);
package RT::Topics;
diff --git a/rt/lib/RT/Transaction.pm b/rt/lib/RT/Transaction.pm
index 3344687da..48d4e8ce9 100755
--- a/rt/lib/RT/Transaction.pm
+++ b/rt/lib/RT/Transaction.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -48,7 +48,7 @@
=head1 NAME
- RT::Transaction - RT\'s transaction object
+ RT::Transaction - RT's transaction object
=head1 SYNOPSIS
@@ -386,13 +386,24 @@ sub Content {
}
$content =~ s/^/> /gm;
- $content = $self->loc("On [_1], [_2] wrote:", $self->CreatedAsString, $self->CreatorObj->Name)
- . "\n$content\n\n";
+ $content = $self->QuoteHeader . "\n$content\n\n";
}
return ($content);
}
+=head2 QuoteHeader
+
+Returns text prepended to content when transaction is quoted
+(see C<Quote> argument in L</Content>). By default returns
+localized "On <date> <user name> wrote:\n".
+
+=cut
+
+sub QuoteHeader {
+ my $self = shift;
+ return $self->loc("On [_1], [_2] wrote:", $self->CreatedAsString, $self->CreatorObj->Name);
+}
=head2 Addresses
@@ -640,11 +651,14 @@ sub BriefDescription {
return ( $self->loc( "[_1] deleted", $obj_type ) );
}
else {
+ my $canon = $self->Object->can("QueueObj")
+ ? sub { $self->Object->QueueObj->Lifecycle->CanonicalCase(@_) }
+ : sub { return $_[0] };
return (
$self->loc(
"Status changed from [_1] to [_2]",
- "'" . $self->loc( $self->OldValue ) . "'",
- "'" . $self->loc( $self->NewValue ) . "'"
+ "'" . $self->loc( $canon->($self->OldValue) ) . "'",
+ "'" . $self->loc( $canon->($self->NewValue) ) . "'"
)
);
@@ -782,8 +796,7 @@ sub BriefDescription {
my $value;
if ( $self->NewValue ) {
my $URI = RT::URI->new( $self->CurrentUser );
- $URI->FromURI( $self->NewValue );
- if ( $URI->Resolver ) {
+ if ( $URI->FromURI( $self->NewValue ) ) {
$value = $URI->Resolver->AsString;
}
else {
@@ -821,8 +834,7 @@ sub BriefDescription {
my $value;
if ( $self->OldValue ) {
my $URI = RT::URI->new( $self->CurrentUser );
- $URI->FromURI( $self->OldValue );
- if ( $URI->Resolver ) {
+ if ( $URI->FromURI( $self->OldValue ) ){
$value = $URI->Resolver->AsString;
}
else {
@@ -1072,6 +1084,11 @@ sub CurrentUserCanSee {
$cf->Load( $cf_id );
return 0 unless $cf->CurrentUserHasRight('SeeCustomField');
}
+
+ # Transactions that might have changed the ->Object's visibility to
+ # the current user are marked readable
+ return 1 if $self->{ _object_is_readable };
+
# Defer to the object in question
return $self->Object->CurrentUserCanSee("Transaction");
}
@@ -1181,37 +1198,31 @@ sub UpdateCustomFields {
}
}
+=head2 LoadCustomFieldByIdentifier
-
-=head2 CustomFieldValues
-
- Do name => id mapping (if needed) before falling back to RT::Record's CustomFieldValues
-
- See L<RT::Record>
+Finds and returns the custom field of the given name for the
+transaction, overriding L<RT::Record/LoadCustomFieldByIdentifier> to
+look for queue-specific CFs before global ones.
=cut
-sub CustomFieldValues {
+sub LoadCustomFieldByIdentifier {
my $self = shift;
my $field = shift;
- if ( UNIVERSAL::can( $self->Object, 'QueueObj' ) ) {
-
- # XXX: $field could be undef when we want fetch values for all CFs
- # do we want to cover this situation somehow here?
- unless ( defined $field && $field =~ /^\d+$/o ) {
- my $CFs = RT::CustomFields->new( $self->CurrentUser );
- $CFs->SetContextObject( $self->Object );
- $CFs->Limit( FIELD => 'Name', VALUE => $field );
- $CFs->LimitToLookupType($self->CustomFieldLookupType);
- $CFs->LimitToGlobalOrObjectId($self->Object->QueueObj->id);
- $field = $CFs->First->id if $CFs->First;
- }
- }
- return $self->SUPER::CustomFieldValues($field);
-}
+ return $self->SUPER::LoadCustomFieldByIdentifier($field)
+ if ref $field or $field =~ /^\d+$/;
+ return $self->SUPER::LoadCustomFieldByIdentifier($field)
+ unless UNIVERSAL::can( $self->Object, 'QueueObj' );
+ my $CFs = RT::CustomFields->new( $self->CurrentUser );
+ $CFs->SetContextObject( $self->Object );
+ $CFs->Limit( FIELD => 'Name', VALUE => $field );
+ $CFs->LimitToLookupType($self->CustomFieldLookupType);
+ $CFs->LimitToGlobalOrObjectId($self->Object->QueueObj->id);
+ return $CFs->First || RT::CustomField->new( $self->CurrentUser );
+}
=head2 CustomFieldLookupType
diff --git a/rt/lib/RT/Transactions.pm b/rt/lib/RT/Transactions.pm
index 86a05f73b..3c9dac4d7 100755
--- a/rt/lib/RT/Transactions.pm
+++ b/rt/lib/RT/Transactions.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/URI.pm b/rt/lib/RT/URI.pm
index 284a75ee0..c0958ca36 100644
--- a/rt/lib/RT/URI.pm
+++ b/rt/lib/RT/URI.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/URI/a.pm b/rt/lib/RT/URI/a.pm
index b88af26fc..9475ba157 100644
--- a/rt/lib/RT/URI/a.pm
+++ b/rt/lib/RT/URI/a.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/URI/base.pm b/rt/lib/RT/URI/base.pm
index 19888b0b1..63af14063 100644
--- a/rt/lib/RT/URI/base.pm
+++ b/rt/lib/RT/URI/base.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -49,6 +49,7 @@
package RT::URI::base;
use strict;
+use warnings;
use base qw(RT::Base);
=head1 NAME
diff --git a/rt/lib/RT/URI/fsck_com_article.pm b/rt/lib/RT/URI/fsck_com_article.pm
index 0c09b7c3c..2b2132f5f 100644
--- a/rt/lib/RT/URI/fsck_com_article.pm
+++ b/rt/lib/RT/URI/fsck_com_article.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/URI/fsck_com_rt.pm b/rt/lib/RT/URI/fsck_com_rt.pm
index 1c11e22d1..34249d057 100644
--- a/rt/lib/RT/URI/fsck_com_rt.pm
+++ b/rt/lib/RT/URI/fsck_com_rt.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/URI/t.pm b/rt/lib/RT/URI/t.pm
index e73f64464..71c81fa91 100644
--- a/rt/lib/RT/URI/t.pm
+++ b/rt/lib/RT/URI/t.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
diff --git a/rt/lib/RT/User.pm b/rt/lib/RT/User.pm
index f26ace445..5511b9f6a 100755
--- a/rt/lib/RT/User.pm
+++ b/rt/lib/RT/User.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -167,18 +167,10 @@ sub Create {
return ( 0, $self->loc("Must specify 'Name' attribute") );
}
- #SANITY CHECK THE NAME AND ABORT IF IT'S TAKEN
- if (RT->SystemUser) { #This only works if RT::SystemUser has been defined
- my $TempUser = RT::User->new(RT->SystemUser);
- $TempUser->Load( $args{'Name'} );
- return ( 0, $self->loc('Name in use') ) if ( $TempUser->Id );
-
- my ($val, $message) = $self->ValidateEmailAddress( $args{'EmailAddress'} );
- return (0, $message) unless ( $val );
- } else {
- $RT::Logger->warning( "$self couldn't check for pre-existing users");
- }
-
+ my ( $val, $msg ) = $self->ValidateName( $args{'Name'} );
+ return ( 0, $msg ) unless $val;
+ ( $val, $msg ) = $self->ValidateEmailAddress( $args{'EmailAddress'} );
+ return ( 0, $msg ) unless ($val);
$RT::Handle->BeginTransaction();
# Groups deal with principal ids, rather than user ids.
@@ -270,6 +262,30 @@ sub Create {
return ( $id, $self->loc('User created') );
}
+=head2 ValidateName STRING
+
+Returns either (0, "failure reason") or 1 depending on whether the given
+name is valid.
+
+=cut
+
+sub ValidateName {
+ my $self = shift;
+ my $name = shift;
+
+ return ( 0, $self->loc('empty name') ) unless defined $name && length $name;
+
+ my $TempUser = RT::User->new( RT->SystemUser );
+ $TempUser->Load($name);
+
+ if ( $TempUser->id && ( !$self->id || $TempUser->id != $self->id ) ) {
+ return ( 0, $self->loc('Name in use') );
+ }
+ else {
+ return 1;
+ }
+}
+
=head2 ValidatePassword STRING
Returns either (0, "failure reason") or 1 depending on whether the given
@@ -572,6 +588,25 @@ sub ValidateEmailAddress {
}
}
+=head2 SetName
+
+Check to make sure someone else isn't using this name already
+
+=cut
+
+sub SetName {
+ my $self = shift;
+ my $Value = shift;
+
+ my ( $val, $message ) = $self->ValidateName($Value);
+ if ($val) {
+ return $self->_Set( Field => 'Name', Value => $Value );
+ }
+ else {
+ return ( 0, $message );
+ }
+}
+
=head2 SetEmailAddress
Check to make sure someone else isn't using this email address already
@@ -1393,7 +1428,7 @@ $user->WatchedQueues('Cc', 'AdminCc');
sub WatchedQueues {
my $self = shift;
- my @roles = @_ || ('Cc', 'AdminCc');
+ my @roles = @_ ? @_ : ('Cc', 'AdminCc');
$RT::Logger->debug('WatcheQueues got user ' . $self->Name);
diff --git a/rt/lib/RT/Users.pm b/rt/lib/RT/Users.pm
index 2784fc757..0f5ca706a 100755
--- a/rt/lib/RT/Users.pm
+++ b/rt/lib/RT/Users.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
@@ -118,7 +118,7 @@ sub PrincipalsAlias {
=head2 LimitToEnabled
-Only find items that haven\'t been disabled
+Only find items that haven't been disabled
=cut
diff --git a/rt/lib/RT/Util.pm b/rt/lib/RT/Util.pm
index 24efe71f5..38c3c20c9 100644
--- a/rt/lib/RT/Util.pm
+++ b/rt/lib/RT/Util.pm
@@ -2,7 +2,7 @@
#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)