Overriding ObjectCustomFIeldValue _FillInTemplateUrl method not working with ObjectCustomFieldValue_Local.pm file

Dear all,

I’ve been fighting with this issue for a bit so thought i would post it here just in case.

I have been trying to build my integration between RequestTracker and MeshCentral, and when you go to a device in MeshCentral, the url is like:

https://meshurl.com/blah?gotonode=

So I figured, great, I will use the Custom Field on Assets Integration feature, “RT can make this custom field’s values into hyperlinks to another service.”. I hooked it up but it turns out that this field when made into a URL performs URL encoding which breaks my MeshCentral URL because some IDs have $ etc characters in them.

I tracked down this feature to /opt/rt6/lib/RT/ObjectCustomFieldValue.pm

{
my %placeholders = (
    id          => { value => sub { $_[0]->ObjectId }, escape => 1 },
    CustomField => { value => sub { $_[0]->Content }, escape => 0 },
    WebDomain   => { value => sub { RT->Config->Get('WebDomain') } },
    WebPort     => { value => sub { RT->Config->Get('WebPort') } },
    WebPath     => { value => sub { RT->Config->Get('WebPath') } },
    WebBaseURL  => { value => sub { RT->Config->Get('WebBaseURL') } },
    WebURL      => { value => sub { RT->Config->Get('WebURL') } },
);

sub _FillInTemplateURL {
    my $self = shift;
    my $url = shift;

    return undef unless defined $url && length $url;

    # special case, whole value should be an URL
    if ( $url =~ /^__CustomField__/ ) {
        my $value = $self->Content;
        $value //= '';
        # protect from potentially malicious URLs
        if ( $value =~ /^\s*(?:javascript|data):/i ) {
            my $object = $self->Object;
            $RT::Logger->error(
                "Potentially dangerous URL type in custom field '". $self->CustomFieldObj->Name ."'"
                ." on ". ref($object) ." #". $object->id
            );
            return undef;
        }
        $url =~ s/^__CustomField__/$value/;
    }

    # default value, uri-escape
    for my $key (keys %placeholders) {
        $url =~ s{__${key}__}{
            my $value = $placeholders{$key}{'value'}->( $self );
            $value //= '';
            RT::Interface::Web::EscapeURI(\$value) if $placeholders{$key}{'escape'};
            $value
        }gxe;
    }

    return $url;
} }

so I tried to override by placing a file /opt/rt6/local/lib/RT/ObjectCustomFieldValue_Local.pm

root@web0:~# cat /opt/rt6/local/lib/RT/ObjectCustomFieldValue_Local.pm
no warnings qw(redefine);

my %placeholders = (
    id          => { value => sub { $_[0]->ObjectId }, escape => 1 },
    CustomField => { value => sub { $_[0]->Content } },
    WebDomain   => { value => sub { RT->Config->Get('WebDomain') } },
    WebPort     => { value => sub { RT->Config->Get('WebPort') } },
    WebPath     => { value => sub { RT->Config->Get('WebPath') } },
    WebBaseURL  => { value => sub { RT->Config->Get('WebBaseURL') } },
    WebURL      => { value => sub { RT->Config->Get('WebURL') } },
);

sub _FillInTemplateURL {
    my $self = shift;
    my $url = shift;

    return undef unless defined $url && length $url;

    # special case, whole value should be an URL
    if ( $url =~ /^__CustomField__/ ) {
        my $value = $self->Content;
        $value //= '';
        # protect from potentially malicious URLs
        if ( $value =~ /^\s*(?:javascript|data):/i ) {
            my $object = $self->Object;
            $RT::Logger->error(
                "Potentially dangerous URL type in custom field '". $self->CustomFieldObj->Name ."'"
                ." on ". ref($object) ." #". $object->id
            );
            return undef;
        }
        $url =~ s/^__CustomField__/$value/;
    }

    # default value, uri-escape
    for my $key (keys %placeholders) {
        $url =~ s{__${key}__}{
            my $value = $placeholders{$key}{'value'}->( $self );
            $value //= '';
            RT::Interface::Web::EscapeURI(\$value) if $placeholders{$key}{'escape'};
            $value
        }gxe;
    }

    return $url;
}

1;

Howver it doesn’t seem to override. I tried manually changing /opt/rt6/lib/RT/ObjectCustomFieldValue.pm to suit my wishes, and my feature works, but i dont want my change to get overridden on update. Indeed i want to package my changes into a plugin in the future.

My question is, and my perl is not the best - is it not being overridden because of an error I made, or is it because the function is inside a scope block {} ? Could anyone shed any light here :slight_smile:

I’ve modified only a few files and I never added any _Local suffix to them. So, try renaming to /opt/rt6/local/lib/RT/ObjectCustomFieldValue.pm and clean Mason cache just in case.