Back to my Dynamic template choosing Scrip problem

Hello,

This is not an easy issue to work out - I’m sorry for repeating this
question but last time I answered myself and then realized the answer
wasn’t going to work out. Anyway here goes…

I have a CF called “Classification” where we classify a ticket based on a
scoring system for keywords in fields like From:, Subject: and Content of
an incoming email report. The incident report might be classified as one
of “Phishing”, “Open Recursive DNS” or “Malware” etc. There are currently
12 different classifications and more may need to be added. When opening
an Investigation for an issue the CF “Classification” is used to determine
the template to send to the client containing some helpful information and
what is required of them.

Not only are we dealing with multiple templates but also each one has its
own language. English, French and Spanish. It is very cumbersome to have
3 Scrips for each classification.

Below is 1 example for the “Open Recursive DNS” classification in all
three languages and how it is dealt with currently:

Desc: On Create Customer Open Recursive DNS English
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (en)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;

If English or no language choose English below…

if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘English’ ||
$ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq “”) {

return 1;

}

Desc: On Create Customer Open Recursive DNS French
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (fr)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;
if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘French’) {
return 1;
}

Desc: On Create Customer Open Recursive DNS Spanish
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (es)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;
if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘Spanish’) {
return 1;
}

“OK!? So what’s the problem?” you might ask…

Can anyone tell me how to roll this into one Scrip without making the
templates themselves a mess of spaghetti code?

Pseudo code might be:
Desc: On Create Customer Open Recursive DNS
Condition: User Defined
Action: Autoreply To Requestor
Template: Global template: Blank
Stage: TransactionCreate
Fake Code Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
my $class = $self->FirstCustomFieldValue(‘Classification’);
my $lang = $ticket->FirstCustomFieldValue(‘PreferredLanguage’);
my $template = $class." (“.$lang.”)";
## Eg: Open Recursive DNS (French)
if (SetTheTemplateTo($template)) {
return 1;
}
return 0;

I know SetTheTemplateTo() is not a real function… But that’s what I want to
work out how to do. Basically override or supplement the template set on
the Scrip form.

Landon Stewart :: lstewart@iweb.com
Lead Specialist, Abuse and Security Management
Spécialiste principal, gestion des abus et sécurité
http://iweb.com :: +1 (888) 909-4932

Hi,

You can do this by inserting custom TemplateObj method into
RT/Action/SendMail.pm

It should be like this:

  1. behave like original method, so copy it from lib/RT/Action.pm
  2. change template on call when Ticket and Txn are available
  3. mark that change was done

For example:

sub TemplateObj {
my $self = shift;
return $self->{TemplateObj} if !$self->{TemplateObj}
|| $self->{our_custom_code_has_made_the_change};

my $ticket = $self->TicketObj;
return $self->{TemplateObj} unless $ticket;

my $orig_name = $self->{TemplateObj}->Name;

my $lang = $ticket->FirstCustomFieldValue('Language');
my $case_type = $ticket->FirstCustomFieldValue('Category');
foreach my $name ("$orig_name $case_type $lang", "$orig_name $case_type

$lang") {
my $tmp = RT::Template->new( $self->CurrentUser );
$tmp->Load( $name ); # queue should be here and fallback to global!
unless ($tmp->id) {
RT->Logger->debug(“No custom template $name”);
} else {
$self->{TemplateObj} = $tmp;
}
}
$self->{our_custom_code_has_made_the_change} = 1;
return $self->{TemplateObj};
}

Note that the code is not tested in any way, just typed it in mail client.On Thu, Oct 3, 2013 at 12:59 AM, Landon Stewart lstewart@iweb.com wrote:

Hello,

This is not an easy issue to work out - I’m sorry for repeating this
question but last time I answered myself and then realized the answer
wasn’t going to work out. Anyway here goes…

