Help with Custom Field of the "User" type?

Greetings & Salutations and a Happy New Years to all in the RT Community!

I could use some advice on the following if any of you wouldn’t mind, perhaps there’s some folks who are not too hungover to lend a hand? :slight_smile:

We have LDAP/Active Directory integration and that works great.

I’d like to get the Requester’s Manager into the ticket somehow so it’s easy to see…

I created a custom field of the type “User” and I’m stuck trying to figure out how to add it to the “People” section.

I’d imagine once I update the UI Template to add a CF to People then it would just be a matter of creating a scrip to do the job of updating the CF - On Create?

Or is there a smoother way of doing this with the data model that would hook directly into the user object? (So that we don’t have to worry about updating again if the requester is changed or if the user manager gets updated and that would be updated from the LDAP Import job we have) - if the LDAP Import job runs and if the user object already has a link from Requester --to-> User–to-> CF.Manager then if the LDAP import happens couldn’t that automatically be updated if there’s a referential link? I guess I’m thinking SQL but wondering if there’s a way to do this with custom fields since I see the custom field has a choice of living in the user object and I’m wondering if that integrity already exists?

Any help you could send my way is greatly appreciated as always.

Happy 2024!

You an quite happily have custom fields attached to user objects in RT.

To display your user custom field you could use callbacks. For example there’s a callback called Modify on /Elements/ShowUser that includes a display parameter with the details that it is about to display for that user. I’ve used this before to add extra information to the user displays. As an example, you’d want code in /opt/rt5/local/html/Callbacks/YourNameHere/Elements/ShowUser/Modify that was something like this:

<%ARGS>
$User => undef
$Address => undef
$display => undef;
</%ARGS>
<%INIT>
my $manager = $user->FirstCustomFieldValue('Manager');
if($manager) {
  $$display .= "( Looked after by $manager )";
}
</%INIT>

ISTR the AD has an attribute for a user’s manager, so if you’re using that in your AD (not all organisations do of course) you could potentially pull that into your user CFs from the LDAP Import. This blog post I made about using User CFs might help. It wasn’t dealing with managers, but it might put you on the right track.

Another aproach might be to use a Custom Role, so the manager can be notified via email by scrips.

Anyway, the searching, setting and update of this role on any change is still a scrip(t)ing thing.

https://docs.bestpractical.com/rt/5.0.0/custom_roles.html

I made a little (very little) progress w/this.

By adding UserCF.Manager to my $LDAPMapping I’m able to get the manager on import which is fine except for how the data is returned from AD.

AD returns an entire CN for the manager so this is what I get back -

Any suggestions on how to parse the field and either put it back into this CF or another CF.

I started to look at “Call Backs”. If I want to add User CF to the ticket meta data when browsing the ticket summary (Ticket/Display.html) would this be the correct path?

html/Callbacks/YourNameHere/Ticket/Display.html/Initial

I took a read on CustomizingWithCallbacks - Request Tracker Wiki but it looks like this hasn’t been updated since RT 3.8 → 4.2 days at most.

If I wanted to search all the code for what the most generic stringv that would show me all call backs on current version of RT would I be looking for: $m->callback ?

If I look in Display.html this is what I get back, but what is this actually telling me? How does this relate to the Callbacks directory for writing custom Callbacks?

