[rt-users] EmailParser.pm:ParseEmailAddress - mixing usernames and email addresses

Ruslan Zakirov ruz at bestpractical.com
Thu Mar 21 08:03:17 EDT 2013


On Thu, Mar 21, 2013 at 10:25 AM, Craig Ringer <craig at 2ndquadrant.com> wrote:
> Hi folks
>
> I have a basic module to convert individual users into "customer groups"
> (customer entities modeled as RT groups) ready. It's going well with a few
> limitations and is doing a good job of converting the requestor of tickets
> into a customer group with a scrip. It's here:
> https://github.com/2ndQuadrant/rt-extension-customergroups-perl but hasn't
> been pushed to CPAN as it's not quite feature complete yet.
>
> I'm hoping to enable users to enter customer group names as requestors
> directly. This works when adding watchers after the ticket has been created,
> though RT doesn't autocomplete them in the web ui, but it doesn't seem to be
> possible for ticket creation via the web ui because of the process RT goes
> through to turn the requestor field input into user IDs which converts all
> inputs to email addresses and from there into user IDs:
>
> Create.html: Requestors is string like 'username1, "Freddy Bob
> <email at hostname>'
> -> calls
> Display.html: passed through unchanged
> -> to
> RT::Interface::Web::CreateTicket: Passed through unchanged
> -> to
> RT::Ticket->Create, still as string or as arrayref containing a single
> string entry, where single digit string is treated as username otherwise:
> -> to
> RT::EmailParser->ParseEmailAddress matches a single user name where string
> has no @ symbols or:
> -> to
> Email::Address->parse returns array of email addresses parsed out and
> discards the rest
> -> returns to
> RT::EmailParser->ParseEmailAddress which returns email address array
> -> returns to
> RT::Ticket->Create .. which *converts the email addresses to RT::User
> objects and gets their IDs*
>
> This flow means that RT can't handle requestor lists containing a mix of
> email addresses and user names. There's no way to pass a list of
> RT::User/RT::Group or RT::Principal objects into RT::Ticket->Create, nor can
> you pass more than one RT user name. Presumably that's why RT's user name
> autocomplete in Requestors converts the user into an email address when it's
> autocompleted.

Email addresses are accepted because of how Email::Address parsing
works. As you understand switching over Email::Address::List may help
handle user names, ids or group names with some additional syntax.

> If I was to teach RT::Ticket->Create to accept a RequestorObj array
> containing RT::User and RT::Group objects that can be passed to
> Ticket::_AddWatcher, is that a chance the RT team would be willing to accept
> this change into RT proper? What I want to do is factor out the
> Requestors-string-to-list-of-users conversion from RT::Ticket->Create into
> its own function that can be wrapped or replaced via the RT SiteConfig,
> since right now there's no common point you can hook into ticket creation
> from all paths (SelfService and normal web ui create, email create, import,
> etc).

RT::Ticket->Create accepts ids of principals/users/groups (those share
the same pool of ids and user/group has the same id as her record in
principals).

So it's easy to wrap Create and convert string to array of ids. What
I'm saying is that you have rope to do required transformation.

> I'd also like to introduce callback sites in RT::Ticket->Create, one before
> the ticket entity is created that allows transformation of the %args array
> and one after that takes the %args array and the new $ticket var. Unlike
> RT's existing callbacks these would be simple Perl functions or modules,
> more like @MailPlugins than the Mason callbacks. That way hooks for custom
> behaviour could be more easily added to things like the ticket creation path
> without having to patch the main sources, easing upgrades and making it
> easier to package changes as modules.

While we consider hooks for libs, we still havn't decided which
approach to take and don't have real urge to do this. The following
works just fine for most cases:

{
my $orig = RT::Ticket->can('Create');
*RT::Ticket::Create = sub {
    my $self = shift;
    my %args = @_;
    return $orig->($self, %args);
};
}

This wraps a method and you can change arguments and return values.
Respects other wrappings and inheritance. If it is not enough then you
have access to lower level API.

> (I know you can wrap methods but this isn't very useful for things like
> RT::Ticket->Create where it's one giant monolithic method).

I agree that it's harder to do for bigger methods, but as I said we
are not sure how we want hooks to work. You can prototype hooks
mechanism and publish it for discussion on rt-devel@ list.

> In the mean time I'm living with a few limitations in the code posted above:
>
> - Users can only be a member of one customer group if they submit tickets
> via email; and

My idea was to use Organization field for that. So user has
Organization field and it's filled then RT loads "<Organization>
Organization" group. Also, a wrap on RT::Users *Set methods to put him
into these groups (wrap as there is no scrips for Users).

> - Tickets created via the web ui are created with the requestor as the
> individual user then immediately rewritten by a scrip to use the customer
> group; this rewrite is visible in the logs.

When I was thinking about customers groups as watchers, I thought that
it's not bad to leave user as requestor on the ticket to see him in
the list in UI.

I'm happy that somebody finally implemented this thing. Thank you.

> --
>  Craig Ringer                   http://www.2ndQuadrant.com/
>  PostgreSQL Development, 24x7 Support, Training & Services



-- 
Best regards, Ruslan.



More information about the rt-users mailing list