I have a CF called “Classification” where we classify a ticket based on a
scoring system for keywords in fields like From:, Subject: and Content of
an incoming email report. The incident report might be classified as one
of “Phishing”, “Open Recursive DNS” or “Malware” etc. There are currently
12 different classifications and more may need to be added. When opening
an Investigation for an issue the CF “Classification” is used to determine
the template to send to the client containing some helpful information and
what is required of them.

Not only are we dealing with multiple templates but also each one has its
own language. English, French and Spanish. It is very cumbersome to have
3 Scrips for each classification.

Below is 1 example for the “Open Recursive DNS” classification in all
three languages and how it is dealt with currently:

Desc: On Create Customer Open Recursive DNS English
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (en)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;

If English or no language choose English below…

if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘English’ ||
$ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq “”) {

return 1;

}

Desc: On Create Customer Open Recursive DNS French
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (fr)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;
if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘French’) {
return 1;
}

Desc: On Create Customer Open Recursive DNS Spanish
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (es)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;
if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘Spanish’) {
return 1;
}

“OK!? So what’s the problem?” you might ask…

Can anyone tell me how to roll this into one Scrip without making the
templates themselves a mess of spaghetti code?

Pseudo code might be:
Desc: On Create Customer Open Recursive DNS
Condition: User Defined
Action: Autoreply To Requestor
Template: Global template: Blank
Stage: TransactionCreate
Fake Code Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
my $class = $self->FirstCustomFieldValue(‘Classification’);
my $lang = $ticket->FirstCustomFieldValue(‘PreferredLanguage’);
my $template = $class." (“.$lang.”)";
## Eg: Open Recursive DNS (French)
if (SetTheTemplateTo($template)) {
return 1;
}
return 0;

I know SetTheTemplateTo() is not a real function… But that’s what I want
to work out how to do. Basically override or supplement the template set
on the Scrip form.


Landon Stewart :: lstewart@iweb.com
Lead Specialist, Abuse and Security Management
Spécialiste principal, gestion des abus et sécurité
http://iweb.com :: +1 (888) 909-4932


RT Training in New York, October 8th and 9th:
Training — Best Practical Solutions

Best regards, Ruslan.

Hi Ruslan,

Firstly, thank you! This worked remarkably well. I customized things a
little to have it not be used unless it’s the right type of notification
etc but otherwise it was pretty much right on and works well. My Scrips
are all now deleted and there’s just one in there now for this purpose and
the template is properly selected based on the criteria used to make the
$name variable.

I have one question however… What is the reason for the foreach loop in
this code you provided.On 3 October 2013 04:27, Ruslan Zakirov ruz@bestpractical.com wrote:

Hi,

You can do this by inserting custom TemplateObj method into
RT/Action/SendMail.pm

It should be like this:

  1. behave like original method, so copy it from lib/RT/Action.pm
  2. change template on call when Ticket and Txn are available
  3. mark that change was done

For example:

sub TemplateObj {
my $self = shift;
return $self->{TemplateObj} if !$self->{TemplateObj}
|| $self->{our_custom_code_has_made_the_change};

my $ticket = $self->TicketObj;
return $self->{TemplateObj} unless $ticket;

my $orig_name = $self->{TemplateObj}->Name;

my $lang = $ticket->FirstCustomFieldValue('Language');
my $case_type = $ticket->FirstCustomFieldValue('Category');
foreach my $name ("$orig_name $case_type $lang", "$orig_name

$case_type $lang") {
my $tmp = RT::Template->new( $self->CurrentUser );
$tmp->Load( $name ); # queue should be here and fallback to
global!
unless ($tmp->id) {
RT->Logger->debug(“No custom template $name”);
} else {
$self->{TemplateObj} = $tmp;
}
}
$self->{our_custom_code_has_made_the_change} = 1;
return $self->{TemplateObj};
}

Note that the code is not tested in any way, just typed it in mail client.

On Thu, Oct 3, 2013 at 12:59 AM, Landon Stewart lstewart@iweb.com wrote:

Hello,

This is not an easy issue to work out - I’m sorry for repeating this
question but last time I answered myself and then realized the answer
wasn’t going to work out. Anyway here goes…