[user@rt Ticket]# grep callback Display.html
% $m->callback(CallbackName => 'BeforeActionList', %ARGS, Actions => \@Actions, ARGSRef => \%ARGS, Ticket => $TicketObj);
% $m->callback( %ARGS, Ticket => $TicketObj, Transactions => $transactions, Attachments => $attachments, CallbackName => 'BeforeShowSummary' );
% $m->callback( Ticket => $TicketObj, %ARGS, Transactions => $transactions, Attachments => $attachments, CallbackName => 'BeforeShowHistory' );
% $m->callback( %ARGS,
$m->callback( TicketObj => $TicketObj, ARGSRef => \%ARGS, CallbackName => 'Initial' );
        $m->callback( CallbackName => 'BeforeProcessArguments',
        $m->callback(CallbackName => 'ProcessArguments',
$m->callback(

Hi @geraldsnm,

don’t know why I missed your reply.

There is the place where you request the manager from LDAP and insert it into the CF. At this place you should use a regular expression to extract only the part you want.

like this code: (it will not work, I’m not that good in regex. Just for an idea)

$manager = getManagerFromLDAP(placeholder to get the data);
$manager ~= /.*CN=(.*),/;
$user->AddCustomFieldValue(Field => "Manager", Value => $1, RecordTransaction => 1 )

See: perlrequick - Perl regular expressions quick start - Perldoc Browser

This way you can trimm your output in the callback, too.

Thanks so much for your reply! It looks like I’m late to see yours too… I’m fine with writing the regex, the problem I’m having a hard time with understanding is the callback system.

If I could get an example of how a callback should be written (working callback code) for RT 5 that would be extremely helpful in understanding how to code the callback for the manager.

I actually found some sample code for a callback here:

The question I have now is: What defines what these callback files are named? Why is this callback in the example named “BeforeDisplay” ? How can I get a list of these different names, can I parse the code in some way, or can someone give me a high level explanation of the common callback names and what they’re used for?

Here’s a handy wiki article on callbacks. That’s still mostly valid for RT5 - if you want to see all the callbacks in the RT5 code just do something like:

cd /opt/rt5
find share/html | xargs grep -r '\->callback'

You usually pop all your callbacks in a directory tree under your local RT modifications (so something like /opt/rt5/local/html/Callbacks, depending where you installed your RT code). For each task you want to use callbacks for you then create a directory under there called whatever you want (something that hopefully reminds you what you wanted the callback(s) for) and then in that directory have a directory hierarchy to the Mason component(s) that contains the callback(s) you want to use. Then in that last directory you have the file with the callback code itself in, which is either named based on the name specified in the callback call in the RT code, or “Default” if there is no name.

So for example we have a callbacks directory of:

/opt/rt5/local/html/Callbacks/

In there one directory is called JumpToTicketTop, which is for callbacks to let people jump back to the top of tickets being displayed. Under this we have a Ticket directory, and then in that we have directories called Display.html, History.html and ModifyAll.html, which are all the pages we want this set of callbacks to work on. Taking Display.html as an example, inside that directory we have two files, one called AfterShowHistory and the other BeforeActionList - these are the names of the two callbacks in Ticket/Display.html that we want to use.

The /opt/rt5/local/html/Callbacks/JumpToTicketTop/Ticket/Display.html/BeforeActionList just contains:

<a name="top"></a>

and /opt/rt5/local/html/Callbacks/JumpToTicketTop/Ticket/Display.html/AfterShowHistory contains:

<a href="#top">[Back to top of page]</a>

That’s about the simplest example I have on our systems. Callbacks can be a lot more complicated of course - they can have Perl code in them, <INIT> and <ARGS> blocks, call RT’s Perl API, etc. But hopefully this is simple enough to get you going.

Callbacks are incredibly useful and IMHO one of the best aspects of RT. I wish other systems I have to deal with had them. My major grumble is that I wish the arguments passed to them were more standardised, but they’ve grown up over time with different people implementing them, so changing them now would probably break too many installations. I can live with that.


Read and thought about this thing again.

You made it to store the manager at a user-CF. That’s half the way. Now you have at least three options.

  1. is searching the code for the place where the user-information is updated from LDAP, look for a callback or use an overlay to trim the user-CF for your needs and maybe reference another RT-user (the manager)
  2. is to use a Scrip “On Create” to read the manager-information vom requestor’s user-object, extract manager’s name and store it in a ticket-CF (just Text) or Custom Role (a RT user).
  3. is to use a callback while displaying the ticket and trim the manager-output.

If the manager has a user-object himself I would prefer the first idea.

If the manager is just a string you can ommit the first idea and just use a Scrip “On Create” to extract the right part from the user-CF and insert into a ticket-CF.
If the manager is a RT-user you may use “On Create” to set a Custom Role instead of a ticket-CF.

The third idea, trimming the output, is quite crude in my opinion, but possible.

To get an overview of customizing RT use this pages: Customizing - Request Tracker Wiki

The levels of customizing have direct impact to the work you do at the next update:

  • Configuration and Scrips are very robust, they are equal no problems.
  • Callbacks fit very well, there may be the need of some work after an update. The overview written by GreenJimll will lead you.
  • Overlays or ‘local’-directory need dedicated attention every update and sometimes you have to reimplement your customization.

Hope this helps.

A.

1 Like

Thank you both so much for your replies!

I’m actually much closer now…

I was able to add some lines to “local/html/Ticket/Elements/ShowPeople” -

  <div class="form-row manager">
    <div class="label col-3"><&|/l&>Manager</&>:</div>
    <div class="value col-9"><span class="current-value"><& /Elements/ShowCustomFields, %ARGS, Object => $Ticket &></span></div>
  </div>

And that works, sorta… It shows all of the custom fields for the ticket, instead of connecting to the user record of the requester and showing a specific custom field. Now I just need to figure out how to make the connection to the requester and return a specific custom field by name…

I found some lines in the columnmap that may be leading me in the right direction… I’m going to go read the code surrounding these lines now:

./Elements/ColumnMap:                my $key = join( "-", "CF", $user->CustomFieldLookupType, $cf_name );
./Elements/ColumnMap:                    $cf = $user->LoadCustomFieldByIdentifier($cf_name);

Update:

I got this close enough to what I wanted without needing any code modifications at all, and it was all so simple I’m almost ready to kick myself for not realizing it any sooner.

Here’s a step-by-step so that future users may benefit:

#1. I modified the ldap configuration to add the user CF to the mapping for manager:

Set($LDAPMapping, {
 ... ... ...
        'UserCF.Manager'    => 'manager'
});

#2. I added the following to my RT_SiteConfig.pm

Set($MoreAboutRequestorExtraInfo, "'CF.Manager'");

#3. I created “local/html/Ticket/Elements/ShowRequestor”

And changed this line:

    <div id="accordion-requestor-<% $requestor->id %>" class="accordion-content collapse" aria-labelledby="accordion-requestor-<% $requestor->id %>-title">

To this line:

    <div id="accordion-requestor-<% $requestor->id %>" class="accordion-content show collapse" aria-labelledby="accordion-requestor-<% $requestor->id %>-title">

And that got me the information I wanted (mainly manager) on the ticket display page with some added info by automatically expanding “More About The Requestors”… While this isn’t in the “People” section (per my original request) it’s pretty close and without any perl code and only a minor edit to the frontend inline css.

But I learned a bunch in this process. Thanks to all for the helpful hints and the feedback!