DefaultCustomFieldValue

From Request Tracker Wiki
Jump to navigation Jump to search

It is possible to have custom fields with default values showing up at edit time.

This example assumes you are using select lists.

First you need to add a callback.

  1. Create the follow directory structure: local/html/Callbacks/CustomFieldDefaultValues/Elements/EditCustomFields
  2. Inside, create the file: MassageCustomFields
  3. Add the following code to the file:
<%init>

unless ($CustomFields) {

    return 1;

}


while (my $customField = $CustomFields->Next) {


    my $id          = $customField->Id;

    my $key         = 'Field-'. $id;

    my $cf_values   =  $customField->ValuesClass;


    ( my $requireName = $cf_values . ".pm" ) =~ s{::}{/}g;


    require $requireName;


    if ($cf_values->can('DefaultValue')) {

        $m->notes($key, $cf_values->DefaultValue());

    }


}


</%init>

<%ARGS>

    $CustomFields => undef

</%ARGS>


Second, you need to go to the custom fields values class, and add the method that will return the default value.

An example:

package RT::CustomFieldValues::CUSTOM_FIELD_NAME;


use strict;

use warnings;


use base qw(RT::CustomFieldValues::External);


sub SourceDescription {

    return 'Ticket distribution (public/private)';

}


sub ExternalValues {

    return [

        {

            name        => "private",

            description => ,

            sortorder   => 0

        },

        {

            name        => "public",

            description => ,

            sortorder   => 1

        }

    ];

}


sub DefaultValue {

    return "private";

}


1;


And thats it. All done.


If you want to read, why, please go on.

If you open the file: /rt-4.2.1/share/html/Elements/EditCustomFields

And read line 63: % my $default = $m->notes('Field-' . $CustomField->Id);

What that does, is to use a mson key value store , for the duration of the request. 

Now read line: 95: $m->callback( %ARGS, CallbackName => 'MassageCustomFields', $CustomFields => $CustomFields );

Since this line is inside the init block, you now have a clear path as to inject default values, to all your custom fields, with your own custom logic.

Just write that callback with your (company) hearts desire.

So in truth, RT is already trying to check for already existing defaults values, in the mason key store. 

And since its a simple key store, you can inject values there from wherever. 

But good practices to keep RT clean, tell me, to use the callback that comes with it.

Another way

Use this scrip to set some CustomField to some value by default.

Note: Default values do not show up at edit time. You need to post the request to see the default values.

Scrip can work with any condition(transaction), but some conditions make more sense then other:

  • On Create - use it if you want default only when people create tickets
  • On Any Transaction - deprecates <no value> at all for particular CF, because when people set CF to <no value> and submit changes than scrip automatically would change value to default.
Description: Set <CF name> to <XXX> by default
Action: User defined
Custom action preparation code: return 1;
Custom action cleanup code:
  my $CFName = 'myCF';
  my $DefaultValue = 'myDefValue';
  my $RecTransaction = 1;

  my $QueueObj = $self->TicketObj->QueueObj;
  my $CFObj = RT::CustomField->new( $QueueObj->CurrentUser );
  $CFObj->LoadByNameAndQueue( Name => $CFName, Queue => $QueueObj->id );
  unless( $CFObj->id ) {
    $CFObj->LoadByNameAndQueue( Name => $CFName, Queue => 0 );
    unless( $CFObj->id ) {
      $RT::Logger->warning("custom field '$CFName' isn't global or defined for queue '". $QueueObj->Name ."'");
      return undef;
    }
  }

  unless( $self->TicketObj->FirstCustomFieldValue( $CFObj->id ) ) {
    my( $st, $msg ) = $self->TicketObj->AddCustomFieldValue(
                                          Field => $CFObj->id,
                                          Value => $DefaultValue,
                                          RecordTransaction => $RecTransaction );
    unless( $st ) {
      $RT::Logger->warning( "Couldn't set $DefaultValue as value for CF $CFName:". $msg );
      return undef;
    }
  }
  return 1;
Template: Global template: Blank

If you'd like to set deafults for a lot of CFs:

my %hash = (
       CF_fu => 'default for CF_fu',
       CF_baar => 'default for CF_baar',
       CF_City => 'Alsobelatelep',
);