I have a CF called “Classification” where we classify a ticket based on a
scoring system for keywords in fields like From:, Subject: and Content of
an incoming email report. The incident report might be classified as one
of “Phishing”, “Open Recursive DNS” or “Malware” etc. There are currently
12 different classifications and more may need to be added. When opening
an Investigation for an issue the CF “Classification” is used to determine
the template to send to the client containing some helpful information and
what is required of them.

Not only are we dealing with multiple templates but also each one has its
own language. English, French and Spanish. It is very cumbersome to have
3 Scrips for each classification.

Below is 1 example for the “Open Recursive DNS” classification in all
three languages and how it is dealt with currently:

Desc: On Create Customer Open Recursive DNS English
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (en)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;

If English or no language choose English below…

if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘English’ ||
$ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq “”) {

return 1;

}

Desc: On Create Customer Open Recursive DNS French
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (fr)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;
if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘French’) {
return 1;
}

Desc: On Create Customer Open Recursive DNS Spanish
Condition: User Defined
Action: Autoreply To Requestor
Template: Open Recursive DNS (es)
Stage: TransactionCreate
Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
return 0 unless $ticket->FirstCustomFieldValue(‘Classification’) eq “Open
Recursive DNS”;
if ($ticket->FirstCustomFieldValue(‘PreferredLanguage’) eq ‘Spanish’) {
return 1;
}

“OK!? So what’s the problem?” you might ask…

Can anyone tell me how to roll this into one Scrip without making the
templates themselves a mess of spaghetti code?

Pseudo code might be:
Desc: On Create Customer Open Recursive DNS
Condition: User Defined
Action: Autoreply To Requestor
Template: Global template: Blank
Stage: TransactionCreate
Fake Code Custom Condition:
my $trans = $self->TransactionObj;
my $ticket = $self->TicketObj;
return 0 unless $trans->Type eq “Create”;
my $class = $self->FirstCustomFieldValue(‘Classification’);
my $lang = $ticket->FirstCustomFieldValue(‘PreferredLanguage’);
my $template = $class." (“.$lang.”)";
## Eg: Open Recursive DNS (French)
if (SetTheTemplateTo($template)) {
return 1;
}
return 0;

I know SetTheTemplateTo() is not a real function… But that’s what I want
to work out how to do. Basically override or supplement the template set
on the Scrip form.


Landon Stewart :: lstewart@iweb.com
Lead Specialist, Abuse and Security Management
Spécialiste principal, gestion des abus et sécurité
http://iweb.com :: +1 (888) 909-4932


RT Training in New York, October 8th and 9th:
Training — Best Practical Solutions


Best regards, Ruslan.

Landon Stewart :: lstewart@iweb.com
Lead Specialist, Abuse and Security Management
Spécialiste principal, gestion des abus et sécurité
http://iweb.com :: +1 (888) 909-4932

Hi,

You can do this by inserting custom TemplateObj method into
RT/Action/SendMail.pm

It should be like this:

  1. behave like original method, so copy it from lib/RT/Action.pm
  2. change template on call when Ticket and Txn are available
  3. mark that change was done

For example:

sub TemplateObj {
my $self = shift;
return $self->{TemplateObj} if !$self->{TemplateObj}
|| $self->{our_custom_code_has_made_the_change};

my $ticket = $self->TicketObj;
return $self->{TemplateObj} unless $ticket;

my $orig_name = $self->{TemplateObj}->Name;

my $lang = $ticket->FirstCustomFieldValue('Language');
my $case_type = $ticket->FirstCustomFieldValue('Category');
foreach my $name ("$orig_name $case_type $lang", "$orig_name

$case_type $lang") {
my $tmp = RT::Template->new( $self->CurrentUser );
$tmp->Load( $name ); # queue should be here and fallback to
global!
unless ($tmp->id) {
RT->Logger->debug(“No custom template $name”);
} else {
$self->{TemplateObj} = $tmp;
}
}
$self->{our_custom_code_has_made_the_change} = 1;
return $self->{TemplateObj};
}

