[Bps-public-commit] rt-extension-ajaxpreviewscrips branch, master, updated. 0724b5e5bd6acc511de4f6a1042c38b5b7cdd9d3
Alex Vandiver
alexmv at bestpractical.com
Mon Jul 14 16:45:38 EDT 2014
The branch, master has been updated
via 0724b5e5bd6acc511de4f6a1042c38b5b7cdd9d3 (commit)
via 451a37dc6bc2754b877be859c968f5a150c28d54 (commit)
via 3d323302af9dacd3c363e8bfa6c5e9147a809083 (commit)
from 9180535e745e818f6c164da0b43712925f58e9ab (commit)
Summary of changes:
.../AjaxPreviewScrips/Ticket/Update.html/AfterForm | 28 ++
html/Elements/Crypt/SignEncryptWidget | 190 +++++++++++++
html/Helpers/PreviewScrips | 32 ++-
html/Helpers/ShowSimplifiedRecipients | 54 ++--
html/Ticket/Elements/PreviewScrips | 24 --
html/Ticket/Elements/ShowSimplifiedRecipients | 27 --
html/Ticket/ModifyPeople.html | 149 ++++++++++
lib/RT/Extension/AjaxPreviewScrips.pm | 310 +++++++++++++++++++++
8 files changed, 731 insertions(+), 83 deletions(-)
create mode 100644 html/Callbacks/AjaxPreviewScrips/Ticket/Update.html/AfterForm
create mode 100644 html/Elements/Crypt/SignEncryptWidget
create mode 100644 html/Ticket/ModifyPeople.html
- Log -----------------------------------------------------------------
commit 3d323302af9dacd3c363e8bfa6c5e9147a809083
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 14 16:26:34 2014 -0400
Don't show checkboxes for one-time Ccs unless they are actually squelchable
diff --git a/html/Helpers/ShowSimplifiedRecipients b/html/Helpers/ShowSimplifiedRecipients
index ab45134..fd110f6 100644
--- a/html/Helpers/ShowSimplifiedRecipients
+++ b/html/Helpers/ShowSimplifiedRecipients
@@ -65,16 +65,18 @@ my $Object = $TicketObj->DryRun(%ARGS);
$m->abort unless $Object;
my %headers = (To => {}, Cc => {}, Bcc => {});
-my %no_squelch;
+my %no_squelch = (To => {}, Cc => {}, Bcc => {});
if ($Object->Scrips) {
for my $scrip (grep $_->ActionObj->Action->isa('RT::Action::SendEmail'), @{$Object->Scrips->Prepared}) {
my $action = $scrip->ActionObj->Action;
for my $type (qw(To Cc Bcc)) {
- $headers{$type}{$_->address} = $_
- for $action->$type();
- }
- for my $type ( keys %{$action->{NoSquelch}} ) {
- $no_squelch{$type}{$_} ||= 1 for @{$action->{NoSquelch}{$type}};
+ for my $addr ($action->$type()) {
+ if (grep {$addr->address eq $_} @{$action->{NoSquelch}{$type} || []}) {
+ $no_squelch{$type}{$addr->address} = $addr;
+ } else {
+ $headers{$type}{$addr->address} = $addr;
+ }
+ }
}
}
}
@@ -91,7 +93,7 @@ my %squelched = ProcessTransactionSquelching( \%ARGS );
</%init>
<table>
% for my $type (qw(To Cc Bcc)) {
-% next unless keys %{$headers{$type}};
+% next unless keys %{$headers{$type}} or keys %{$no_squelch{$type}};
<tr>
<td valign="top"><% $type %>:</td>
<td valign="top">
@@ -103,16 +105,15 @@ my %squelched = ProcessTransactionSquelching( \%ARGS );
<label for="TxnSendMailTo-<% $addr->address %>-<% $recips{$addr->address} %>"><& /Elements/ShowUser, Address => $addr &></label>
% $m->callback(CallbackName => 'AfterAddress', Ticket => $TicketObj, Address => $addr, Type => $type);
<br />
-% if ( $no_squelch{$type}{$addr} ) {
+% }
+% for my $addr (sort {$a->address cmp $b->address} values %{$no_squelch{$type}}) {
<label><& /Elements/ShowUser, Address => $addr &></label>
-% if ( $type eq 'Cc' ) {
+% if ( $type eq 'Cc' ) {
(<&|/l&>explicit one-time Cc</&>)
-% }
-% else {
+% } else {
(<&|/l&>explicit one-time Bcc</&>)
-% }
-<br />
% }
+<br />
% }
</td></tr>
% }
commit 451a37dc6bc2754b877be859c968f5a150c28d54
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 14 16:27:31 2014 -0400
Unify recipients and previews javascript
diff --git a/html/Callbacks/AjaxPreviewScrips/Ticket/Update.html/AfterForm b/html/Callbacks/AjaxPreviewScrips/Ticket/Update.html/AfterForm
new file mode 100644
index 0000000..4c6c0af
--- /dev/null
+++ b/html/Callbacks/AjaxPreviewScrips/Ticket/Update.html/AfterForm
@@ -0,0 +1,28 @@
+<%args>
+$Ticket
+</%args>
+<%init>
+return unless $Ticket->CurrentUserHasRight('ShowOutgoingEmail')
+ or RT->Config->Get('SimplifiedRecipients', $session{'CurrentUser'});
+</%init>
+<script type="text/javascript">
+jQuery( function() {
+ var updateScrips = function() {
+ CKEDITOR.instances['UpdateContent'].updateElement();
+ var syncCheckboxes = function(ev) {
+ jQuery("input[name=TxnSendMailTo]").filter( function() { return this.value == ev.target.value; } ).prop("checked",jQuery(ev.target).prop('checked'));
+ };
+ jQuery('#recipients div.titlebox-content').load( '<% RT->Config->Get('WebPath')%>/Helpers/ShowSimplifiedRecipients',
+ jQuery('form[name=TicketUpdate]').serialize(),
+ function() { jQuery("#recipients input[name=TxnSendMailTo]").change( syncCheckboxes ); }
+ );
+ jQuery('#previewscrips div.titlebox-content').load( '<% RT->Config->Get('WebPath')%>/Helpers/PreviewScrips',
+ jQuery('form[name=TicketUpdate]').serialize(),
+ function() { jQuery("#previewscrips input[name=TxnSendMailTo]").change( syncCheckboxes ); }
+ );
+ };
+ updateScrips();
+ CKEDITOR.instances['UpdateContent'].on('blur', updateScrips );
+ jQuery("#ticket-update-metadata :input, input[name^=UpdateCc], input[name^=UpdateBcc]").change( updateScrips );
+});
+</script>
diff --git a/html/Ticket/Elements/PreviewScrips b/html/Ticket/Elements/PreviewScrips
index d7e5aa1..8ccb064 100644
--- a/html/Ticket/Elements/PreviewScrips
+++ b/html/Ticket/Elements/PreviewScrips
@@ -48,27 +48,3 @@
<%args>
$TicketObj => undef
</%args>
-<script type="text/javascript">
-jQuery( function() {
- jQuery('#ticket-update-metadata :input, input[name^=UpdateCc], input[name^=UpdateBcc]').change( function() {
- jQuery('#previewscrips div.titlebox-content').load( '<% RT->Config->Get('WebPath')%>/Helpers/PreviewScrips',
- jQuery('form[name=TicketUpdate]').serialize(),
- function() {
- jQuery("input[name=TxnSendMailTo]").change(function(ev) {
- jQuery("input[name=TxnSendMailTo]").filter( function() { return this.value == ev.target.value; } ).prop("checked",jQuery(ev.target).prop('checked'));
- });
- }
- );
- });
- jQuery('#UpdateType').change();
-
- jQuery('input[name=UpdateCc], input[name=UpdateBcc]').each( function() {
- var old_select = jQuery(this).autocomplete('option', 'select');
- jQuery(this).autocomplete('option', 'select', function(event, ui) {
- var ret = old_select.call(this, event, ui);
- jQuery(this).change();
- return ret;
- });
- });
-});
-</script>
diff --git a/html/Ticket/Elements/ShowSimplifiedRecipients b/html/Ticket/Elements/ShowSimplifiedRecipients
index 2e6093b..a4cec73 100644
--- a/html/Ticket/Elements/ShowSimplifiedRecipients
+++ b/html/Ticket/Elements/ShowSimplifiedRecipients
@@ -51,32 +51,5 @@ $TicketObj
<%INIT>
return unless RT->Config->Get('SimplifiedRecipients', $session{'CurrentUser'});
</%INIT>
-<script type="text/javascript">
-jQuery( function() {
- jQuery('#ticket-update-metadata :input, input[name^=UpdateCc], input[name^=UpdateBcc]').change( function() {
- jQuery('#recipients div.titlebox-content').load( '<% RT->Config->Get('WebPath')%>/Helpers/ShowSimplifiedRecipients',
- jQuery('form[name=TicketUpdate]').serialize(),
- function() {
-% unless ($TicketObj->CurrentUserHasRight('ShowOutgoingEmail')) {
- jQuery("input[name=TxnSendMailTo]").change(function(ev) {
- jQuery("input[name=TxnSendMailTo]").filter( function() { return this.value == ev.target.value; } ).prop("checked",jQuery(ev.target).prop('checked'));
- });
-% }
- });
- });
-% unless ($TicketObj->CurrentUserHasRight('ShowOutgoingEmail')) {
- jQuery('#UpdateType').change();
- jQuery('input[name=UpdateCc], input[name=UpdateBcc]').each( function() {
- var old_select = jQuery(this).autocomplete('option', 'select');
- jQuery(this).autocomplete('option', 'select', function(event, ui) {
- var ret = old_select.call(this, event, ui);
- jQuery(this).change();
- return ret;
- });
- } );
-% }
-});
-</script>
-
<&|/Widgets/TitleBox, title => loc('Recipients'), id => 'recipients' &>
</&>
commit 0724b5e5bd6acc511de4f6a1042c38b5b7cdd9d3
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Mon Jul 14 16:27:50 2014 -0400
Preview TransactionBatch scrips
diff --git a/html/Elements/Crypt/SignEncryptWidget b/html/Elements/Crypt/SignEncryptWidget
new file mode 100644
index 0000000..165210c
--- /dev/null
+++ b/html/Elements/Crypt/SignEncryptWidget
@@ -0,0 +1,190 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
+%# <sales at 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 }}}
+<table><tr>
+% my $columnsplit = "</td><td>";
+% if ( RT->Config->Get('Crypt')->{'Outgoing'} eq 'GnuPG' ) {
+<td><% loc( 'Sign[_1][_2] using [_3]',
+ $columnsplit,
+ $m->scomp('/Widgets/Form/Boolean:InputOnly',
+ Name => 'Sign', CurrentValue => $self->{'Sign'}
+ ),
+ $m->scomp('SelectKeyForSigning', User => $session{'CurrentUser'}->UserObj ),
+) |n %></td>
+% } else {
+<td><% loc( 'Sign[_1][_2]',
+ $columnsplit,
+ $m->scomp('/Widgets/Form/Boolean:InputOnly',
+ Name => 'Sign', CurrentValue => $self->{'Sign'}
+ ),
+) |n %></td>
+% }
+
+<td><% loc('Encrypt')%></td>
+<td><& /Widgets/Form/Boolean:InputOnly, Name => 'Encrypt', CurrentValue => $self->{'Encrypt'} &></td>
+</tr></table>
+<%ARGS>
+$self => undef,
+</%ARGS>
+<%INIT>
+return unless $self;
+</%INIT>
+
+<%METHOD new>
+<%ARGS>
+$Arguments => {}
+</%ARGS>
+<%INIT>
+return undef unless RT->Config->Get('Crypt')->{'Enable'};
+return { %$Arguments };
+</%INIT>
+</%METHOD>
+
+<%METHOD ShowIssues>
+<%ARGS>
+$self => undef,
+</%ARGS>
+<%INIT>
+return unless $self;
+
+return $m->comp( '/Elements/Crypt/KeyIssues',
+ Issues => $self->{'GnuPGRecipientsKeyIssues'} || [],
+ SignAddresses => $self->{'GnuPGCanNotSignAs'} || [],
+);
+</%INIT>
+</%METHOD>
+
+
+<%METHOD Process>
+<%ARGS>
+$self => undef
+$QueueObj => undef
+$TicketObj => undef
+</%ARGS>
+<%INIT>
+return unless $self;
+
+$QueueObj ||= $TicketObj->QueueObj if $TicketObj;
+
+foreach ( qw(Sign Encrypt) ) {
+ $self->{ $_ } = $m->comp( '/Widgets/Form/Boolean:Process',
+ Name => $_,
+ DefaultValue => $QueueObj->$_,
+ Arguments => $self,
+ );
+}
+</%INIT>
+</%METHOD>
+
+<%METHOD Check>
+<%ARGS>
+$self => undef
+$Operation => 'Update'
+$TicketObj => undef
+$QueueObj => undef
+</%ARGS>
+<%INIT>
+return 1 unless $self;
+
+my $checks_failure = 0;
+
+if ( $self->{'Sign'} ) {
+ $QueueObj ||= $TicketObj->QueueObj
+ if $TicketObj;
+
+ my $private = $session{'CurrentUser'}->UserObj->PrivateKey || '';
+ my $queue = ($self->{'UpdateType'} && $self->{'UpdateType'} eq "private")
+ ? ( $QueueObj->CommentAddress || RT->Config->Get('CommentAddress') )
+ : ( $QueueObj->CorrespondAddress || RT->Config->Get('CorrespondAddress') );
+
+ my $address = $self->{'SignUsing'} || $queue;
+ if ($address ne $private and $address ne $queue) {
+ push @{ $self->{'GnuPGCanNotSignAs'} ||= [] }, $address;
+ $checks_failure = 1;
+ } elsif ( not RT::Crypt->DrySign( Signer => $address ) ) {
+ push @{ $self->{'GnuPGCanNotSignAs'} ||= [] }, $address;
+ $checks_failure = 1;
+ } else {
+ RT::Crypt->UseKeyForSigning( $self->{'SignUsing'} )
+ if $self->{'SignUsing'};
+ }
+}
+
+if ( $self->{'Encrypt'} ) {
+
+ my @recipients;
+
+ if ( $Operation eq 'Update' ) {
+ @recipients = map {$_->Recipients} $TicketObj->DryRun(
+ sub { ProcessUpdateMessage( ARGSRef => {%$self}, TicketObj => $TicketObj ) } );
+ }
+ elsif ( $Operation eq 'Create' ) {
+ $TicketObj = RT::Ticket->new( $session{'CurrentUser'} );
+ @recipients = map {$_->Recipients} $TicketObj->DryRun(
+ sub { CreateTicket( %$self, TicketObj => $TicketObj ); } );
+ }
+ else {
+ $RT::Logger->crit('Incorrect operation: '. $Operation );
+ }
+
+ my %seen;
+ @recipients = grep !$seen{ lc $_ }++, @recipients;
+
+ RT::Crypt->UseKeyForEncryption(
+ map { (/^UseKey-(.*)$/)[0] => $self->{ $_ } }
+ grep $self->{ $_ } && /^UseKey-/,
+ keys %$self
+ );
+
+ my ($status, @issues) = RT::Crypt->CheckRecipients( @recipients );
+ push @{ $self->{'GnuPGRecipientsKeyIssues'} ||= [] }, @issues;
+ $checks_failure = 1 unless $status;
+}
+
+return $checks_failure ? 0 : 1;
+</%INIT>
+</%METHOD>
diff --git a/html/Helpers/PreviewScrips b/html/Helpers/PreviewScrips
index 8cceb89..ef7db09 100644
--- a/html/Helpers/PreviewScrips
+++ b/html/Helpers/PreviewScrips
@@ -60,9 +60,20 @@ else {
unless $TicketObj->CurrentUserHasRight( 'ReplyToTicket' ) || $TicketObj->CurrentUserHasRight( 'ModifyTicket' );
}
-my $Object = $TicketObj->DryRun(%ARGS);
+my @dryrun = $TicketObj->DryRun(
+ sub {
+ local $ARGS{UpdateContent} ||= "Content";
+ ProcessUpdateMessage(ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketWatchers(ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketBasics( ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketLinks( ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketDates( ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessObjectCustomFieldUpdates(ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketReminders( ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ }
+);
my %recips;
-$m->abort unless $Object;
+$m->abort unless @dryrun;
my %squelched = ProcessTransactionSquelching( \%ARGS );
</%init>
@@ -71,13 +82,9 @@ my %squelched = ProcessTransactionSquelching( \%ARGS );
&>Uncheck boxes to disable notifications to the listed recipients <b>for this transaction only</b>; persistent squelching is managed on the <a href="[_1]">People page</a>.</&>
</p>
-% if ( $Object->Scrips ) {
-% # Sort scrips with recipients before those without
-% my @scrips = map { $_->[0] }
-% sort { ($b->[1]?1:0) <=> ($a->[1]?1:0) }
-% map { [$_, $_->ActionObj->Action->To + $_->ActionObj->Action->Cc + $_->ActionObj->Action->Bcc] }
-% grep {$_->ActionObj->Action->isa('RT::Action::SendEmail')}
-% @{$Object->Scrips->Prepared};
+% my @scrips = grep {$_->ActionObj->Action->isa('RT::Action::SendEmail')}
+% map {@{$_->Scrips->Prepared}} @dryrun;
+% if (@scrips) {
% for my $scrip (@scrips) {
<b><% $scrip->Description || loc('Scrip #[_1]',$scrip->id) %></b><br />
<&|/l, loc($scrip->ConditionObj->Name), loc($scrip->ActionObj->Name), loc($scrip->Template)&>[_1] [_2] with template [_3]</&>
@@ -123,8 +130,9 @@ my %squelched = ProcessTransactionSquelching( \%ARGS );
% }
% }
-% if ( $Object->Rules ) {
-% for my $rule (@{$Object->Rules}) {
+% my @rules = map {@{$_->Rules}} @dryrun;
+% if ( @rules ) {
+% for my $rule (@rules) {
% next unless $rule->{hints} && $rule->{hints}{class} eq 'SendEmail';
<b><% $rule->Describe %></b>
% my $data = $rule->{hints}{recipients};
@@ -150,4 +158,4 @@ my %squelched = ProcessTransactionSquelching( \%ARGS );
% $m->callback( CallbackName => 'AfterRecipients', TicketObj => $TicketObj );
<input type="hidden" name="TxnRecipients" value="<% join ",",sort keys %recips %>" />
-% $m->abort();
\ No newline at end of file
+% $m->abort();
diff --git a/html/Helpers/ShowSimplifiedRecipients b/html/Helpers/ShowSimplifiedRecipients
index fd110f6..68e86cc 100644
--- a/html/Helpers/ShowSimplifiedRecipients
+++ b/html/Helpers/ShowSimplifiedRecipients
@@ -61,13 +61,25 @@ else {
unless $TicketObj->CurrentUserHasRight( 'ReplyToTicket' ) || $TicketObj->CurrentUserHasRight( 'ModifyTicket' );
}
-my $Object = $TicketObj->DryRun(%ARGS);
-$m->abort unless $Object;
+my @dryrun = $TicketObj->DryRun(
+ sub {
+ local $ARGS{UpdateContent} ||= "Content";
+ ProcessUpdateMessage(ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketWatchers(ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketBasics( ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketLinks( ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketDates( ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessObjectCustomFieldUpdates(ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ ProcessTicketReminders( ARGSRef => \%ARGS, TicketObj => $TicketObj );
+ }
+);
+$m->abort unless @dryrun;
my %headers = (To => {}, Cc => {}, Bcc => {});
my %no_squelch = (To => {}, Cc => {}, Bcc => {});
-if ($Object->Scrips) {
- for my $scrip (grep $_->ActionObj->Action->isa('RT::Action::SendEmail'), @{$Object->Scrips->Prepared}) {
+my @scrips = map {@{$_->Scrips->Prepared}} @dryrun;
+if (@scrips) {
+ for my $scrip (grep $_->ActionObj->Action->isa('RT::Action::SendEmail'), @scrips) {
my $action = $scrip->ActionObj->Action;
for my $type (qw(To Cc Bcc)) {
for my $addr ($action->$type()) {
@@ -80,8 +92,9 @@ if ($Object->Scrips) {
}
}
}
-if ($Object->Rules) {
- for my $rule (grep {$_->{hints} and $_->{hints}{class} eq "SendEmail"} @{$Object->Rules}) {
+my @rules = map {@{$_->Rules}} @dryrun;
+if (@rules) {
+ for my $rule (grep {$_->{hints} and $_->{hints}{class} eq "SendEmail"} @rules) {
for my $type (qw(To Cc Bcc)) {
$headers{$type}{$_} ||= @{[Email::Address->parse($_)]}[0] # Hate list context
for @{$rule->{hints}{recipients}{$type}};
@@ -127,4 +140,4 @@ my %squelched = ProcessTransactionSquelching( \%ARGS );
% unless ($TicketObj->CurrentUserHasRight('ShowOutgoingEmail')) {
<input type="hidden" name="TxnRecipients" value="<% join ",",sort keys %recips %>" />
% }
-% $m->abort();
\ No newline at end of file
+% $m->abort();
diff --git a/html/Ticket/ModifyPeople.html b/html/Ticket/ModifyPeople.html
new file mode 100644
index 0000000..bda19d4
--- /dev/null
+++ b/html/Ticket/ModifyPeople.html
@@ -0,0 +1,149 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
+%# <sales at 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 }}}
+<& /Elements/Header, Title => loc('Modify people related to ticket #[_1]', $Ticket->id) &>
+<& /Elements/Tabs &>
+
+% $m->callback(CallbackName => 'BeforeActionList', Actions => \@results, ARGSRef => \%ARGS, Ticket => $Ticket);
+<& /Elements/ListActions, actions => \@results &>
+
+<form method="post" action="ModifyPeople.html" name="TicketPeople">
+<input type="hidden" class="hidden" name="id" value="<%$Ticket->Id%>" />
+% $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS );
+<&| /Widgets/TitleBox, title => loc('Modify people related to ticket #[_1]', $Ticket->Id), width => "100%", color=> "#333399", class=>'ticket-info-people' &>
+<& Elements/EditPeople, Ticket => $Ticket, UserField => $UserField, UserString => $UserString, UserOp => $UserOp, GroupString => $GroupString, GroupOp => $GroupOp, GroupField => $GroupField &>
+</&>
+<&| /Widgets/TitleBox, title => loc("Modify who receives mail for ticket #[_1]", $Ticket->Id), width => "100%", color=> "#333399", class=>'ticket-info-squelch' &>
+<p>
+ The checked users may receive email related to this ticket depending on the
+ action taken. Uncheck users to stop sending email to them about this ticket.
+</p>
+
+<ul>
+% for my $addr (sort keys %recips) {
+ <li>
+ <input type="hidden" name="autorecipient" value="<% $addr %>">
+ <input type="checkbox" name="checked_recipient" id="checked_recipient_<%$addr%>" value="<%$addr%>" <% $recips{$addr} ? "checked" : "" %>>
+ <label for="checked_recipient_<%$addr%>"><& /Elements/ShowUser, Address => Email::Address->parse($addr) &></label>
+ </li>
+% }
+</ul>
+</&>
+<& /Elements/Submit, Name => 'SubmitTicket', Label => loc('Save Changes'), Caption => loc("If you've updated anything above, be sure to"), color => "#333399" &>
+</form>
+
+% $m->callback(CallbackName => 'AfterForm', ARGSRef => \%ARGS, Ticket => $Ticket);
+
+<%INIT>
+
+my @results;
+
+my $Ticket = LoadTicket($id);
+$m->callback( TicketObj => $Ticket, ARGSRef => \%ARGS );
+
+# Update the squelch list
+my %squelched = map {$_->Content => 1} $Ticket->SquelchMailTo;
+my %checked = map {$_ => 1} grep {defined}
+ (ref $ARGS{'checked_recipient'} eq "ARRAY" ? @{$ARGS{'checked_recipient'}}
+ : defined $ARGS{'checked_recipient'} ? ($ARGS{'checked_recipient'}) : ());
+my @all = grep {defined}
+ (ref $ARGS{'autorecipient'} eq "ARRAY" ? @{$ARGS{'autorecipient'}}
+ : defined $ARGS{'autorecipient'} ? ($ARGS{'autorecipient'}) : ());
+$Ticket->UnsquelchMailTo($_)
+ for grep {$squelched{$_}} keys %checked;
+$Ticket->SquelchMailTo($_)
+ for grep {!$squelched{$_} and !$checked{$_}} @all;
+
+# if we're trying to search for watchers and nothing else
+unless ($OnlySearchForPeople or $OnlySearchForGroup) {
+ push @results, ProcessTicketBasics( TicketObj => $Ticket, ARGSRef => \%ARGS);
+ push @results, ProcessTicketWatchers( TicketObj => $Ticket, ARGSRef => \%ARGS);
+ push @results, ProcessObjectCustomFieldUpdates( TicketObj => $Ticket, ARGSRef => \%ARGS );
+
+ $Ticket->ApplyTransactionBatch;
+}
+
+# Use the ticket's scrips to figure out the new list of recipients.
+my @txns = $Ticket->DryRun(
+ sub {
+ my $MIME = MIME::Entity->build( Type => "text/plain", Data => "" );
+ $Ticket->Comment(MIMEObj => $MIME);
+ $Ticket->Correspond(MIMEObj => $MIME);
+ }
+);
+my %recips=();
+for my $scrip (map {@{$_->Scrips->Prepared}} @txns) {
+ next unless $scrip->ActionObj->Action->isa('RT::Action::SendEmail');
+ for my $type (qw(To Cc Bcc)) {
+ $recips{$_->address} = 1 for $scrip->ActionObj->Action->$type();
+ }
+}
+for my $rule (map {@{$_->Rules}} @txns) {
+ next unless $rule->{hints} && $rule->{hints}{class} eq "SendEmail";
+ for my $type (qw(To Cc Bcc)) {
+ $recips{$_} = 1 for @{$rule->{hints}{recips}{$type}};
+ }
+}
+
+# Use tkt squelch list to get recipients who will NOT get mail:
+$recips{$_->Content} = 0 for $Ticket->SquelchMailTo;
+</%INIT>
+
+
+
+<%ARGS>
+$OnlySearchForPeople => undef
+$OnlySearchForGroup => undef
+$UserField => undef
+$UserOp => undef
+$UserString => undef
+$GroupField => undef
+$GroupOp => undef
+$GroupString => undef
+$id => undef
+</%ARGS>
+
diff --git a/lib/RT/Extension/AjaxPreviewScrips.pm b/lib/RT/Extension/AjaxPreviewScrips.pm
index 8a40d70..3e5e680 100644
--- a/lib/RT/Extension/AjaxPreviewScrips.pm
+++ b/lib/RT/Extension/AjaxPreviewScrips.pm
@@ -41,6 +41,316 @@ May need root permissions
=back
+=cut
+
+no warnings 'redefine';
+
+package HTML::Mason::Commands;
+use vars qw/%session/;
+sub CreateTicket {
+ my %ARGS = (@_);
+
+ my (@Actions);
+
+ my $Ticket = delete $ARGS{TicketObj} || RT::Ticket->new( $session{'CurrentUser'} );
+
+ my $Queue = RT::Queue->new( $session{'CurrentUser'} );
+ unless ( $Queue->Load( $ARGS{'Queue'} ) ) {
+ Abort('Queue not found');
+ }
+
+ unless ( $Queue->CurrentUserHasRight('CreateTicket') ) {
+ Abort('You have no permission to create tickets in that queue.');
+ }
+
+ my $due;
+ if ( defined $ARGS{'Due'} and $ARGS{'Due'} =~ /\S/ ) {
+ $due = RT::Date->new( $session{'CurrentUser'} );
+ $due->Set( Format => 'unknown', Value => $ARGS{'Due'} );
+ }
+ my $starts;
+ if ( defined $ARGS{'Starts'} and $ARGS{'Starts'} =~ /\S/ ) {
+ $starts = RT::Date->new( $session{'CurrentUser'} );
+ $starts->Set( Format => 'unknown', Value => $ARGS{'Starts'} );
+ }
+
+ my $sigless = RT::Interface::Web::StripContent(
+ Content => $ARGS{Content},
+ ContentType => $ARGS{ContentType},
+ StripSignature => 1,
+ CurrentUser => $session{'CurrentUser'},
+ );
+
+ my $MIMEObj = MakeMIMEEntity(
+ Subject => $ARGS{'Subject'},
+ From => $ARGS{'From'},
+ Cc => $ARGS{'Cc'},
+ Body => $sigless,
+ Type => $ARGS{'ContentType'},
+ Interface => RT::Interface::Web::MobileClient() ? 'Mobile' : 'Web',
+ );
+
+ my @attachments;
+ if ( my $tmp = $session{'Attachments'}{ $ARGS{'Token'} || '' } ) {
+ push @attachments, grep $_, map $tmp->{$_}, sort keys %$tmp;
+
+ delete $session{'Attachments'}{ $ARGS{'Token'} || '' }
+ unless $ARGS{'KeepAttachments'};
+ $session{'Attachments'} = $session{'Attachments'}
+ if @attachments;
+ }
+ if ( $ARGS{'Attachments'} ) {
+ push @attachments, grep $_, map $ARGS{Attachments}->{$_}, sort keys %{ $ARGS{'Attachments'} };
+ }
+ if ( @attachments ) {
+ $MIMEObj->make_multipart;
+ $MIMEObj->add_part( $_ ) foreach @attachments;
+ }
+
+ for my $argument (qw(Encrypt Sign)) {
+ if ( defined $ARGS{ $argument } ) {
+ $MIMEObj->head->replace( "X-RT-$argument" => $ARGS{$argument} ? 1 : 0 );
+ }
+ }
+
+ my %create_args = (
+ Type => $ARGS{'Type'} || 'ticket',
+ Queue => $ARGS{'Queue'},
+ Owner => $ARGS{'Owner'},
+
+ # note: name change
+ Requestor => $ARGS{'Requestors'},
+ Cc => $ARGS{'Cc'},
+ AdminCc => $ARGS{'AdminCc'},
+ InitialPriority => $ARGS{'InitialPriority'},
+ FinalPriority => $ARGS{'FinalPriority'},
+ TimeLeft => $ARGS{'TimeLeft'},
+ TimeEstimated => $ARGS{'TimeEstimated'},
+ TimeWorked => $ARGS{'TimeWorked'},
+ Subject => $ARGS{'Subject'},
+ Status => $ARGS{'Status'},
+ Due => $due ? $due->ISO : undef,
+ Starts => $starts ? $starts->ISO : undef,
+ MIMEObj => $MIMEObj,
+ TransSquelchMailTo => $ARGS{'TransSquelchMailTo'},
+ );
+
+ my @txn_squelch;
+ foreach my $type (qw(Requestor Cc AdminCc)) {
+ push @txn_squelch, map $_->address, Email::Address->parse( $create_args{$type} )
+ if grep $_ eq $type || $_ eq ( $type . 's' ), @{ $ARGS{'SkipNotification'} || [] };
+ }
+ push @{$create_args{TransSquelchMailTo}}, @txn_squelch;
+
+ if ( $ARGS{'AttachTickets'} ) {
+ require RT::Action::SendEmail;
+ RT::Action::SendEmail->AttachTickets( RT::Action::SendEmail->AttachTickets,
+ ref $ARGS{'AttachTickets'}
+ ? @{ $ARGS{'AttachTickets'} }
+ : ( $ARGS{'AttachTickets'} ) );
+ }
+
+ my %cfs = ProcessObjectCustomFieldUpdatesForCreate(
+ ARGSRef => \%ARGS,
+ ContextObject => $Queue,
+ );
+
+ my %links = ProcessLinksForCreate( ARGSRef => \%ARGS );
+
+ my ( $id, $Trans, $ErrMsg ) = $Ticket->Create(%create_args, %links, %cfs);
+
+ unless ($id) {
+ Abort($ErrMsg);
+ }
+
+ push( @Actions, split( "\n", $ErrMsg ) );
+ unless ( $Ticket->CurrentUserHasRight('ShowTicket') ) {
+ Abort( "No permission to view newly created ticket #" . $Ticket->id . "." );
+ }
+ return ( $Ticket, @Actions );
+
+}
+
+my $_ProcessUpdateMessageRecipients = \&_ProcessUpdateMessageRecipients;
+*_ProcessUpdateMessageRecipients = sub {
+ $_ProcessUpdateMessageRecipients->(@_);
+
+ my %args = (
+ TicketObj => undef,
+ MessageArgs => undef,
+ @_,
+ );
+ $args{TicketObj}{TransSquelchMailTo} ||= $args{message_args}{'SquelchMailTo'};
+};
+
+
+package RT::Record;
+sub _NewTransaction {
+ my $self = shift;
+ my %args = (
+ TimeTaken => undef,
+ Type => undef,
+ OldValue => undef,
+ NewValue => undef,
+ OldReference => undef,
+ NewReference => undef,
+ ReferenceType => undef,
+ Data => undef,
+ Field => undef,
+ MIMEObj => undef,
+ ActivateScrips => 1,
+ SquelchMailTo => undef,
+ @_
+ );
+
+ my $in_txn = RT->DatabaseHandle->TransactionDepth;
+ RT->DatabaseHandle->BeginTransaction unless $in_txn;
+
+ $self->LockForUpdate;
+
+ my $old_ref = $args{'OldReference'};
+ my $new_ref = $args{'NewReference'};
+ my $ref_type = $args{'ReferenceType'};
+ if ($old_ref or $new_ref) {
+ $ref_type ||= ref($old_ref) || ref($new_ref);
+ if (!$ref_type) {
+ $RT::Logger->error("Reference type not specified for transaction");
+ return;
+ }
+ $old_ref = $old_ref->Id if ref($old_ref);
+ $new_ref = $new_ref->Id if ref($new_ref);
+ }
+
+ require RT::Transaction;
+ my $trans = RT::Transaction->new( $self->CurrentUser );
+ my ( $transaction, $msg ) = $trans->Create(
+ ObjectId => $self->Id,
+ ObjectType => ref($self),
+ TimeTaken => $args{'TimeTaken'},
+ Type => $args{'Type'},
+ Data => $args{'Data'},
+ Field => $args{'Field'},
+ NewValue => $args{'NewValue'},
+ OldValue => $args{'OldValue'},
+ NewReference => $new_ref,
+ OldReference => $old_ref,
+ ReferenceType => $ref_type,
+ MIMEObj => $args{'MIMEObj'},
+ ActivateScrips => $args{'ActivateScrips'},
+ DryRun => $self->{DryRun},
+ SquelchMailTo => $args{'SquelchMailTo'} || $self->{TransSquelchMailTo},
+ );
+
+ # Rationalize the object since we may have done things to it during the caching.
+ $self->Load($self->Id);
+
+ $RT::Logger->warning($msg) unless $transaction;
+
+ $self->_SetLastUpdated;
+
+ if ( defined $args{'TimeTaken'} and $self->can('_UpdateTimeTaken')) {
+ $self->_UpdateTimeTaken( $args{'TimeTaken'}, Transaction => $trans );
+ }
+ if ( RT->Config->Get('UseTransactionBatch') and $transaction ) {
+ push @{$self->{_TransactionBatch}}, $trans;
+ }
+
+ RT->DatabaseHandle->Commit unless $in_txn;
+
+ return ( $transaction, $msg, $trans );
+}
+
+package RT::Ticket;
+sub DryRun {
+ my $self = shift;
+
+ my ($subref) = @_;
+
+ my @transactions;
+
+ $RT::Handle->BeginTransaction();
+ {
+ # Getting nested "commit"s inside this rollback is fine
+ local %DBIx::SearchBuilder::Handle::TRANSROLLBACK;
+ local $self->{DryRun} = \@transactions;
+ eval { $subref->() };
+ warn "Error is $@" if $@;
+ $self->ApplyTransactionBatch;
+ }
+
+ @transactions = grep {$_} @transactions;
+
+ $RT::Handle->Rollback();
+
+ return wantarray ? @transactions : $transactions[0];
+}
+
+sub _ApplyTransactionBatch {
+ my $self = shift;
+
+ return if $self->RanTransactionBatch;
+ $self->RanTransactionBatch(1);
+
+ my $still_exists = RT::Ticket->new( RT->SystemUser );
+ $still_exists->Load( $self->Id );
+ if (not $still_exists->Id) {
+ # The ticket has been removed from the database, but we still
+ # have pending TransactionBatch txns for it. Unfortunately,
+ # because it isn't in the DB anymore, attempting to run scrips
+ # on it may produce unpredictable results; simply drop the
+ # batched transactions.
+ $RT::Logger->warning("TransactionBatch was fired on a ticket that no longer exists; unable to run scrips! Call ->ApplyTransactionBatch before shredding the ticket, for consistent results.");
+ return;
+ }
+
+ my $batch = $self->TransactionBatch;
+
+ my %seen;
+ my $types = join ',', grep !$seen{$_}++, grep defined, map $_->__Value('Type'), grep defined, @{$batch};
+
+ require RT::Scrips;
+ my $scrips = RT::Scrips->new(RT->SystemUser);
+ $scrips->Prepare(
+ Stage => 'TransactionBatch',
+ TicketObj => $self,
+ TransactionObj => $batch->[0],
+ Type => $types,
+ );
+
+ # Entry point of the rule system
+ my $rules = RT::Ruleset->FindAllRules(
+ Stage => 'TransactionBatch',
+ TicketObj => $self,
+ TransactionObj => $batch->[0],
+ Type => $types,
+ );
+
+ if ($self->{DryRun}) {
+ my $fake_txn = RT::Transaction->new( $self->CurrentUser );
+ $fake_txn->{scrips} = $scrips;
+ $fake_txn->{rules} = $rules;
+ push @{$self->{DryRun}}, $fake_txn;
+ } else {
+ $scrips->Commit;
+ RT::Ruleset->CommitRules($rules);
+ }
+}
+
+
+package RT::Transaction;
+
+my $Create = \&Create;
+*Create = sub {
+ my $self = shift;
+ my %args = (@_);
+ $args{CommitScrips} = 0 if $args{DryRun};
+ my @retval = $Create->($self, %args);
+ push @{$args{DryRun}}, $self if $args{DryRun} and $retval[0];
+
+ return wantarray ? @retval : $retval[0];
+};
+
+
=head1 AUTHOR
sunnavy <sunnavy at bestpractical.com>
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list