[Rt-commit] rt branch, 4.2/template-name-instead-of-id, created. rt-4.0.8-575-g6b3c57a

Ruslan Zakirov ruz at bestpractical.com
Wed Nov 21 14:06:36 EST 2012


The branch, 4.2/template-name-instead-of-id has been created
        at  6b3c57a872772da61a27dcfb1d726af9ea52a0fd (commit)

- Log -----------------------------------------------------------------
commit 444e888978a8b57de8521a27d6d4d5576251c869
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Apr 13 02:14:43 2012 +0400

    change Template column in Scrips from id to Name
    
    New code should use $scrip->Template rather than
    ->TemplateObj->Name. Since we apply scrips to multiple
    queues TemplateObj becomes ambiguous, the same Scrip
    may use different template object depending on queue.
    The name stays the same.
    
    Old variant should still work, but I think it's better
    to avoid using TemplateObj without context.

diff --git a/etc/schema.Oracle b/etc/schema.Oracle
index d99fee0..56b02f5 100755
--- a/etc/schema.Oracle
+++ b/etc/schema.Oracle
@@ -142,7 +142,7 @@ CREATE TABLE Scrips (
 	CustomPrepareCode	CLOB,
 	CustomCommitCode	CLOB,
 	Disabled 	NUMBER(11,0) DEFAULT 0 NOT NULL,
-	Template	NUMBER(11,0) DEFAULT 0 NOT NULL,
+	Template	VARCHAR2(200) NOT NULL,
   	Creator 	NUMBER(11,0) DEFAULT 0 NOT NULL,
   	Created 	DATE,
   	LastUpdatedBy 	NUMBER(11,0) DEFAULT 0 NOT NULL,
diff --git a/etc/schema.Pg b/etc/schema.Pg
index 5dc5bcc..dfb5557 100755
--- a/etc/schema.Pg
+++ b/etc/schema.Pg
@@ -231,7 +231,7 @@ CREATE TABLE Scrips (
   CustomPrepareCode text NULL  ,
   CustomCommitCode text NULL  ,
   Disabled integer NOT NULL DEFAULT 0 ,
-  Template integer NOT NULL DEFAULT 0  ,
+  Template varchar(200) NOT NULL,
   Creator integer NOT NULL DEFAULT 0  ,
   Created TIMESTAMP NULL  ,
   LastUpdatedBy integer NOT NULL DEFAULT 0  ,
diff --git a/etc/schema.SQLite b/etc/schema.SQLite
index f06abb6..28b97f2 100755
--- a/etc/schema.SQLite
+++ b/etc/schema.SQLite
@@ -151,7 +151,7 @@ CREATE TABLE Scrips (
   CustomPrepareCode text NULL  ,
   CustomCommitCode text NULL  ,
   Disabled int2 NOT NULL DEFAULT 0 ,
-  Template integer NULL DEFAULT 0 ,
+  Template varchar(200) NOT NULL ,
   Creator integer NULL DEFAULT 0 ,
   Created DATETIME NULL  ,
   LastUpdatedBy integer NULL DEFAULT 0 ,
diff --git a/etc/schema.mysql b/etc/schema.mysql
index 6113334..96373a5 100755
--- a/etc/schema.mysql
+++ b/etc/schema.mysql
@@ -143,7 +143,7 @@ CREATE TABLE Scrips (
   CustomPrepareCode text NULL  ,
   CustomCommitCode text NULL  ,
   Disabled int2 NOT NULL DEFAULT 0 ,
-  Template integer NOT NULL DEFAULT 0  ,
+  Template varchar(200) NOT NULL  ,
   Creator integer NOT NULL DEFAULT 0  ,
   Created DATETIME NULL  ,
   LastUpdatedBy integer NOT NULL DEFAULT 0  ,
diff --git a/lib/RT/Scrip.pm b/lib/RT/Scrip.pm
index fb78a72..d3eb274 100644
--- a/lib/RT/Scrip.pm
+++ b/lib/RT/Scrip.pm
@@ -180,7 +180,7 @@ sub Create {
     $args{'Disabled'} ||= 0;
 
     my ( $id, $msg ) = $self->SUPER::Create(
-        Template               => $template->Id,
+        Template               => $template->Name,
         ScripCondition         => $condition->id,
         ScripAction            => $action->Id,
         Disabled               => $args{'Disabled'},
@@ -269,7 +269,7 @@ sub AddToObject {
         )
     ;
 
-    my $tname = $self->TemplateObj->Name;
+    my $tname = $self->Template;
     my $template = RT::Template->new( $self->CurrentUser );
     $template->LoadQueueTemplate( Queue => $queue? $queue->id : 0, Name => $tname );
     $template->LoadGlobalTemplate( $tname ) if $queue && !$template->id;
@@ -803,7 +803,7 @@ sub SetTemplate {
     return ( 0, $self->loc( "Template '[_1]' not found", $value ) )
       unless $template->Id;
 
-    return $self->_Set( Field => 'Template', Value => $template->Id );
+    return $self->_Set( Field => 'Template', Value => $template->Name );
 }
 
 1;
@@ -1015,7 +1015,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =head2 Template
 
 Returns the current value of Template.
-(In the database, Template is stored as int(11).)
+(In the database, Template is stored as varchar(200).)
 
 
 
@@ -1024,7 +1024,7 @@ Returns the current value of Template.
 
 Set Template to VALUE.
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
-(In the database, Template will be stored as a int(11).)
+(In the database, Template will be stored as a varchar(200).)
 
 
 =cut
@@ -1091,7 +1091,7 @@ sub _CoreAccessible {
         Disabled =>
                 {read => 1, write => 1, sql_type => 5, length => 6,  is_blob => 0,  is_numeric => 1,  type => 'smallint(6)', default => '0'},
         Template =>
-		{read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+		{read => 1, write => 1, sql_type => 12, length => 200,  is_blob => 0,  is_numeric => 0,  type => 'varchar(200)', default => 'Blank'},
         Creator =>
 		{read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
         Created =>
diff --git a/lib/RT/ScripAction.pm b/lib/RT/ScripAction.pm
index 13ab47e..8093653 100644
--- a/lib/RT/ScripAction.pm
+++ b/lib/RT/ScripAction.pm
@@ -197,7 +197,7 @@ sub TemplateObj {
     return undef unless $self->{Template};
     if ( !$self->{'TemplateObj'} ) {
         $self->{'TemplateObj'} = RT::Template->new( $self->CurrentUser );
-        $self->{'TemplateObj'}->LoadById( $self->{'Template'} );
+        $self->{'TemplateObj'}->Load( $self->{'Template'} );
 
         if ( ( $self->{'TemplateObj'}->__Value('Queue') == 0 )
             && $self->{'_TicketObj'} ) {
diff --git a/lib/RT/Shredder/Plugin/Summary.pm b/lib/RT/Shredder/Plugin/Summary.pm
index aa21242..aed6922 100644
--- a/lib/RT/Shredder/Plugin/Summary.pm
+++ b/lib/RT/Shredder/Plugin/Summary.pm
@@ -142,7 +142,7 @@ sub WriteDownScrip {
     my $props = $self->_MakeHash( $args{'Object'} );
     $props->{'Action'} = $args{'Object'}->ActionObj->Name;
     $props->{'Condition'} = $args{'Object'}->ConditionObj->Name;
-    $props->{'Template'} = $args{'Object'}->TemplateObj->Name;
+    $props->{'Template'} = $args{'Object'}->Template;
     $props->{'Queue'} = $args{'Object'}->QueueObj->Name || 'global';
 
     return $self->_WriteDownHash( $args{'Object'}, $props );
diff --git a/share/html/Admin/Scrips/Elements/SelectTemplate b/share/html/Admin/Scrips/Elements/SelectTemplate
index 3bcb212..d0a6a45 100644
--- a/share/html/Admin/Scrips/Elements/SelectTemplate
+++ b/share/html/Admin/Scrips/Elements/SelectTemplate
@@ -63,7 +63,7 @@ $Default => undef
 <%INIT>
 
 my $current;
-$current = $Scrip->TemplateObj->Name if $Scrip;
+$current = $Scrip->Template if $Scrip;
 
 my $global = RT::Templates->new($session{'CurrentUser'});
 $global->LimitToGlobal;
diff --git a/share/html/Elements/RT__Scrip/ColumnMap b/share/html/Elements/RT__Scrip/ColumnMap
index 6f14181..417c91c 100644
--- a/share/html/Elements/RT__Scrip/ColumnMap
+++ b/share/html/Elements/RT__Scrip/ColumnMap
@@ -78,14 +78,14 @@ my $COLUMN_MAP = {
     },
     Template => {
         title     => 'Template', # loc
-        value     => sub { return $_[0]->loc( $_[0]->TemplateObj->Name ) },
+        value     => sub { return $_[0]->loc( $_[0]->Template ) },
     },
     AutoDescription => {
         title     => 'Condition, Action and Template', # loc
         value     => sub { return $_[0]->loc( "[_1] [_2] with template [_3]",
             $_[0]->loc($_[0]->ConditionObj->Name),
             $_[0]->loc($_[0]->ActionObj->Name),
-            $_[0]->loc($_[0]->TemplateObj->Name),
+            $_[0]->loc($_[0]->Template),
         ) },
     },
     Description => {
diff --git a/share/html/Ticket/Elements/PreviewScrips b/share/html/Ticket/Elements/PreviewScrips
index 75fbc45..0f6e820 100644
--- a/share/html/Ticket/Elements/PreviewScrips
+++ b/share/html/Ticket/Elements/PreviewScrips
@@ -67,7 +67,7 @@ return unless $Object;
 %                  @{$Object->Scrips->Prepared};
 %     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->TemplateObj->Name)&>[_1] [_2] with template [_3]</&>
+          <&|/l, loc($scrip->ConditionObj->Name), loc($scrip->ActionObj->Name), loc($scrip->Template)&>[_1] [_2] with template [_3]</&>
           <br />
 %         for my $type (qw(To Cc Bcc)) {
 %             my @addresses =  $scrip->ActionObj->Action->$type();

commit 4868d569ec1932fdc8c4fef379ef499cfc60151e
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Apr 14 00:55:00 2012 +0400

    we don't need `require`s as we have `use`s

diff --git a/lib/RT/Scrip.pm b/lib/RT/Scrip.pm
index d3eb274..364ce85 100644
--- a/lib/RT/Scrip.pm
+++ b/lib/RT/Scrip.pm
@@ -148,7 +148,6 @@ sub Create {
 
     #TODO +++ validate input
 
-    require RT::ScripAction;
     return ( 0, $self->loc("Action is mandatory argument") )
         unless $args{'ScripAction'};
     my $action = RT::ScripAction->new( $self->CurrentUser );
@@ -156,7 +155,6 @@ sub Create {
     return ( 0, $self->loc( "Action '[_1]' not found", $args{'ScripAction'} ) ) 
         unless $action->Id;
 
-    require RT::Template;
     return ( 0, $self->loc("Template is mandatory argument") )
         unless $args{'Template'};
     my $template = RT::Template->new( $self->CurrentUser );
@@ -164,7 +162,6 @@ sub Create {
     return ( 0, $self->loc( "Template '[_1]' not found", $args{'Template'} ) )
         unless $template->Id;
 
-    require RT::ScripCondition;
     return ( 0, $self->loc("Condition is mandatory argument") )
         unless $args{'ScripCondition'};
     my $condition = RT::ScripCondition->new( $self->CurrentUser );

commit bdec3fdb036791f3966ecd737de1ef7ba8c52a06
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Apr 14 01:29:58 2012 +0400

    a test was deleted when .t files were merged
    
    test checks that rightless user still can reach
    from template object to its queue object.

diff --git a/t/api/template.t b/t/api/template.t
index 331d9f9..54b31b1 100644
--- a/t/api/template.t
+++ b/t/api/template.t
@@ -2,12 +2,13 @@
 use warnings;
 use strict;
 
-use RT;
-use RT::Test tests => 10;
+use RT::Test tests => 12;
 
 my $queue = RT::Test->load_or_create_queue( Name => 'Templates' );
 ok $queue && $queue->id, "loaded or created a queue";
 
+use_ok('RT::Template');
+
 {
     my $template = RT::Template->new( RT->SystemUser );
     isa_ok($template, 'RT::Template');
@@ -32,3 +33,11 @@ ok $queue && $queue->id, "loaded or created a queue";
     $template->Load($id);
     ok !$template->id, "can not load template after deletion";
 }
+
+{
+    my $t = RT::Template->new(RT->SystemUser);
+    $t->Create(Name => "Foo", Queue => $queue->id);
+    my $t2 = RT::Template->new(RT->Nobody);
+    $t2->Load($t->Id);
+    ok($t2->QueueObj->id, "Got the template's queue objet");
+}

commit 02ee1050e128859823b577748a09d508cc324a7a
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Mon Apr 16 15:50:36 2012 +0400

    make sure we can not create templates with duplicate names

diff --git a/lib/RT/Template.pm b/lib/RT/Template.pm
index e509454..e2cd96a 100644
--- a/lib/RT/Template.pm
+++ b/lib/RT/Template.pm
@@ -256,6 +256,16 @@ sub Create {
         $args{'Queue'} = $QueueObj->Id;
     }
 
+    return ( undef, $self->loc('Name is required') )
+        unless $args{Name};
+
+    {
+        my $tmp = $self->new( RT->SystemUser );
+        $tmp->LoadByCols( Name => $args{'Name'}, Queue => $args{'Queue'} );
+        return ( undef, $self->loc('Template with that name already exist') )
+            if $tmp->id;
+    }
+
     my $result = $self->SUPER::Create(
         Content     => $args{'Content'},
         Queue       => $args{'Queue'},
diff --git a/t/api/template.t b/t/api/template.t
index 54b31b1..957a8eb 100644
--- a/t/api/template.t
+++ b/t/api/template.t
@@ -4,22 +4,26 @@ use strict;
 
 use RT::Test tests => 12;
 
+use_ok('RT::Template');
+
 my $queue = RT::Test->load_or_create_queue( Name => 'Templates' );
 ok $queue && $queue->id, "loaded or created a queue";
 
-use_ok('RT::Template');
+{
+    my $template = RT::Template->new(RT->SystemUser);
+    isa_ok($template, 'RT::Template');
+}
 
 {
     my $template = RT::Template->new( RT->SystemUser );
-    isa_ok($template, 'RT::Template');
     my ($val,$msg) = $template->Create(
         Queue => $queue->id,
-        Name => 'InsertTest',
+        Name => 'Test',
         Content => 'This is template content'
     );
     ok $val, "created a template" or diag "error: $msg";
     ok my $id = $template->id, "id is defined";
-    is $template->Name, 'InsertTest';
+    is $template->Name, 'Test';
     is $template->Content, 'This is template content', "We created the object right";
 
     ($val, $msg) = $template->SetContent( 'This is new template content');
@@ -34,6 +38,17 @@ use_ok('RT::Template');
     ok !$template->id, "can not load template after deletion";
 }
 
+note "can not create template with duplicate name";
+{
+    clean_templates( Queue => $queue->id );
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($val,$msg) = $template->Create( Queue => $queue->id, Name => 'Test' );
+    ok($val,$msg);
+
+    ($val,$msg) = $template->Create( Queue => $queue->id, Name => 'Test' );
+    ok(!$val,$msg);
+}
+
 {
     my $t = RT::Template->new(RT->SystemUser);
     $t->Create(Name => "Foo", Queue => $queue->id);
@@ -41,3 +56,17 @@ use_ok('RT::Template');
     $t2->Load($t->Id);
     ok($t2->QueueObj->id, "Got the template's queue objet");
 }
+
+sub clean_templates {
+    my %args = (@_);
+
+    my $templates = RT::Templates->new( RT->SystemUser );
+    $templates->Limit( FIELD => 'Queue', VALUE => $args{'Queue'} )
+        if defined $args{'Queue'};
+    $templates->Limit( FIELD => 'Name', VALUE => $_ )
+        foreach ref $args{'Name'}? @{$args{'Name'}} : ($args{'Name'}||());
+    while ( my $t = $templates->Next ) {
+        $t->Delete;
+    }
+}
+

commit ba7e62a0c607f9c38c0ab2face42706e171edeb8
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Mon Apr 16 15:52:32 2012 +0400

    make sure we can not create template without name

diff --git a/t/api/template.t b/t/api/template.t
index 957a8eb..4d1000b 100644
--- a/t/api/template.t
+++ b/t/api/template.t
@@ -38,6 +38,14 @@ ok $queue && $queue->id, "loaded or created a queue";
     ok !$template->id, "can not load template after deletion";
 }
 
+note "can not create template w/o Name";
+{
+    clean_templates( Queue => $queue->id );
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($val,$msg) = $template->Create( Queue => $queue->id );
+    ok(!$val,$msg);
+}
+
 note "can not create template with duplicate name";
 {
     clean_templates( Queue => $queue->id );

commit 8bd0d450f114d54ddea1b3ba4fc184071d40f2a9
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Mon Apr 16 16:13:53 2012 +0400

    test that we can change template name

diff --git a/t/api/template.t b/t/api/template.t
index 4d1000b..c8fa7a6 100644
--- a/t/api/template.t
+++ b/t/api/template.t
@@ -57,6 +57,18 @@ note "can not create template with duplicate name";
     ok(!$val,$msg);
 }
 
+note "change template's name";
+{
+    clean_templates( Queue => $queue->id );
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($val,$msg) = $template->Create( Queue => $queue->id, Name => 'Test' );
+    ok($val,$msg);
+
+    ($val,$msg) = $template->SetName( 'Some' );
+    ok($val,$msg);
+    is $template->Name, 'Some';
+}
+
 {
     my $t = RT::Template->new(RT->SystemUser);
     $t->Create(Name => "Foo", Queue => $queue->id);

commit 2544c3a6f6512c7807167b023ecb06e9e1301682
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Mon Apr 16 16:18:18 2012 +0400

    make sure tmpl's name can't be set to empty or duplicate

diff --git a/lib/RT/Template.pm b/lib/RT/Template.pm
index e2cd96a..91e61db 100644
--- a/lib/RT/Template.pm
+++ b/lib/RT/Template.pm
@@ -632,6 +632,30 @@ sub CurrentUserHasQueueRight {
     return ( $self->QueueObj->CurrentUserHasRight(@_) );
 }
 
+=head2 SetName
+
+Change name of the template.
+
+=cut
+
+sub SetName {
+    my $self = shift;
+    my $value = shift;
+
+    return ( undef, $self->loc('Name is required') )
+        unless $value;
+
+    return $self->_Set( Field => 'Name', Value => $value )
+        if lc($self->Name) eq lc($value);
+
+    my $tmp = $self->new( RT->SystemUser );
+    $tmp->LoadByCols( Name => $value, Queue => $self->Queue );
+    return ( undef, $self->loc('Template with that name already exist') )
+        if $tmp->id;
+
+    return $self->_Set( Field => 'Name', Value => $value );
+}
+
 =head2 SetType
 
 If setting Type to Perl, require the ExecuteCode right.
diff --git a/t/api/template.t b/t/api/template.t
index c8fa7a6..9131d7f 100644
--- a/t/api/template.t
+++ b/t/api/template.t
@@ -69,6 +69,30 @@ note "change template's name";
     is $template->Name, 'Some';
 }
 
+note "can not change name to empty";
+{
+    clean_templates( Queue => $queue->id );
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($val,$msg) = $template->Create( Queue => $queue->id, Name => 'Test' );
+    ok($val,$msg);
+
+    ($val,$msg) = $template->Create( Queue => $queue->id, Name => '' );
+    ok(!$val,$msg);
+    ($val,$msg) = $template->Create( Queue => $queue->id, Name => undef );
+    ok(!$val,$msg);
+}
+
+note "can not change name to duplicate";
+{
+    clean_templates( Queue => $queue->id );
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($val,$msg) = $template->Create( Queue => $queue->id, Name => 'Test' );
+    ok($val,$msg);
+
+    ($val,$msg) = $template->Create( Queue => $queue->id, Name => 'Some' );
+    ok($val,$msg);
+}
+
 {
     my $t = RT::Template->new(RT->SystemUser);
     $t->Create(Name => "Foo", Queue => $queue->id);

commit b98cf3794172c7673d40ff122e6e79c4915283ed
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Mon Apr 16 16:40:37 2012 +0400

    make sure we can not change template's queue
    
    moving templates between queues gonna be too
    complicated

diff --git a/lib/RT/Template.pm b/lib/RT/Template.pm
index 91e61db..86e3153 100644
--- a/lib/RT/Template.pm
+++ b/lib/RT/Template.pm
@@ -632,6 +632,17 @@ sub CurrentUserHasQueueRight {
     return ( $self->QueueObj->CurrentUserHasRight(@_) );
 }
 
+=head2 SetQueue
+
+Changing queue is not implemented.
+
+=cut
+
+sub SetQueue {
+    my $self = shift;
+    return ( undef, $self->loc('Changing queue is not implemented') );
+}
+
 =head2 SetName
 
 Change name of the template.
diff --git a/t/api/template.t b/t/api/template.t
index 9131d7f..a368eef 100644
--- a/t/api/template.t
+++ b/t/api/template.t
@@ -9,6 +9,9 @@ use_ok('RT::Template');
 my $queue = RT::Test->load_or_create_queue( Name => 'Templates' );
 ok $queue && $queue->id, "loaded or created a queue";
 
+my $alt_queue = RT::Test->load_or_create_queue( Name => 'Alternative' );
+ok $alt_queue && $alt_queue->id, 'loaded or created queue';
+
 {
     my $template = RT::Template->new(RT->SystemUser);
     isa_ok($template, 'RT::Template');
@@ -93,6 +96,17 @@ note "can not change name to duplicate";
     ok($val,$msg);
 }
 
+note "changing queue of template is not implemented";
+{
+    clean_templates( Queue => $queue->id );
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($val,$msg) = $template->Create( Queue => $queue->id, Name => 'Test' );
+    ok($val,$msg);
+
+    ($val,$msg) = $template->SetQueue( $alt_queue->id );
+    ok(!$val,$msg);
+}
+
 {
     my $t = RT::Template->new(RT->SystemUser);
     $t->Create(Name => "Foo", Queue => $queue->id);

commit 23ce40d17bc7bb111402f42948f49ab1375c0c6f
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 13 13:10:48 2012 +0400

    RT::Template->LoadByName method
    
    Loads queue's or global template

diff --git a/lib/RT/Scrip.pm b/lib/RT/Scrip.pm
index 364ce85..c3513f8 100644
--- a/lib/RT/Scrip.pm
+++ b/lib/RT/Scrip.pm
@@ -268,8 +268,7 @@ sub AddToObject {
 
     my $tname = $self->Template;
     my $template = RT::Template->new( $self->CurrentUser );
-    $template->LoadQueueTemplate( Queue => $queue? $queue->id : 0, Name => $tname );
-    $template->LoadGlobalTemplate( $tname ) if $queue && !$template->id;
+    $template->LoadByName( Queue => $queue? $queue->id : 0, Name => $tname );
     unless ( $template->id ) {
         if ( $queue ) {
             return (0, $self->loc('No template [_1] in the queue', $tname));
diff --git a/lib/RT/Template.pm b/lib/RT/Template.pm
index 86e3153..dc8c3c3 100644
--- a/lib/RT/Template.pm
+++ b/lib/RT/Template.pm
@@ -151,7 +151,7 @@ Load a template, either by number or by name.
 Note that loading templates by name using this method B<is
 ambiguous>. Several queues may have template with the same name
 and as well global template with the same name may exist.
-Use L</LoadGlobalTemplate> and/or L<LoadQueueTemplate> to get
+Use L</LoadByName>, L</LoadGlobalTemplate> or L<LoadQueueTemplate> to get
 precise result.
 
 =cut
@@ -167,6 +167,37 @@ sub Load {
     return $self->LoadById( $identifier );
 }
 
+=head2 LoadByName
+
+Takes Name and Queue arguments. Tries to load queue specific template
+first, then global. If Queue argument is omitted then global template
+is tried, not template with the name in any queue.
+
+=cut
+
+sub LoadByName {
+    my $self = shift;
+    my %args = (
+        Queue => undef,
+        Name  => undef,
+        @_
+    );
+    my $queue = $args{'Queue'};
+    if ( blessed $queue ) {
+        $queue = $queue->id;
+    } elsif ( $queue =~ /\D/ ) {
+        my $tmp = RT::Queue->new( $self->CurrentUser );
+        $tmp->Load($queue);
+        $queue = $tmp->id;
+    }
+
+    return $self->LoadGlobalTemplate( $args{'Name'} ) unless $queue;
+
+    $self->LoadQueueTemplate( Queue => $queue, Name => $args{'Name'} );
+    return $self->id if $self->id;
+    return $self->LoadGlobalTemplate( $args{'Name'} );
+}
+
 =head2 LoadGlobalTemplate NAME
 
 Load the global template with the name NAME
@@ -185,18 +216,7 @@ sub LoadGlobalTemplate {
 Loads the Queue template named NAME for Queue QUEUE.
 
 Note that this method doesn't load a global template with the same name
-if template in the queue doesn't exist. THe following code can be used:
-
-    $template->LoadQueueTemplate( Queue => $queue_id, Name => $template_name );
-    unless ( $template->id ) {
-        $template->LoadGlobalTemplate( $template_name );
-        unless ( $template->id ) {
-            # no template
-            ...
-        }
-    }
-    # ok, template either queue's or global
-    ...
+if template in the queue doesn't exist. Use L</LoadByName>.
 
 =cut
 

commit 574a97a5940ee3a12c4fd7b4c1c145316edc59ad
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 13 13:11:31 2012 +0400

    more details in an error message

diff --git a/lib/RT/Scrip.pm b/lib/RT/Scrip.pm
index c3513f8..20e793f 100644
--- a/lib/RT/Scrip.pm
+++ b/lib/RT/Scrip.pm
@@ -271,7 +271,8 @@ sub AddToObject {
     $template->LoadByName( Queue => $queue? $queue->id : 0, Name => $tname );
     unless ( $template->id ) {
         if ( $queue ) {
-            return (0, $self->loc('No template [_1] in the queue', $tname));
+            return (0, $self->loc('No template [_1] in queue [_2] or global',
+                    $tname, $queue->Name||$queue->id));
         } else {
             return (0, $self->loc('No global template [_1]', $tname));
         }

commit c683c7132e2a416955a4481aca0b2d74704ae234
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 13 13:12:19 2012 +0400

    undef as default Template arg in Scrip->Create, not 0

diff --git a/lib/RT/Scrip.pm b/lib/RT/Scrip.pm
index 20e793f..841b181 100644
--- a/lib/RT/Scrip.pm
+++ b/lib/RT/Scrip.pm
@@ -107,7 +107,7 @@ sub Create {
     my $self = shift;
     my %args = (
         Queue                  => 0,
-        Template               => 0,                     # name or id
+        Template               => undef,                 # name or id
         ScripAction            => 0,                     # name or id
         ScripCondition         => 0,                     # name or id
         Stage                  => 'TransactionCreate',

commit b32bdda83cb98a1505146d870da1fbbf04135515
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Nov 29 19:44:12 2011 +0400

    IsEmpty column map for templates

diff --git a/share/html/Elements/RT__Template/ColumnMap b/share/html/Elements/RT__Template/ColumnMap
index 5a8c6f2..b3e747d 100644
--- a/share/html/Elements/RT__Template/ColumnMap
+++ b/share/html/Elements/RT__Template/ColumnMap
@@ -78,6 +78,10 @@ my $COLUMN_MAP = {
         title     => 'Queue', # loc
         value     => sub { $_[0]->Queue },
     },
+    IsEmpty => {
+        title     => 'Empty', # loc
+        value     => sub { $_[0]->IsEmpty? $_[0]->loc('Yes') : $_[0]->loc('No') },
+    },
 };
 
 </%ONCE>

commit 77109237f2c3779e2d280f920e2c5da8a518a20b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Nov 29 19:47:40 2011 +0400

    $tmpl->UsedBy, $scrips->LimitByTemplate methods and UsedBy ColumnMap
    
    $scrips->LimitByTemplate - limits to scrips that
    really use particular template, accounts that global
    templates can be overriden.
    
    $tmpl->UsedBy - sugar for above from template side.
    
    UsedBy column map for templates that shows links to
    scrips.

diff --git a/lib/RT/Scrips.pm b/lib/RT/Scrips.pm
index f314fcc..17bffcd 100644
--- a/lib/RT/Scrips.pm
+++ b/lib/RT/Scrips.pm
@@ -147,6 +147,85 @@ sub LimitByStage  {
     );
 }
 
+=head2 LimitByTemplate
+
+Takes a L<RT::Template> object and limits scrips to those that
+use the template.
+
+=cut
+
+sub LimitByTemplate {
+    my $self = shift;
+    my $template = shift;
+
+    $self->Limit( FIELD => 'Template', VALUE => $template->Name );
+
+    if ( $template->Queue ) {
+        # if template is local then we are interested in global and
+        # queue specific scrips
+        $self->LimitToQueue( $template->Queue );
+        $self->LimitToGlobal;
+    }
+    else { # template is global
+
+        # if every queue has a custom version then there
+        # is no scrip that uses the template
+        {
+            my $queues = RT::Queues->new( RT->SystemUser );
+            my $alias = $queues->Join(
+                TYPE   => 'LEFT',
+                ALIAS1 => 'main',
+                FIELD1 => 'id',
+                TABLE2 => 'Templates',
+                FIELD2 => 'Queue',
+            );
+            $queues->Limit(
+                LEFTJOIN   => $alias,
+                ALIAS      => $alias,
+                FIELD      => 'Name',
+                VALUE      => $template->Name,
+            );
+            $queues->Limit(
+                ALIAS      => $alias,
+                FIELD      => 'id',
+                OPERATOR   => 'IS',
+                VALUE      => 'NULL',
+            );
+            return $self->Limit( FIELD => 'id', VALUE => 0 )
+                unless $queues->Count;
+        }
+
+        # otherwise it's either a global scrip or application to
+        # a queue with custom version of the template.
+        my $os_alias = RT::ObjectScrips->new( $self->CurrentUser )
+            ->JoinTargetToThis( $self );
+        my $tmpl_alias = $self->Join(
+            TYPE   => 'LEFT',
+            ALIAS1 => $os_alias,
+            FIELD1 => 'ObjectId',
+            TABLE2 => 'Templates',
+            FIELD2 => 'Queue',
+        );
+        $self->Limit(
+            LEFTJOIN => $tmpl_alias, ALIAS => $tmpl_alias, FIELD => 'Name', VALUE => $template->Name,
+        );
+        $self->Limit(
+            LEFTJOIN => $tmpl_alias, ALIAS => $tmpl_alias, FIELD => 'Queue', OPERATOR => '!=', VALUE => 0,
+        );
+
+        $self->_OpenParen('UsedBy');
+        $self->Limit( SUBCLAUSE => 'UsedBy', ALIAS => $os_alias, FIELD => 'ObjectId', VALUE => 0 );
+        $self->Limit(
+            SUBCLAUSE => 'UsedBy',
+            ALIAS => $tmpl_alias,
+            FIELD => 'id',
+            OPERATOR => 'IS',
+            VALUE => 'NULL',
+        );
+        $self->_CloseParen('UsedBy');
+    }
+}
+
 sub ApplySortOrder {
     my $self = shift;
     my $order = shift || 'ASC';
diff --git a/lib/RT/Template.pm b/lib/RT/Template.pm
index dc8c3c3..18cfafa 100644
--- a/lib/RT/Template.pm
+++ b/lib/RT/Template.pm
@@ -314,6 +314,21 @@ sub Delete {
     return ( $self->SUPER::Delete(@_) );
 }
 
+=head2 UsedBy
+
+Returns L<RT::Scrips> limitted to scrips that use this template. Takes
+into account that template can be overriden in a queue.
+
+=cut
+
+sub UsedBy {
+    my $self = shift;
+
+    my $scrips = RT::Scrips->new( $self->CurrentUser );
+    $scrips->LimitByTemplate( $self );
+    return $scrips;
+}
+
 =head2 IsEmpty
 
 Returns true value if content of the template is empty, otherwise
diff --git a/share/html/Elements/RT__Template/ColumnMap b/share/html/Elements/RT__Template/ColumnMap
index b3e747d..0f09a7e 100644
--- a/share/html/Elements/RT__Template/ColumnMap
+++ b/share/html/Elements/RT__Template/ColumnMap
@@ -82,6 +82,20 @@ my $COLUMN_MAP = {
         title     => 'Empty', # loc
         value     => sub { $_[0]->IsEmpty? $_[0]->loc('Yes') : $_[0]->loc('No') },
     },
+    UsedBy => {
+        title     => 'Used by scrips', # loc
+        value     => sub {
+            my @res;
+            my $scrips = $_[0]->UsedBy;
+            while ( my $scrip = $scrips->Next ) {
+                push @res, ', ' if @res;
+                push @res, \'<a href="', RT->Config->Get('WebPath'), '/Admin/Scrips/Modify.html';
+                push @res, '?id='. $scrip->id;
+                push @res, \'" title="', $scrip->Description, \'">', $scrip->id, \'</a>';
+            }
+            return @res;
+        },
+    },
 };
 
 </%ONCE>

commit f11867ee25890dd2f620682ba6c3eac5109d8f5b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Nov 29 19:48:09 2011 +0400

    show UsedBy and IsEmpty columns in templates AdminUI

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 0a5b761..28c52c0 100755
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -2633,7 +2633,7 @@ Set(%AdminSearchResultFormat,
     Templates =>
         q{'<a href="__WebPath__/__WebRequestPathDir__/Template.html?Queue=__QueueId__&Template=__id__">__id__</a>/TITLE:#'}
         .q{,'<a href="__WebPath__/__WebRequestPathDir__/Template.html?Queue=__QueueId__&Template=__id__">__Name__</a>/TITLE:Name'}
-        .q{,'__Description__'},
+        .q{,'__Description__','__UsedBy__','__IsEmpty__'},
     Classes =>
         q{ '<a href="__WebPath__/Admin/Articles/Classes/Modify.html?id=__id__">__id__</a>/TITLE:#'}
         .q{,'<a href="__WebPath__/Admin/Articles/Classes/Modify.html?id=__id__">__Name__</a>/TITLE:Name'}

commit 373ae8264f3bede0f562e22a6ab094e3d872ca95
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 13 13:41:21 2012 +0400

    tidy, no code change, tiny doc changes
    
    retab, indent, drop useless space only and empty lines,
    drop some comments, several very small doc changes

diff --git a/lib/RT/ScripAction.pm b/lib/RT/ScripAction.pm
index 8093653..e0e962d 100644
--- a/lib/RT/ScripAction.pm
+++ b/lib/RT/ScripAction.pm
@@ -48,21 +48,13 @@
 
 =head1 NAME
 
-  RT::ScripAction - RT Action object
-
-=head1 SYNOPSIS
-
-  use RT::ScripAction;
-
+RT::ScripAction - RT Action object
 
 =head1 DESCRIPTION
 
-This module should never be called directly by client code. it's an internal module which
-should only be accessed through exported APIs in other modules.
-
-
-
-=head1 METHODS
+This module should never be called directly by client code. it's an
+internal module which should only be accessed through exported APIs
+in other modules.
 
 =cut
 
@@ -76,29 +68,29 @@ use base 'RT::Record';
 
 sub Table {'ScripActions'}
 
-
-
 use RT::Template;
 
 sub _Accessible  {
     my $self = shift;
-    my %Cols = ( Name  => 'read',
-		 Description => 'read',
-		 ExecModule  => 'read',
-		 Argument  => 'read',
-		 Creator => 'read/auto',
-		 Created => 'read/auto',
-		 LastUpdatedBy => 'read/auto',
-		 LastUpdated => 'read/auto'
-       );
+    my %Cols = (
+        Name  => 'read',
+        Description => 'read',
+        ExecModule  => 'read',
+        Argument  => 'read',
+        Creator => 'read/auto',
+        Created => 'read/auto',
+        LastUpdatedBy => 'read/auto',
+        LastUpdated => 'read/auto'
+    );
     return($self->SUPER::_Accessible(@_, %Cols));
 }
 
 
+=head1 METHODS
+
 =head2 Create
 
-Takes a hash. Creates a new Action entry.  should be better
-documented.
+Takes a hash. Creates a new Action entry.
 
 =cut
 
@@ -110,7 +102,6 @@ sub Create  {
 
 sub Delete  {
     my $self = shift;
-    
     return (0, "ScripAction->Delete not implemented");
 }
 
@@ -126,25 +117,23 @@ Returns: Id, Error Message
 sub Load  {
     my $self = shift;
     my $identifier = shift;
-    
+
     if (!$identifier) {
-	return (0, $self->loc('Input error'));
-    }	    
-    
+        return (0, $self->loc('Input error'));
+    }
+
     my ($ok, $msg);
     if ($identifier !~ /\D/) {
-	($ok, $msg) = $self->SUPER::Load($identifier);
+        ($ok, $msg) = $self->SUPER::Load($identifier);
     }
     else {
-	($ok, $msg) = $self->LoadByCol('Name', $identifier);
-	
+        ($ok, $msg) = $self->LoadByCol('Name', $identifier);
     }
 
     if (@_) {
-	# Set the template Id to the passed in template    
-	my $template = shift;
-	
-	$self->{'Template'} = $template;
+        # Set the template Id to the passed in template
+        my $template = shift;
+        $self->{'Template'} = $template;
     }
 
     return ($ok, $msg);
@@ -153,33 +142,36 @@ sub Load  {
 
 =head2 LoadAction HASH
 
-  Takes a hash consisting of TicketObj and TransactionObj.  Loads an RT::Action:: module.
+Takes a hash consisting of TicketObj and TransactionObj.  Loads an RT::Action:: module.
 
 =cut
 
 sub LoadAction  {
     my $self = shift;
-    my %args = ( TransactionObj => undef,
-		 TicketObj => undef,
-		 @_ );
+    my %args = (
+        TransactionObj => undef,
+        TicketObj => undef,
+        ScripObj => undef,
+        @_
+    );
 
     $self->{_TicketObj} = $args{TicketObj};
-    
-    #TODO: Put this in an eval  
+
     $self->ExecModule =~ /^(\w+)$/;
     my $module = $1;
     my $type = "RT::Action::". $module;
- 
+
     eval "require $type" || die "Require of $type failed.\n$@\n";
-    
-    $self->{'Action'}  = $type->new ( Argument => $self->Argument,
-                                      CurrentUser => $self->CurrentUser,
-                                      ScripActionObj => $self, 
-                                      ScripObj => $args{'ScripObj'},
-                                      TemplateObj => $self->TemplateObj,
-                                      TicketObj => $args{'TicketObj'},
-                                      TransactionObj => $args{'TransactionObj'},
-				    );
+
+    return $self->{'Action'} = $type->new(
+        Argument => $self->Argument,
+        CurrentUser => $self->CurrentUser,
+        ScripActionObj => $self,
+        ScripObj => $args{'ScripObj'},
+        TemplateObj => $self->TemplateObj,
+        TicketObj => $args{'TicketObj'},
+        TransactionObj => $args{'TransactionObj'},
+    );
 }
 
 
@@ -187,9 +179,6 @@ sub LoadAction  {
 
 Return this action's template object
 
-TODO: Why are we not using the Scrip's template object?
-
-
 =cut
 
 sub TemplateObj {
@@ -217,27 +206,20 @@ sub TemplateObj {
     return ( $self->{'TemplateObj'} );
 }
 
-# The following methods call the action object
-
-
 sub Prepare  {
     my $self = shift;
     $self->{_Message_ID} = 0;
-    return ($self->Action->Prepare());
-  
+    return $self->Action->Prepare();
 }
 
 sub Commit  {
     my $self = shift;
-    return($self->Action->Commit());
-    
-    
+    return $self->Action->Commit();
 }
 
 sub Describe  {
     my $self = shift;
-    return ($self->Action->Describe());
-    
+    return $self->Action->Describe();
 }
 
 =head2 Action
@@ -248,7 +230,7 @@ Return the actual RT::Action object for this scrip.
 
 sub Action {
     my $self = shift;
-    return ($self->{'Action'});
+    return $self->{'Action'};
 }
 
 sub DESTROY {
@@ -258,15 +240,6 @@ sub DESTROY {
     $self->{'TemplateObj'} = undef;
 }
 
-=head2 TODO
-
-Between this, RT::Scrip and RT::Action::*, we need to be able to get rid of a 
-class. This just reeks of too much complexity -- jesse
-
-=cut
-
-
-
 
 =head2 id
 
@@ -274,139 +247,98 @@ Returns the current value of id.
 (In the database, id is stored as int(11).)
 
 
-=cut
-
-
 =head2 Name
 
 Returns the current value of Name.
 (In the database, Name is stored as varchar(200).)
 
-
-
 =head2 SetName VALUE
 
-
 Set Name to VALUE.
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 (In the database, Name will be stored as a varchar(200).)
 
 
-=cut
-
-
 =head2 Description
 
 Returns the current value of Description.
 (In the database, Description is stored as varchar(255).)
 
-
-
 =head2 SetDescription VALUE
 
-
 Set Description to VALUE.
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 (In the database, Description will be stored as a varchar(255).)
 
 
-=cut
-
-
 =head2 ExecModule
 
 Returns the current value of ExecModule.
 (In the database, ExecModule is stored as varchar(60).)
 
-
-
 =head2 SetExecModule VALUE
 
-
 Set ExecModule to VALUE.
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 (In the database, ExecModule will be stored as a varchar(60).)
 
 
-=cut
-
-
 =head2 Argument
 
 Returns the current value of Argument.
 (In the database, Argument is stored as varbinary(255).)
 
-
-
 =head2 SetArgument VALUE
 
-
 Set Argument to VALUE.
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 (In the database, Argument will be stored as a varbinary(255).)
 
 
-=cut
-
-
 =head2 Creator
 
 Returns the current value of Creator.
 (In the database, Creator is stored as int(11).)
 
-
-=cut
-
-
 =head2 Created
 
 Returns the current value of Created.
 (In the database, Created is stored as datetime.)
 
-
-=cut
-
-
 =head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy.
 (In the database, LastUpdatedBy is stored as int(11).)
 
-
-=cut
-
-
 =head2 LastUpdated
 
 Returns the current value of LastUpdated.
 (In the database, LastUpdated is stored as datetime.)
 
-
 =cut
 
 
-
 sub _CoreAccessible {
     {
 
         id =>
-		{read => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
+                {read => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
         Name =>
-		{read => 1, write => 1, sql_type => 12, length => 200,  is_blob => 0,  is_numeric => 0,  type => 'varchar(200)', default => ''},
+                {read => 1, write => 1, sql_type => 12, length => 200,  is_blob => 0,  is_numeric => 0,  type => 'varchar(200)', default => ''},
         Description =>
-		{read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varchar(255)', default => ''},
+                {read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varchar(255)', default => ''},
         ExecModule =>
-		{read => 1, write => 1, sql_type => 12, length => 60,  is_blob => 0,  is_numeric => 0,  type => 'varchar(60)', default => ''},
+                {read => 1, write => 1, sql_type => 12, length => 60,  is_blob => 0,  is_numeric => 0,  type => 'varchar(60)', default => ''},
         Argument =>
-		{read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varbinary(255)', default => ''},
+                {read => 1, write => 1, sql_type => 12, length => 255,  is_blob => 0,  is_numeric => 0,  type => 'varbinary(255)', default => ''},
         Creator =>
-		{read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+                {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
         Created =>
-		{read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
+                {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
         LastUpdatedBy =>
-		{read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
+                {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
         LastUpdated =>
-		{read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
+                {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
 
  }
 };

commit fe59c145a541dd45eb304251ac0bfcecdde5d441
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 13 13:49:51 2012 +0400

    pass arguments further to Action

diff --git a/lib/RT/ScripAction.pm b/lib/RT/ScripAction.pm
index e0e962d..e9717ab 100644
--- a/lib/RT/ScripAction.pm
+++ b/lib/RT/ScripAction.pm
@@ -209,17 +209,17 @@ sub TemplateObj {
 sub Prepare  {
     my $self = shift;
     $self->{_Message_ID} = 0;
-    return $self->Action->Prepare();
+    return $self->Action->Prepare( @_ );
 }
 
 sub Commit  {
     my $self = shift;
-    return $self->Action->Commit();
+    return $self->Action->Commit( @_ );
 }
 
 sub Describe  {
     my $self = shift;
-    return $self->Action->Describe();
+    return $self->Action->Describe( @_ );
 }
 
 =head2 Action

commit 583215493a2700232ecd3a39ecb1d356cc018600
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 13 13:51:57 2012 +0400

    these DESTROY methods are useless
    
    It looks like an atempt to fix memory leak, but really
    it's impossible to fix circular references by sticking
    in custom DESTROY functions around. No object is
    destroyed in a cycle.

diff --git a/lib/RT/Action.pm b/lib/RT/Action.pm
index 31c89ae..83e9de1 100644
--- a/lib/RT/Action.pm
+++ b/lib/RT/Action.pm
@@ -179,19 +179,6 @@ sub IsApplicable  {
   return(undef);
 }
 
-sub DESTROY {
-    my $self = shift;
-
-    # We need to clean up all the references that might maybe get
-    # oddly circular
-    $self->{'ScripActionObj'} = undef;
-    $self->{'ScripObj'} = undef;
-    $self->{'TemplateObj'} =undef
-    $self->{'TicketObj'} = undef;
-    $self->{'TransactionObj'} = undef;
-}
-
-
 RT::Base->_ImportOverlays();
 
 1;
diff --git a/lib/RT/ScripAction.pm b/lib/RT/ScripAction.pm
index e9717ab..d7916d2 100644
--- a/lib/RT/ScripAction.pm
+++ b/lib/RT/ScripAction.pm
@@ -233,14 +233,6 @@ sub Action {
     return $self->{'Action'};
 }
 
-sub DESTROY {
-    my $self=shift;
-    $self->{'_TicketObj'} = undef;
-    $self->{'Action'} = undef;
-    $self->{'TemplateObj'} = undef;
-}
-
-
 =head2 id
 
 Returns the current value of id.
diff --git a/lib/RT/ScripCondition.pm b/lib/RT/ScripCondition.pm
index 4156b69..8e38693 100644
--- a/lib/RT/ScripCondition.pm
+++ b/lib/RT/ScripCondition.pm
@@ -209,16 +209,6 @@ sub IsApplicable  {
 }
 
 
-sub DESTROY {
-    my $self=shift;
-    $self->{'Condition'} = undef;
-}
-
-
-
-
-
-
 
 =head2 id
 

commit 97990d8b464194ececf76eb064aca2b1d43195e0
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 13 17:01:17 2012 +0400

    drop RT::Action->IsApplicable
    
    This was never documented, never used, no code calls it.

diff --git a/lib/RT/Action.pm b/lib/RT/Action.pm
index 83e9de1..798e9f7 100644
--- a/lib/RT/Action.pm
+++ b/lib/RT/Action.pm
@@ -172,13 +172,6 @@ sub Prepare  {
 }
 
 
-#If this rule applies to this transaction, return true.
-
-sub IsApplicable  {
-  my $self = shift;
-  return(undef);
-}
-
 RT::Base->_ImportOverlays();
 
 1;

commit 89fbe2b911c44ac99a440bddf86708dddfd691fb
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 13 17:11:57 2012 +0400

    we don't need to set $self->{'table'}
    
    Since we use Table class methods that return constant table names,
    we don't need to set $self->{'table'}

diff --git a/lib/RT/ScripCondition.pm b/lib/RT/ScripCondition.pm
index 8e38693..474f049 100644
--- a/lib/RT/ScripCondition.pm
+++ b/lib/RT/ScripCondition.pm
@@ -78,13 +78,6 @@ use base 'RT::Record';
 sub Table {'ScripConditions'}
 
 
-
-sub _Init  {
-    my $self = shift; 
-    $self->{'table'} = "ScripConditions";
-    return ($self->SUPER::_Init(@_));
-}
-
 sub _Accessible  {
     my $self = shift;
     my %Cols = ( Name  => 'read',

commit 51991fe0674c236f42d00311e253838a3c0c886c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Sep 14 21:39:19 2012 +0400

    upgrade step for Template column in Scrips table
    
    Convert type of the column in schema.* files and
    in content file turn number into Name.

diff --git a/etc/upgrade/4.1.3/content b/etc/upgrade/4.1.3/content
new file mode 100644
index 0000000..8e907ee
--- /dev/null
+++ b/etc/upgrade/4.1.3/content
@@ -0,0 +1,33 @@
+use strict; use warnings;
+
+our @Initial = (
+    # upgrade Template from id to name
+    sub {
+        require RT::Scrips;
+        my $scrips = RT::Scrips->new( RT->SystemUser );
+        $scrips->UnLimit;
+        while ( my $scrip = $scrips->Next ) {
+            my $id = $scrip->Template;
+            if ( $id =~ /\D/ ) {
+                $RT::Logger->info('Template column for scrip #'. $scrip->id .' already contains characters');
+                next;
+            }
+
+            my $name;
+
+            my $template = RT::Template->new( RT->SystemUser );
+            $template->Load( $id );
+            unless ( $template->id ) {
+                $RT::Logger->error("Scrip #". $scrip->id ." has template set to #$id, but it's not in DB, setting it 'Blank'");
+                $name = 'Blank';
+            } else {
+                $name = $template->Name;
+            }
+
+            my ($status, $msg) = $scrip->_Set( Field => 'Template', Value => $name );
+            unless ( $status ) {
+                $RT::Logger->error("Couldn't set template: $msg");
+            }
+        }
+    },
+);
diff --git a/etc/upgrade/4.1.3/schema.Oracle b/etc/upgrade/4.1.3/schema.Oracle
new file mode 100644
index 0000000..b0b4d4c
--- /dev/null
+++ b/etc/upgrade/4.1.3/schema.Oracle
@@ -0,0 +1,5 @@
+# Template column
+ALTER TABLE Scrips RENAME COLUMN Template TO TemplateOld;
+ALTER TABLE Scrips ADD COLUMN Template VARCHAR2(200) NOT NULL;
+UPDATE TABLE Scrips SET Template = CAST(TemplateOld AS varchar2);
+ALTER TABLE Scrips DROP COLUMN TemplateOld;
\ No newline at end of file
diff --git a/etc/upgrade/4.1.3/schema.Pg b/etc/upgrade/4.1.3/schema.Pg
new file mode 100644
index 0000000..3a12d4d
--- /dev/null
+++ b/etc/upgrade/4.1.3/schema.Pg
@@ -0,0 +1,2 @@
+# Template colum
+ALTER TABLE Scrips ALTER COLUMN Template TYPE varchar(200);
diff --git a/etc/upgrade/4.1.3/schema.mysql b/etc/upgrade/4.1.3/schema.mysql
new file mode 100644
index 0000000..d35d730
--- /dev/null
+++ b/etc/upgrade/4.1.3/schema.mysql
@@ -0,0 +1,2 @@
+# Template column
+ALTER TABLE Scrips CHANGE Template Template varchar(200) NOT NULL;

commit c49a22afb38f514a3fac1c6a35fc689e390d48a2
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Sep 14 23:27:03 2012 +0400

    change how we pass template to RT::Action::*
    
    New way is just passing correct Template object to LoadAction
    module along with other things RT::Actions have access to.
    
    Old way was to pass template name/id as second argument to
    ScripAction->Load (deprecated), then call ScripAction->TemplateObj
    method (deprecated) and call it only from LoadAction as it's only
    place where we have Ticket to get proper queue specific template.
    
    Old code is still there, but it gives warnings.

diff --git a/lib/RT/Rule.pm b/lib/RT/Rule.pm
index b007a4e..be62f96 100644
--- a/lib/RT/Rule.pm
+++ b/lib/RT/Rule.pm
@@ -103,11 +103,10 @@ sub RunScripAction {
 
     my $action = $ScripAction->LoadAction( TransactionObj => $self->TransactionObj,
                                            TicketObj => $self->TicketObj,
+                                           TemplateObj => $template,
                                            %args,
                                        );
 
-    # XXX: fix template to allow additional arguments to be passed from here
-    $action->{'TemplateObj'} = $template;
     $action->{'ScripObj'} = RT::Scrip->new($self->CurrentUser); # Stub. sendemail action really wants a scripobj available
     $action->Prepare or return;
     $action->Commit;
diff --git a/lib/RT/Scrip.pm b/lib/RT/Scrip.pm
index 841b181..a2237fa 100644
--- a/lib/RT/Scrip.pm
+++ b/lib/RT/Scrip.pm
@@ -316,12 +316,8 @@ sub ActionObj {
 
     unless ( defined $self->{'ScripActionObj'} ) {
         require RT::ScripAction;
-
         $self->{'ScripActionObj'} = RT::ScripAction->new( $self->CurrentUser );
-
-        #TODO: why are we loading Actions with templates like this.
-        # two separate methods might make more sense
-        $self->{'ScripActionObj'}->Load( $self->ScripAction, $self->Template );
+        $self->{'ScripActionObj'}->Load( $self->ScripAction );
     }
     return ( $self->{'ScripActionObj'} );
 }
@@ -365,13 +361,11 @@ Retuns an RT::Template object with this Scrip\'s Template
 
 sub TemplateObj {
     my $self = shift;
+    my $queue = shift;
 
-    unless ( defined $self->{'TemplateObj'} ) {
-        require RT::Template;
-        $self->{'TemplateObj'} = RT::Template->new( $self->CurrentUser );
-        $self->{'TemplateObj'}->Load( $self->Template );
-    }
-    return ( $self->{'TemplateObj'} );
+    my $res = RT::Template->new( $self->CurrentUser );
+    $res->LoadByName( Queue => $queue, Name => $self->Template );
+    return $res;
 }
 
 =head2 Stage
@@ -546,9 +540,11 @@ sub Prepare {
 
     my $return;
     eval {
-        $self->ActionObj->LoadAction( ScripObj       => $self,
-                                      TicketObj      => $args{'TicketObj'},
-                                      TransactionObj => $args{'TransactionObj'},
+        $self->ActionObj->LoadAction(
+            ScripObj       => $self,
+            TicketObj      => $args{'TicketObj'},
+            TransactionObj => $args{'TransactionObj'},
+            TemplateObj    => $self->TemplateObj( $args{'TicketObj'}->Queue ),
         );
 
         $return = $self->ActionObj->Prepare();
diff --git a/lib/RT/ScripAction.pm b/lib/RT/ScripAction.pm
index d7916d2..a8d68a9 100644
--- a/lib/RT/ScripAction.pm
+++ b/lib/RT/ScripAction.pm
@@ -131,9 +131,8 @@ sub Load  {
     }
 
     if (@_) {
-        # Set the template Id to the passed in template
-        my $template = shift;
-        $self->{'Template'} = $template;
+        $RT::Logger->warning("Passing in Template as second argument is deprecated");
+        $self->{'Template'} = shift;
     }
 
     return ($ok, $msg);
@@ -155,7 +154,14 @@ sub LoadAction  {
         @_
     );
 
-    $self->{_TicketObj} = $args{TicketObj};
+    # XXX: this whole block goes with TemplateObj method
+    unless ( @_ && exists $args{'TemplateObj'} ) {
+        local $self->{_TicketObj} = $args{TicketObj};
+        $args{'TemplateObj'} = $self->TemplateObj;
+    }
+    else {
+        $self->{'TemplateObj'} = $args{'TemplateObj'};
+    }
 
     $self->ExecModule =~ /^(\w+)$/;
     my $module = $1;
@@ -164,13 +170,10 @@ sub LoadAction  {
     eval "require $type" || die "Require of $type failed.\n$@\n";
 
     return $self->{'Action'} = $type->new(
-        Argument => $self->Argument,
-        CurrentUser => $self->CurrentUser,
+        %args,
+        Argument       => $self->Argument,
+        CurrentUser    => $self->CurrentUser,
         ScripActionObj => $self,
-        ScripObj => $args{'ScripObj'},
-        TemplateObj => $self->TemplateObj,
-        TicketObj => $args{'TicketObj'},
-        TransactionObj => $args{'TransactionObj'},
     );
 }
 
@@ -183,6 +186,8 @@ Return this action's template object
 
 sub TemplateObj {
     my $self = shift;
+    Carp::carp(__PACKAGE__."::TemplateObj is deprecated");
+
     return undef unless $self->{Template};
     if ( !$self->{'TemplateObj'} ) {
         $self->{'TemplateObj'} = RT::Template->new( $self->CurrentUser );

commit ba08e130c55639317d2845c8d3fb121f61e6bb9b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Sep 19 01:29:04 2012 +0400

    check template harder in RT::Scrip->Create

diff --git a/lib/RT/Scrip.pm b/lib/RT/Scrip.pm
index a2237fa..0dd6cc9 100644
--- a/lib/RT/Scrip.pm
+++ b/lib/RT/Scrip.pm
@@ -158,9 +158,22 @@ sub Create {
     return ( 0, $self->loc("Template is mandatory argument") )
         unless $args{'Template'};
     my $template = RT::Template->new( $self->CurrentUser );
-    $template->Load( $args{'Template'} );
-    return ( 0, $self->loc( "Template '[_1]' not found", $args{'Template'} ) )
-        unless $template->Id;
+    if ( $args{'Template'} =~ /\D/ ) {
+        $template->LoadByName( Name => $args{'Template'}, Queue => $args{'Queue'} );
+        return ( 0, $self->loc( "Global template '[_1]' not found", $args{'Template'} ) )
+            if !$template->Id && !$args{'Queue'};
+        return ( 0, $self->loc( "Global or queue specific template '[_1]' not found", $args{'Template'} ) )
+            if !$template->Id;
+    } else {
+        $template->Load( $args{'Template'} );
+        return ( 0, $self->loc( "Template '[_1]' not found", $args{'Template'} ) )
+            unless $template->Id;
+
+        return (0, $self->loc( "Template '[_1]' is not global" ))
+            if !$args{'Queue'} && $template->Queue;
+        return (0, $self->loc( "Template '[_1]' is not global nor queue specific" ))
+            if $args{'Queue'} && $template->Queue && $template->Queue != $args{'Queue'};
+    }
 
     return ( 0, $self->loc("Condition is mandatory argument") )
         unless $args{'ScripCondition'};
diff --git a/t/api/scrip.t b/t/api/scrip.t
index 4cad73a..f1606d2 100644
--- a/t/api/scrip.t
+++ b/t/api/scrip.t
@@ -1,7 +1,7 @@
 
 use strict;
 use warnings;
-use RT::Test tests => 68;
+use RT::Test tests => 74;
 
 my $queue = RT::Test->load_or_create_queue( Name => 'General' );
 ok $queue && $queue->id, 'loaded or created queue';
@@ -113,22 +113,67 @@ note 'modify properties of a scrip';
 my $queue_B = RT::Test->load_or_create_queue( Name => 'B' );
 ok $queue_B && $queue_B->id, 'loaded or created queue';
 
-note 'check applications vs. templates';
+note 'check creation errors vs. templates';
 {
+    my $scrip = RT::Scrip->new(RT->SystemUser);
+    my ($status, $msg) = $scrip->Create(
+        Queue          => $queue->id,
+        ScripAction    => 'User Defined',
+        ScripCondition => 'User Defined',
+        Template       => 'not exist',
+    );
+    ok(!$status, "couldn't create scrip, not existing template");
+
+    ($status, $msg) = $scrip->Create(
+        ScripAction    => 'User Defined',
+        ScripCondition => 'User Defined',
+        Template       => 'not exist',
+    );
+    ok(!$status, "couldn't create scrip, not existing template");
+
+    ($status, $msg) = $scrip->Create(
+        Queue          => $queue->id,
+        ScripAction    => 'User Defined',
+        ScripCondition => 'User Defined',
+        Template       => 54321,
+    );
+    ok(!$status, "couldn't create scrip, not existing template");
+
+    ($status, $msg) = $scrip->Create(
+        ScripAction    => 'User Defined',
+        ScripCondition => 'User Defined',
+        Template       => 54321,
+    );
+    ok(!$status, "couldn't create scrip, not existing template");
+
     my $template = RT::Template->new( RT->SystemUser );
-    my ($status, $msg) = $template->Create( Queue => $queue->id, Name => 'foo' );
+    ($status, $msg) = $template->Create( Queue => $queue->id, Name => 'bar' );
     ok $status, 'created a template';
 
-    my $scrip = RT::Scrip->new(RT->SystemUser);
     ($status, $msg) = $scrip->Create(
-        Queue          => $queue->Id,
         ScripAction    => 'User Defined',
         ScripCondition => 'User Defined',
-        Template       => 'bar',
+        Template       => $template->id,
     );
-    ok(!$status, "couldn't create scrip, incorrect template");
+    ok(!$status, "couldn't create scrip, wrong template");
 
     ($status, $msg) = $scrip->Create(
+        Queue          => $queue_B->id,
+        ScripAction    => 'User Defined',
+        ScripCondition => 'User Defined',
+        Template       => $template->id,
+    );
+    ok(!$status, "couldn't create scrip, wrong template");
+}
+
+note 'check applications vs. templates';
+{
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($status, $msg) = $template->Create( Queue => $queue->id, Name => 'foo' );
+    ok $status, 'created a template';
+
+    my $scrip = RT::Scrip->new(RT->SystemUser);
+    ($status, $msg) = $scrip->Create(
         Queue          => $queue->Id,
         ScripAction    => 'User Defined',
         ScripCondition => 'User Defined',

commit 6600ee55be500f6b2fb2eb6967d180d7171a109f
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Sep 19 17:57:00 2012 +0400

    test Templates in scrips' admin UI

diff --git a/t/web/scrips.t b/t/web/scrips.t
index cf12427..2fbf6d6 100644
--- a/t/web/scrips.t
+++ b/t/web/scrips.t
@@ -11,6 +11,12 @@ RT->Config->Set( UseTransactionBatch => 1 );
 # Test templates?
 # Test cleanup scripts.
 
+my $queue_g = RT::Test->load_or_create_queue( Name => 'General' );
+ok $queue_g && $queue_g->id, 'loaded or created queue';
+
+my $queue_r = RT::Test->load_or_create_queue( Name => 'Regression' );
+ok $queue_r && $queue_r->id, 'loaded or created queue';
+
 my ($baseurl, $m) = RT::Test->started_ok;
 ok $m->login, "logged in";
 
@@ -59,6 +65,7 @@ sub prepare_code_with_value {
             'CustomPrepareCode' => $prepare_code,
         );
         $m->click('Create');
+        $m->content_like(qr{Scrip Created});
     }
 
     my $ticket_obj = RT::Test->create_ticket(
@@ -175,21 +182,74 @@ note "check application in admin interface";
     $m->click_ok("Update", "update scrip application");
     RT::Test->object_scrips_are($sid, []);
 
-    my $queue = RT::Test->load_or_create_queue( Name => 'General' );
-    ok $queue && $queue->id, "loaded queue";
-
     ok $m->form_name("AddRemoveScrip"), "found form";
     $m->tick("AddScrip-$sid", 0);
-    $m->tick("AddScrip-$sid", $queue->id);
+    $m->tick("AddScrip-$sid", $queue_g->id);
     $m->click_ok("Update", "update scrip application");
-    RT::Test->object_scrips_are($sid, [0], [$queue->id]);
+    RT::Test->object_scrips_are($sid, [0], [$queue_g->id, $queue_r->id]);
 }
 
-note "apply scrip in different stage to different queues";
+note "check templates in scrip's admin interface";
 {
-    my $queue = RT::Test->load_or_create_queue( Name => 'Regression' );
-    ok $queue && $queue->id, 'loaded or created queue';
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($status, $msg) = $template->Create( Queue => $queue_g->id, Name => 'foo' );
+    ok $status, 'created a template';
+
+    my @default = (
+          '',
+          'Admin Comment',
+          'Admin Correspondence',
+          'Autoreply',
+          'Blank',
+          'Correspondence',
+          'Email Digest',
+          'Error to RT owner: public key',
+          'Error: bad GnuPG data',
+          'Error: Missing dashboard',
+          'Error: no private key',
+          'Error: public key',
+          'Forward',
+          'Forward Ticket',
+          'PasswordChange',
+          'Resolved',
+          'Status Change',
+          'Transaction'
+    );
+
+    $m->follow_link_ok( { id => 'tools-config-global-scrips-create' } );
+    ok $m->form_name('CreateScrip');
+    my @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
+        ->possible_values;
+    is_deeply(\@templates, \@default);
+
+    $m->follow_link_ok( { id => 'tools-config-queues' } );
+    $m->follow_link_ok( { text => 'General' } );
+    $m->follow_link_ok( { id => 'page-scrips-create' } );
+
+    ok $m->form_name('CreateScrip');
+    my @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
+        ->possible_values;
+    is_deeply([sort @templates], [sort @default, 'foo']);
+
+note "make sure we can not apply scrip to queue without required template";
+    $m->field('Description' => 'test template');
+    $m->select('ScripCondition' => 'On Close');
+    $m->select('ScripAction' => 'Notify Ccs');
+    $m->select('Template' => 'foo');
+    $m->click('Create');
+    $m->content_contains("Scrip Created");
 
+    $m->follow_link_ok( { id => 'page-applies-to' } );
+    my ($id) = ($m->content =~ /Modify associated objects for scrip #(\d+)/);
+    $m->form_name('AddRemoveScrip');
+    $m->tick('AddScrip-'.$id, $queue_r->id);
+    $m->click('Update');
+
+    $m->content_like(qr{No template foo in queue Regression or global});
+}
+
+note "apply scrip in different stage to different queues";
+{
     $m->follow_link_ok( { id => 'tools-config-queues' } );
     $m->follow_link_ok( { text => 'General' } );
     $m->follow_link_ok( { id => 'page-scrips-create'});
@@ -208,7 +268,7 @@ note "apply scrip in different stage to different queues";
     $m->follow_link_ok({ text => 'Applies to' });
     ok $m->form_name('AddRemoveScrip');
     $m->select('Stage' => 'Batch');
-    $m->tick( "AddScrip-$sid" => $queue->id );
+    $m->tick( "AddScrip-$sid" => $queue_r->id );
     $m->click('Update');
     $m->content_contains("Object created");
 

commit 7c99e1498ca6d6cf036e2d13cdb5f6ada069cb50
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 20 18:17:06 2012 +0400

    improve picking template for a scrip
    
    If Scrip is not applied then user can pick any template, so
    he can apply it to particular queue after that.
    
    Present Template picker on /Admin/Scrips/Objects.html page,
    so it's possible to pick new template when scrip is applied
    to a queue.

diff --git a/share/html/Admin/Scrips/Elements/SelectTemplate b/share/html/Admin/Scrips/Elements/SelectTemplate
index d0a6a45..4989709 100644
--- a/share/html/Admin/Scrips/Elements/SelectTemplate
+++ b/share/html/Admin/Scrips/Elements/SelectTemplate
@@ -53,7 +53,6 @@
 ><% loc($name) %></option>
 % }
 </select>
-
 <%ARGS>
 $Name => 'Template'
 $Queue => undef
@@ -65,32 +64,42 @@ $Default => undef
 my $current;
 $current = $Scrip->Template if $Scrip;
 
-my $global = RT::Templates->new($session{'CurrentUser'});
-$global->LimitToGlobal;
+my @list;
+if ( $Scrip && $Scrip->id && !$Scrip->IsAddedToAny ) {
+    my $templates = RT::Templates->new($session{'CurrentUser'});
+    $templates->UnLimit;
+    @list = $templates->DistinctFieldValues('Name');
+} else {
+    my $global = RT::Templates->new($session{'CurrentUser'});
+    $global->LimitToGlobal;
 
-my %global;
-$global{ lc $_ } = $_ foreach map $_->Name, @{ $global->ItemsArrayRef };
+    my %global;
+    $global{ lc $_ } = $_ foreach map $_->Name, @{ $global->ItemsArrayRef };
 
-my @queues;
-push @queues, @{ $Scrip->AddedTo->ItemsArrayRef } if $Scrip && $Scrip->id;
-push @queues, $Queue if $Queue && $Queue->id;
+    my @queues;
+    push @queues, @{ $Scrip->AddedTo->ItemsArrayRef } if $Scrip && $Scrip->id;
+    push @queues, $Queue if $Queue && $Queue->id;
 
-my (%names, %counters);
-foreach my $queue ( @queues ) {
-    my $templates = RT::Templates->new($session{'CurrentUser'});
-    $templates->LimitToQueue( $queue->id );
-    foreach my $name ( map $_->Name, @{ $templates->ItemsArrayRef } ) {
-        next if $global{ lc $name };
-        $counters{ lc $name }++;
-        $names{lc $name} = $name;
+    my (%names, %counters);
+    foreach my $queue ( @queues ) {
+        my $templates = RT::Templates->new($session{'CurrentUser'});
+        $templates->LimitToQueue( $queue->id );
+        foreach my $name ( map $_->Name, @{ $templates->ItemsArrayRef } ) {
+            next if $global{ lc $name };
+            $counters{ lc $name }++;
+            $names{lc $name} = $name;
+        }
     }
+    delete $counters{ $_ }
+        foreach grep $counters{$_} != @queues,
+        keys %counters;
+
+    @list =
+        map $global{$_} || $names{$_},
+        keys %global, keys %counters;
 }
-delete $counters{ $_ }
-    foreach grep $counters{$_} != @queues,
-    keys %counters;
 
-my @list =
-    sort { lc loc($a) cmp lc loc($b) }
-    map $global{$_} || $names{$_},
-    keys %global, keys %counters;
+ at list = sort { lc loc($a) cmp lc loc($b) } @list
+    if @list;
+
 </%INIT>
diff --git a/share/html/Admin/Scrips/Objects.html b/share/html/Admin/Scrips/Objects.html
index e37a319..f356c38 100644
--- a/share/html/Admin/Scrips/Objects.html
+++ b/share/html/Admin/Scrips/Objects.html
@@ -105,6 +105,11 @@
 &>
 
 <& /Admin/Elements/SelectStageForAdded, Default => $Stage &>
+<div style="text-align:right">
+<% loc('You can change template if needed') %>:
+<& Elements/SelectTemplate, Scrip => $scrip, Default => $Template &>
+</div>
+
 % }
 
 <& /Elements/Submit, Name => 'Update' &>
@@ -113,6 +118,7 @@
 <%ARGS>
 $id => undef
 $Stage => undef
+$Template => ''
 $Update => 0
 </%ARGS>
 <%INIT>
@@ -124,6 +130,10 @@ my $global = $scrip->IsGlobal;
 
 if ( $Update ) {
     my (@results);
+    if ( $Template ) {
+        my ($status, $msg) = $scrip->SetTemplate( $Template );
+        push @results, loc('Template: [_1]', $msg);
+    }
     if ( defined (my $del = $ARGS{"RemoveScrip-$id"}) ) {
         foreach my $id ( ref $del? (@$del) : ($del) ) {
             my ($status, $msg) = $scrip->RemoveFromObject( $id );
diff --git a/t/web/scrips.t b/t/web/scrips.t
index 2fbf6d6..f1aef54 100644
--- a/t/web/scrips.t
+++ b/t/web/scrips.t
@@ -227,7 +227,7 @@ note "check templates in scrip's admin interface";
     $m->follow_link_ok( { id => 'page-scrips-create' } );
 
     ok $m->form_name('CreateScrip');
-    my @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
+    @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
         ->possible_values;
     is_deeply([sort @templates], [sort @default, 'foo']);
 
@@ -244,8 +244,37 @@ note "make sure we can not apply scrip to queue without required template";
     $m->form_name('AddRemoveScrip');
     $m->tick('AddScrip-'.$id, $queue_r->id);
     $m->click('Update');
-
     $m->content_like(qr{No template foo in queue Regression or global});
+
+note "unapply the scrip from any queue";
+    $m->form_name('AddRemoveScrip');
+    $m->tick('RemoveScrip-'.$id, $queue_g->id);
+    $m->click('Update');
+    $m->content_like(qr{Object deleted});
+
+note "you can pick any template";
+    $m->follow_link_ok( { id => 'page-basics' } );
+    ok $m->form_name('ModifyScrip');
+    @templates = ($m->find_all_inputs( type => 'option', name => 'Template' ))[0]
+        ->possible_values;
+    is_deeply(
+        [sort @templates],
+        [sort do {
+            my $t = RT::Templates->new( RT->SystemUser );
+            $t->UnLimit;
+            ('', $t->DistinctFieldValues('Name'))
+        }],
+    );
+
+note "go to apply page and apply with template change";
+    $m->follow_link_ok( { id => 'page-applies-to' } );
+    $m->form_name('AddRemoveScrip');
+    $m->field('Template' => 'blank');
+    $m->tick('AddScrip-'.$id, $queue_g->id);
+    $m->tick('AddScrip-'.$id, $queue_r->id);
+    $m->click('Update');
+    $m->content_contains("Template: Template changed from ");
+    $m->content_contains("Object created");
 }
 
 note "apply scrip in different stage to different queues";

commit c8ec075e585457961eea998cb15ee6dadab4592f
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Sep 27 20:53:33 2012 +0400

    make sure you can not delete template in use

diff --git a/lib/RT/Template.pm b/lib/RT/Template.pm
index 18cfafa..cb0012e 100644
--- a/lib/RT/Template.pm
+++ b/lib/RT/Template.pm
@@ -311,6 +311,10 @@ sub Delete {
         return ( 0, $self->loc('Permission Denied') );
     }
 
+    if ( $self->UsedBy->Count ) {
+        return ( 0, $self->loc('Template is in use') );
+    }
+
     return ( $self->SUPER::Delete(@_) );
 }
 
diff --git a/t/api/template.t b/t/api/template.t
index a368eef..8d9cc82 100644
--- a/t/api/template.t
+++ b/t/api/template.t
@@ -2,7 +2,7 @@
 use warnings;
 use strict;
 
-use RT::Test tests => 12;
+use RT::Test tests => 29;
 
 use_ok('RT::Template');
 
@@ -107,6 +107,27 @@ note "changing queue of template is not implemented";
     ok(!$val,$msg);
 }
 
+note "make sure template can not be deleted if it has scrips";
+{
+    clean_templates( Queue => $queue->id );
+    my $template = RT::Template->new( RT->SystemUser );
+    my ($val,$msg) = $template->Create( Queue => $queue->id, Name => 'Test' );
+    ok($val,$msg);
+
+    my $scrip = RT::Scrip->new( RT->SystemUser );
+    ($val,$msg) = $scrip->Create(
+        Queue => $queue->id,
+        ScripCondition => "On Create",
+        ScripAction => 'Autoreply To Requestors',
+        Template => $template->Name,
+    );
+    ok($val, $msg);
+
+    ($val, $msg) = $template->Delete;
+    ok(!$val,$msg);
+}
+
+
 {
     my $t = RT::Template->new(RT->SystemUser);
     $t->Create(Name => "Foo", Queue => $queue->id);

commit bddbca3dbae4807d4823ccdc9a56fc530c83f55d
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Nov 21 16:53:18 2012 +0400

    fix shredding templates
    
    Scrip now stores template name. We shouldn't delete
    all scrips that reference the name, but only those
    that actually use the template. Likely we have method
    for that already.

diff --git a/lib/RT/Shredder/Template.pm b/lib/RT/Shredder/Template.pm
index 415fda0..9a8b284 100644
--- a/lib/RT/Shredder/Template.pm
+++ b/lib/RT/Shredder/Template.pm
@@ -69,9 +69,7 @@ sub __DependsOn
     my $list = [];
 
 # Scrips
-    my $objs = RT::Scrips->new( $self->CurrentUser );
-    $objs->Limit( FIELD => 'Template', VALUE => $self->Id );
-    push( @$list, $objs );
+    push( @$list, $self->UsedBy );
 
     $deps->_PushDependencies(
         BaseObject => $self,

commit 6b3c57a872772da61a27dcfb1d726af9ea52a0fd
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Nov 21 17:00:52 2012 +0400

    validator fix: Template in Scrips now references Name

diff --git a/sbin/rt-validator.in b/sbin/rt-validator.in
index a06f53b..15fce50 100644
--- a/sbin/rt-validator.in
+++ b/sbin/rt-validator.in
@@ -789,7 +789,7 @@ push @CHECKS, Scrips => sub {
         'Scrips', 'ScripAction' => 'ScripActions', 'id',
     );
     check_integrity(
-        'Scrips', 'Template' => 'Templates', 'id',
+        'Scrips', 'Template' => 'Templates', 'Name',
     );
     check_integrity(
         'ObjectScrips', 'Scrip' => 'Scrips', 'id',

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


More information about the Rt-commit mailing list