Hi Ruslan,

Firstly, thank you! This worked remarkably well. I customized things a
little to have it not be used unless it’s the right type of notification
etc but otherwise it was pretty much right on and works well. My Scrips
are all now deleted and there’s just one in there now for this purpose and
the template is properly selected based on the criteria used to make the
$name variable.

I have one question however… What is the reason for the foreach loop in
this code you provided.

One update to this… I had to add a line to stop the sub from overriding if
the TransactionObj->Type is not Create

my $ticket = $self->TicketObj;
return $self->{TemplateObj} unless $ticket;
return $self->{TemplateObj} unless $trans->Type eq “Create”;

Without this the template is overridden on correspondence as well.

Landon Stewart :: lstewart@iweb.com
Lead Specialist, Abuse and Security Management
Spécialiste principal, gestion des abus et sécurité
http://iweb.com :: +1 (888) 909-4932

Hi,

You can do this by inserting custom TemplateObj method into
RT/Action/SendMail.pm

It should be like this:

  1. behave like original method, so copy it from lib/RT/Action.pm
  2. change template on call when Ticket and Txn are available
  3. mark that change was done

For example:

sub TemplateObj {
my $self = shift;
return $self->{TemplateObj} if !$self->{TemplateObj}
|| $self->{our_custom_code_has_made_the_change};

my $ticket = $self->TicketObj;
return $self->{TemplateObj} unless $ticket;

my $orig_name = $self->{TemplateObj}->Name;

my $lang = $ticket->FirstCustomFieldValue('Language');
my $case_type = $ticket->FirstCustomFieldValue('Category');
foreach my $name ("$orig_name $case_type $lang", "$orig_name

$case_type $lang") {
my $tmp = RT::Template->new( $self->CurrentUser );
$tmp->Load( $name ); # queue should be here and fallback to
global!
unless ($tmp->id) {
RT->Logger->debug(“No custom template $name”);
} else {
$self->{TemplateObj} = $tmp;
}
}
$self->{our_custom_code_has_made_the_change} = 1;
return $self->{TemplateObj};
}

Hi Ruslan,

Firstly, thank you! This worked remarkably well. I customized things a
little to have it not be used unless it’s the right type of notification
etc but otherwise it was pretty much right on and works well. My Scrips
are all now deleted and there’s just one in there now for this purpose and
the template is properly selected based on the criteria used to make the
$name variable.

I have one question however… What is the reason for the foreach loop in
this code you provided.

Typo in my code made it less clear, it should have been:

foreach my $name (“$orig_name $case_type $lang”, “$orig_name $lang” ) {

}

Idea is to look first for template with more detailed name, then look for
name without case type, but language specific, then fallback to default in
case all are absent.

One update to this… I had to add a line to stop the sub from overriding if

the TransactionObj->Type is not Create

my $ticket = $self->TicketObj;
return $self->{TemplateObj} unless $ticket;
return $self->{TemplateObj} unless $trans->Type eq “Create”;

Without this the template is overridden on correspondence as well.

Without type check you can use this to customize notifications for other
txns, for example “Notify requestor on reply”. I understand why you want it
only for autoreplies. Your choice.

Landon Stewart :: lstewart@iweb.com
Lead Specialist, Abuse and Security Management
Spécialiste principal, gestion des abus et sécurité
http://iweb.com :: +1 (888) 909-4932

Best regards, Ruslan.

Typo in my code made it less clear, it should have been:

foreach my $name (“$orig_name $case_type $lang”, “$orig_name $lang” ) {

}

Idea is to look first for template with more detailed name, then look for
name without case type, but language specific, then fallback to default in
case all are absent.

Oh that makes complete sense now. Thanks again.

Landon Stewart :: lstewart@iweb.com
Lead Specialist, Abuse and Security Management
Spécialiste principal, gestion des abus et sécurité
http://iweb.com :: +1 (888) 909-4932