while ( my ($CFName , $DefaultValue ) = each(%hash) ) {

 my $RecTransaction = 1;

 my $QueueObj = $self->TicketObj->QueueObj;
 my $CFObj = RT::CustomField->new( $QueueObj->CurrentUser );
 $CFObj->LoadByNameAndQueue( Name => $CFName, Queue => $QueueObj->id );
 unless( $CFObj->id ) {
   $CFObj->LoadByNameAndQueue( Name => $CFName, Queue => 0 );
   unless( $CFObj->id ) {
     $RT::Logger->warning("custom field '$CFName' isn't global or defined for queue '". $QueueObj->Name ."'");
     return undef;
   }
 }

 unless( $self->TicketObj->FirstCustomFieldValue( $CFObj->id ) ) {
   my( $st, $msg ) = $self->TicketObj->AddCustomFieldValue(
                                         Field => $CFObj->id,
                                         Value => $DefaultValue,
                                         RecordTransaction => $RecTransaction );
   unless( $st ) {
     $RT::Logger->warning( "Couldn't set $DefaultValue as value for CF $CFName:". $msg );
     return undef;
   }
 }
}
return 1;

Simpler/Modern form

Queue doesn't seem to include CurrentUser (in modern RTs), so here's a working action variant:

my $CFName = 'myCF';
my $DefaultValue = 'myDefValue';
my $RecTransaction = 1;

unless( $self->TicketObj->FirstCustomFieldValue( $CFName ) ) {
  my( $st, $msg ) = $self->TicketObj->AddCustomFieldValue(
                                        Field => $CFName,
                                        Value => $DefaultValue,
                                        RecordTransaction => $RecTransaction );
  unless( $st ) {
    $RT::Logger->warning( "Couldn't set $DefaultValue as value for CF $CFName:". $msg );
    return undef;
  }
}
return 1;

Yet another way

Defaults that do show up at edit time and are set to the values picked in the last ticket created by this user.

  • Use a specific keyword in the description of the customfields that you want memorized (e.g. "default")
  • Create a scrip as follows:
Description: On Create set custom field defaults
Condition: On Create
Action: User defined
Custom action preparation code: return 1;
Custom action cleanup code:

#capture chosen values for custom fields in an attribute called "cf_defaults"
# we get them in a hash of the form {customfield_id => [one or more values]}

my %cache;
my $ticket = $self->TicketObj;
my $CustomFields = $ticket->QueueObj->TicketCustomFields();
while (my $CustomField = $CustomFields->Next()) {
   my $cfid = $CustomField->Id;
   # only those that contain "default" in the description, all the others
   # won't save defaults:
   next unless $CustomField->Description =~ /default/i;
   my $vals = $ticket->CustomFieldValues($cfid);
   while (my $cfval = $vals->Next){
     push @{$cache{$cfid}}, $cfval->Content;
   }
}
# finished populating %cache

my $user = $self->TransactionObj->CreatorObj; 

if ( my $attr = ($user->Attributes->Named('cf_defaults'))[0]){
    # I don't want to touch the database if nothing's been changed
    # so I need to compare %cache with the actual content
    require Storable; 
    local $Storable::canonical = 1;
    if ( Storable::freeze(\%cache) ne Storable::freeze($attr->Content) ){
        $attr->SetContent(\%cache);
    }
} else {
    $user->AddAttribute( Name => "cf_defaults", Content => \%cache);
}
return 1;


  • Copy .../share/html/Ticket/Elements/EditCustomFields to ../local/htmlTicket/Elements/EditCustomFields. Edit the copy and replace this:
<%INIT>
my $CustomFields;

if ($TicketObj && !$OnCreate) {
    $CustomFields = $TicketObj->CustomFields();
    $NamePrefix .= "Object-RT::Ticket-".$TicketObj->Id."-CustomField-";
} else {
    $CustomFields = $QueueObj->TicketCustomFields();
    $NamePrefix .= "Object-RT::Ticket--CustomField-";
}

...



with this:

<%INIT>
my $CustomFields;

if ($TicketObj && !$OnCreate) {
    $CustomFields = $TicketObj->CustomFields();
    $NamePrefix .= "Object-RT::Ticket-".$TicketObj->Id."-CustomField-";
} else {
    $CustomFields = $QueueObj->TicketCustomFields();
    $NamePrefix .= "Object-RT::Ticket--CustomField-";
    #Iulian
    my $me = $session{'CurrentUser'}->UserObj;
    if(my $attr = ($me->Attributes->Named('cf_defaults'))[0]){
      foreach my $cfid (keys %{$attr->Content}){
        my @vals = @{$attr->Content->{$cfid}};
        $ARGS{"CustomField-". $cfid } = @vals == 1 ? $vals[0] : \@vals;
      }
     }
}

...


Now RT will remember the last chosen customfield values for every user.