Edgewall Software
Modify

Opened 16 years ago

Closed 16 years ago

#7562 closed enhancement (fixed)

AutoQuery as a patch to trac

Reported by: jhammel@… Owned by: Christopher Lenz
Priority: normal Milestone: 0.12
Component: ticket system Version: 0.12dev
Severity: normal Keywords:
Cc: osimons Branch:
Release Notes:
API Changes:
Internal Changes:

Description

The th:AutoQueryPlugin, which provides links to trac's query interface based on field name and value in the ticket box, may be implemented as a simple patch to trac.

see http://groups.google.com/group/trac-dev/msg/9bd18f28e6ff930b for discussion of the issue

The original ticket is th:#3226

Patch attached

Attachments (11)

autoquery_patch_vs_r7349.txt (3.4 KB ) - added by jhammel@… 16 years ago.
patch to trac trunk r7249
autoquery_patch_linkknownusers_r7499.txt (2.2 KB ) - added by Jeff Hammel <jhammel@…> 16 years ago.
patch to limit linking only to known users vs @7499
autoquery_patch_dontlinkownerreporter_r7499.txt (1.3 KB ) - added by Jeff Hammel <jhammel@…> 16 years ago.
patch to eliminate linking to the owner and reporter of tickets vs r7499
autoquery_patch_dontlinkobfuscated_r7499.txt (2.2 KB ) - added by Jeff Hammel <jhammel@…> 16 years ago.
improved version of attachment:autoquery_patch_linkknownusers_r7499.txt that uses Chrome.format_author for checking changes
autoquery_patch_dontlinkobfuscated_r7499b.diff (2.0 KB ) - added by osimons 16 years ago.
Same patch, just a little less verbose.
autoquery_patch_r7508.diff (3.7 KB ) - added by Jeff Hammel <jhammel@…> 16 years ago.
link checkboxes and don't link textareas
autoquery_patch_linked_fields_r7508.diff (4.3 KB ) - added by Jeff Hammel <jhammel@…> 16 years ago.
use linked_fields instead of unlinked_fields
t7562-autoquery_tweaks_r7548.diff (6.0 KB ) - added by osimons 16 years ago.
Cumulated tweaks + word linking.
t7562-autoquery_tweaks-r7548b.diff (6.0 KB ) - added by osimons 16 years ago.
Oops. Missed one unlinked reference. Use this cumulative patch, please - ignore previous.
t7562-autoquery_tweaks-r7548c.diff (6.1 KB ) - added by osimons 16 years ago.
Updated cumulative patch without test failures (previous tried to split None type)
t7562-autoquery_tweaks-r7557.diff (7.0 KB ) - added by osimons 16 years ago.
Cumulative patch using new parse_query_string.

Download all attachments as: .zip

Change History (51)

by jhammel@…, 16 years ago

patch to trac trunk r7249

comment:1 by Christopher Lenz, 16 years ago

Milestone: 0.12
Status: newassigned

comment:2 by osimons, 16 years ago

Patch seems to be committed to trunk in [7499], but I have some minor problems with it.

The patch conflicts with the efforts to provide e-mail obfuscation as fields like authorinfo(ticket.reporter) (and owner) that did obfuscation depending on permissions are now links that naturally must link to the true value to be meaningful.

At the very least, EMAIL_VIEW permissions should be checked before rendering links for owner and reporter. Additionally 'owner' and 'reporter' could be default for fields to not link-ify. On the subject of defaults, I don't quite see why ['estimatedhours', 'hours', 'totalhours'] should be Trac defaults?

comment:3 by Christopher Lenz, 16 years ago

Resolution: fixed
Status: assignedclosed

Patch applied in [7499]. Thanks!

in reply to:  2 comment:4 by Jeff Hammel <jhammel@…>, 16 years ago

Replying to osimons:

Patch seems to be committed to trunk in [7499], but I have some minor problems with it.

The patch conflicts with the efforts to provide e-mail obfuscation as fields like authorinfo(ticket.reporter) (and owner) that did obfuscation depending on permissions are now links that naturally must link to the true value to be meaningful.

I hadn't noticed this before and will look into it now.

At the very least, EMAIL_VIEW permissions should be checked before rendering links for owner and reporter. Additionally 'owner' and 'reporter' could be default for fields to not link-ify.

Or not link-ify if they are email-addresses. I have a hunch these should be rendered fields which don't get auto-link-ified, but am not sure without further investigation.

On the subject of defaults, I don't quite see why ['estimatedhours', 'hours', 'totalhours'] should be Trac defaults?

These are fields used by the TimingAndEstimationPlugin which are marked-up using JS. Now that the patch is in trac-core, hopefully the plugin authors can be persuaded to not do things this way. I will ticket the plugin soon, after investigation

comment:5 by osimons, 16 years ago

Resolution: fixed
Status: closedreopened

Reopening for now until remaining issues reach some conclusion.

in reply to:  5 ; comment:6 by Jeff Hammel <jhammel@…>, 16 years ago

Replying to osimons:

Reopening for now until remaining issues reach some conclusion.

Found the problem with osimons' help (haven't yet fixed yet):

I remove the call to authorinfo; this needs to be put back in for anonymizing

comment:7 by osimons, 16 years ago

While testing, just adding some other nits discovered:

  • It renders link for all fields before alternative rendering is applied. That means a checkbox that renders as 'yes' and 'no' does not get a link as that custom rendering replaces the content later in the code. It should link to 0 and 1, and keep the text it gets from whatever translation is used by the user.
  • cc~=$USER is part of default_anonymous_query (although not working correctly), but as jhammel correctly points out, it does not make sense when the whole point of this setting is that the user is unknown (anonymous). It should be removed from default setting in query module.
  • It linkifies any field, including custom fields of type text and textarea. For most use cases that will not be a useful behaviour. Also, see #1791 for the future of linking in text and textareas.

by Jeff Hammel <jhammel@…>, 16 years ago

patch to limit linking only to known users vs @7499

by Jeff Hammel <jhammel@…>, 16 years ago

patch to eliminate linking to the owner and reporter of tickets vs r7499

in reply to:  6 ; comment:8 by Jeff Hammel <jhammel@…>, 16 years ago

Replying to Jeff Hammel <jhammel@…>:

Replying to osimons:

Reopening for now until remaining issues reach some conclusion.

Found the problem with osimons' help (haven't yet fixed yet):

I remove the call to authorinfo; this needs to be put back in for anonymizing

I have included two patches that solve this problem in different ways:

Anther possibility is to have _query_link just return the url that is linked to and give this as an optional parameter to authorinfo which will markup the link if the reporter or owner is not anonymous. I haven't coded this yet, but if there is interest, I will

The easiest solution would be a check something like

<py:choose test="ticket['reporter'] == authorinfo(ticket['reporter'])">
<py:when test="True">${reporter_link}</py:when>
<py:otherwise>${authorinfo(ticket['reporter'])}</py:otherwise>
</py:choose>

However, since authorinfo lives in a macro and not in python-land, this won't work. I'd prefer if authorinfo lived in python-land, but don't understand why it doesn't and this may involve changing a fair amount (don't know, haven't tried it)

by Jeff Hammel <jhammel@…>, 16 years ago

improved version of attachment:autoquery_patch_linkknownusers_r7499.txt that uses Chrome.format_author for checking changes

in reply to:  8 ; comment:9 by Jeff Hammel <jhammel@…>, 16 years ago

Replying to Jeff Hammel <jhammel@…>:

With osimons' suggestion to use format_author as a test, I wrote a better version of this patch that should have the correct logic: attachment:autoquery_patch_dontlinkobfuscated_r7499.txt

This is my recommended solution, FWIW

by osimons, 16 years ago

Same patch, just a little less verbose.

in reply to:  9 ; comment:10 by osimons, 16 years ago

Replying to Jeff Hammel <jhammel@…>:

This is my recommended solution, FWIW

Yeah, that seems to handle the obfuscation issue nicely. I attached a slightly less verbose version of the patch.

in reply to:  10 comment:11 by Jeff Hammel <jhammel@…>, 16 years ago

Replying to osimons:

Replying to Jeff Hammel <jhammel@…>:

This is my recommended solution, FWIW

Yeah, that seems to handle the obfuscation issue nicely. I attached a slightly less verbose version of the patch.

looks good to me

in reply to:  7 comment:12 by Jeff Hammel <jhammel@…>, 16 years ago

Replying to osimons:

While testing, just adding some other nits discovered:

  • It renders link for all fields before alternative rendering is applied. That means a checkbox that renders as 'yes' and 'no' does not get a link as that custom rendering replaces the content later in the code. It should link to 0 and 1, and keep the text it gets from whatever translation is used by the user.

I hadn't thought about non-text custom fields. I'll look at this next.

  • cc~=$USER is part of default_anonymous_query (although not working correctly), but as jhammel correctly points out, it does not make sense when the whole point of this setting is that the user is unknown (anonymous). It should be removed from default setting in query module.

+1; FWIW, the cc~=$USER doesn't seem to hurt anything that this patch does (that is, the query results are correct), but I'd like to see it gone. Another approach would be to have a separate Option for default_auto_query (or what not) that is separate, but I'd prefer to keep the number of options to the minimum.

  • It linkifies any field, including custom fields of type text and textarea. For most use cases that will not be a useful behaviour. Also, see #1791 for the future of linking in text and textareas.

IMHO, textarea fields should not be linkified; I can see custom text fields as being useful to link to sometimes. Not sure if programmatic distinction can be made between potentially useful custom fields and non-useful custom fields as far as linking. Another option is to use the existing unlinked_fields option to specify non-useful fields. Or, the reverse — this Option could become linked_fields which by default contains the trac core fields, then other fields aren't linked unless they are added. What do people think of this?

comment:13 by Remy Blank, 16 years ago

I agree that textarea fields should never be linkified, and I would also tend to say that text fields should not be linkified either, except for "reporter" and "owner". So +1 for a linked_fields option with a default of "all core non-text fields plus reporter and owner".

Another issue, checkbox fields are currently not linkified. Any reason why this should not be done, or is this just an oversight (there's a special case for _type == 'checkbox' at the bottom of _prepare_fields() that overrides the linkification)?

comment:14 by osimons, 16 years ago

Well… Both linked and unlinked has its pros and cons for text fields. Textarea excluded of course, but perhaps also having non-core text fields off by default is the least obtrusive.

The issue with checkbox was noted in comment:7, and yes, those should be linked of course.

in reply to:  13 ; comment:15 by Jeff Hammel <jhammel@…>, 16 years ago

Replying to rblank:

I agree that textarea fields should never be linkified, and I would also tend to say that text fields should not be linkified either, except for "reporter" and "owner". So +1 for a linked_fields option with a default of "all core non-text fields plus reporter and owner".

Another issue, checkbox fields are currently not linkified. Any reason why this should not be done, or is this just an oversight (there's a special case for _type == 'checkbox' at the bottom of _prepare_fields() that overrides the linkification)?

The reason checkbox fields aren't linked is just oversight — the links are put into a field's rendered attribute at the top of _prepare_fields with the idea that anything that overrides rendered should be used instead. With checkboxes, this is not the desired behavior and additional linking code should be done (around http://trac.edgewall.org/browser/trunk/trac/ticket/web_ui.py#L1151).

My proposal for an additional patch:

  • fix the checkbox linking — they should link
  • never link text areas
  • change unlinked_fields to linked_fields with the defaults given in comment:13; maybe this should only apply to text fields (though linked_text_fields is a bit longish for an option name, though of course the behavior could be noted in the Option description).

How does this sound? If there is no huge controversy, I'd like to upload a patch early next week.

in reply to:  15 ; comment:16 by Remy Blank, 16 years ago

Replying to Jeff Hammel <jhammel@…>:

How does this sound? If there is no huge controversy, I'd like to upload a patch early next week.

Sounds great! I would keep it as linked_fields, so you can disable linking for any type of field (if you wish).

by Jeff Hammel <jhammel@…>, 16 years ago

Attachment: autoquery_patch_r7508.diff added

link checkboxes and don't link textareas

comment:17 by Jeff Hammel <jhammel@…>, 16 years ago

i added a patch that fixes the checkbox (link these) and textarea (don't link these) behavior: attachment:autoquery_patch_r7508.diff (this also includes attachment:autoquery_patch_dontlinkobfuscated_r7499b.diff); for this patch, i've kept it unlinked_fields though my next task is to write a patch that switches this to linked fields

by Jeff Hammel <jhammel@…>, 16 years ago

use linked_fields instead of unlinked_fields

comment:18 by Jeff Hammel <jhammel@…>, 16 years ago

i've made a patch that uses a list of fields to link to (linked_fields) versus the previous fields not to link to (unlinked_fields): attachment:autoquery_patch_linked_fields_r7508.diff

though now that i've done this, i think this is the wrong approach, perhaps. Currently, the patch is pretty dumb — it doesn't do anything based on the type of field (except it won't link textareas). so if you add a new custom field of any type, it won't be linked to unless you explicitly add it. One alternative is to make linking smarter — link all fields except text fields in all cases, only link text fields if they are listed in linked_fields. This way, adding a new text field never links whereas adding a select, checkbox, or radio button would automatically link. However, this gives no mechanism to not link select, checkbox, or radio button fields. Maybe this isn't a big deal (I know I wouldn't care if I couldn't unlink these fields, but don't know if this feeling is universal).

The alternative is just to go with unlinked fields — link everything by default except textareas. The drawback to this approach is if a new custom text field is added, it will be linked to until added to unlinked_fields. [One alternative to this is just not to link any text fields except owner and reporter].

I suppose my feelings aren't dramatically strong between these two options. I suppose my gut reaction would be to link everything except text fields unless they are explicitly mentioned in linked_fields.

In any case, once this decision is made, maybe a final patch is made and applied, if any cruft remains regarding th:TimingAndEstimationPlugin (hours, estimatedhours, totalhours) it should be removed and any associated issue ticketed with that plugin (as has been correctly pointed out, stuff in trac core should not refer to outside plugins).

in reply to:  16 ; comment:19 by Jeff Hammel <jhammel@…>, 16 years ago

Replying to rblank:

Replying to Jeff Hammel <jhammel@…>:

How does this sound? If there is no huge controversy, I'd like to upload a patch early next week.

Sounds great! I would keep it as linked_fields, so you can disable linking for any type of field (if you wish).

Not sure if this is a typo; did you mean "I would keep it as unlinked_fields"?

in reply to:  19 comment:20 by Remy Blank, 16 years ago

Replying to Jeff Hammel <jhammel@…>:

Not sure if this is a typo; did you mean "I would keep it as unlinked_fields"?

No, I did mean linked_fields, as opposed to your proposed linked_text_fields in the comment I replied to. But I have no strong opinion about linked_fields / unlinked_fields. I just feel that it will be easier to understand if the option applies to all field types.

comment:21 by osimons, 16 years ago

Cc: osimons added

comment:22 by osimons, 16 years ago

Personally, unlinked_fields is my favorite - by default it just works for all fields (except textarea), and everything works the same way. If anyone for a special field or other reason should have a problem with that, then they can go and unlink what they don't want.

by osimons, 16 years ago

Cumulated tweaks + word linking.

comment:23 by osimons, 16 years ago

Attachment t7562-autoquery_tweaks_r7548.diff provides a well-working solution, I think:

  • It incorporates previous fixes for obfuscation and checkbox/radio rendering.
  • It add word linking to keywords and cc fields, with 'contains' link for each word. Obfuscation for cc is handled in a very simple manner, so that if any content inside cc gets obfuscated then no links will render.
  • It does not link to text and textarea fields, leaving that to perhaps some future .format=query option for rendering of custom fields - see discussion on #1791.
  • As all default fields is handled + remaining custom fields should all be choice fields, there is no longer a need for a specific option to unlink/link fields. Option removed.
  • The default query is also modified. The $USER is removed as it makes no sense for an anonymous query. Also, the ! in status is switched from != to =! as the GET parser does not comprehend the former (but both work as values for the setting).

Feedback please. Getting ready to commit…

by osimons, 16 years ago

Oops. Missed one unlinked reference. Use this cumulative patch, please - ignore previous.

comment:24 by osimons, 16 years ago

Oh dear. These changes wreaks havoc with the tests: 825 tests. FAILED (failures=30, errors=4)… Anyway, test the user-side of things for now while I look into the tests :-(

comment:25 by Remy Blank, 16 years ago

I haven't yet tested the patch, but I already have a question about the splitting algorithm in _query_link_words(). IIUC, you split at whitespace, strip ".,;" from both ends of every word, and combine again with a single space. This will change the apparent content of the fields in the display.

What about splitting with something like (untested):

for (i, word) in enumerate(re.split(r'(\s*[ .,;]\s*)')):
    if i % 2:
        # Generate tag here
        items.append(tag.a(...))
    else:
        items.append(word)

This will split at any of " .,;" and enclosing whitespace, and it will keep the separators and insert them in the output list, so it will keep the visual content of the field as it was before linkification.

comment:26 by Remy Blank, 16 years ago

Oops, that should be:

for (i, word) in enumerate(re.split(r'(\s*[ .,;]\s*)')):
    if i % 2:
        items.append(word)
    else:
        # Generate tag here
        items.append(tag.a(...))

by osimons, 16 years ago

Updated cumulative patch without test failures (previous tried to split None type)

in reply to:  25 ; comment:27 by osimons, 16 years ago

Replying to rblank:

This will split at any of " .,;" and enclosing whitespace, and it will keep the separators and insert them in the output list, so it will keep the visual content of the field as it was before linkification.

Tried latest variation, but not ideal as it will also split inside words so that individual emails also gets split for each dot(.). The dot is not really a divider, but i wanted to strip it from the end of words as this makes less sense for query (should perhaps use rstrip() to catch .net and similar?)

But, you are right - the split/strip algorithm can no doubt be improved.

comment:28 by osimons, 16 years ago

Hmm. Having looked at it some more, I think that for such a rendering feature of 'keywords' and 'cc' what looks best overall is just having a uniform separator like comma:

...
        for word in value.split():
            word = word.rstrip(",.;")
            if word:
                link = req.href('query', **{name: '~' + word}) \
                            + (default and '&' + default or '') 
                items.extend([tag.a(word, href=link), ', '])
        return items and tag(items[:-1]) # Strip last comma

in reply to:  27 comment:29 by Remy Blank, 16 years ago

Replying to osimons:

Tried latest variation, but not ideal as it will also split inside words so that individual emails also gets split for each dot(.). The dot is not really a divider, but i wanted to strip it from the end of words as this makes less sense for query (should perhaps use rstrip() to catch .net and similar?)

You're right, splitting on dots is no good. No idea why I put it in, actually.

What I find important is that the text displayed is the actual text in the DB, just linkified. I don't like the idea of "reformatting" values. This will lead to strange situations like having a field containing "Hello world", which will be displayed as "Hello, world", but where an "is" query for "Hello, world" will not return any results.

So I would still argue for splitting with a regexp of '\s*[ ,;]\s*' (i.e. without the dot).

comment:30 by Remy Blank, 16 years ago

I have tested your latest patch, and the following additional changes make the output nice and clean:

  • trac/ticket/web_ui.py

    diff --git a/trac/ticket/web_ui.py b/trac/ticket/web_ui.py
    a b  
    10741074            return value
    10751075        default = self.env.config.get('query', 'default_anonymous_query', '')
    10761076        items = []
    1077         for word in value.split():
    1078             word = word.strip(",.;")
    1079             if word:
     1077        for (i, word) in enumerate(re.split(r'(\s*(?:\s|[,;])\s*)', value)):
     1078            if i % 2:
     1079                items.append(word)
     1080            elif word:
    10801081                link = req.href('query', **{name: '~' + word}) \
    10811082                            + (default and '&' + default or '')
    1082                 items.append((tag.a(word, href=link), ' '))
     1083                items.append(tag.a(word, href=link))
    10831084        return tag(items)
    10841085
    10851086    def _prepare_fields(self, req, ticket):

I have another concern. The query link generation method (href('query') with the specific field, and appending the default query) is fragile:

  • It build a query URL by using query syntax. Is query syntax supported directly in query URLs?
  • What happens if the default query already has a parameter for the specific field?
  • Once #5998 will be applied, the default query options will allow both query syntax and URL query strings (in the same way as what the query: TracLinks support), so this will break.

A solution might be to decode the default query using a Query instance (using either Query() or Query.from_string() depending on the default query syntax), to get its constraints, update its constraints and get the link from Query.get_href().

in reply to:  30 comment:31 by Christian Boos, 16 years ago

Replying to rblank:

A solution might be to decode the default query using a Query instance …

Note that Query instances are not cheap due to the #6436 bug.

in reply to:  30 ; comment:32 by osimons, 16 years ago

Replying to rblank:

I have tested your latest patch, and the following additional changes make the output nice and clean:

Thanks a lot - that looks like a keeper :-)

As for your remaining query questions, I'm quite ignorant as I've not spent much time inside the query module code. I've just reused what this ticket had already implemented in an effort to make this new feature work better. I do notice strange query behavior like difference between != and =! that I can't quite explain, but that should be more improvements to the query module rather than side issues to this ticket. I'm OK with constructing simple href based links and fixing it later should it prove to be a problem.

in reply to:  32 ; comment:33 by Remy Blank, 16 years ago

Replying to osimons:

I do notice strange query behavior like difference between != and =! that I can't quite explain, but that should be more improvements to the query module rather than side issues to this ticket.

According to TracQuery#UsingTracLinks, there are two syntaxes for ticket queries:

  • The query language, which is parsed by Query.from_string() and uses the syntax where the modifier is before then =, like ~=.
  • URL query strings, which are the part following /query in the custom query URL. They start with a ? and place the modifier after the =, like =~. They are processed minimally in Query.process_request() and passed directly to Query.__init__().

When constructing an href URL, you should always use the latter. However, the default_query options contain a query in the former syntax (at least until #5998 is solved). That's why you are seeing strange results: the generated URL is actually wrong. You can see how query: TracLinks are generated in `_format_link()`. The same should be done here.

But as Christian mentions, constructing the Query object is currently expensive (and this will probably need FieldRefactoring to be fixed). What you could do is to have a separate autoquery_query option instead of using default_query, and require that option to be in URL syntax. It would then be relatively cheap to parse with the parse_query_string() function introduced in #5998. If you want, I can do that after closing that ticket.

in reply to:  33 comment:34 by osimons, 16 years ago

Replying to rblank:

According to TracQuery#UsingTracLinks, there are two syntaxes for ticket queries:

Thanks for explaining. I'll make a ticketlink_query option to keep these different, and just read and use that directly for now.

comment:35 by Remy Blank, 16 years ago

#5998 has been closed in [7553]. This gives you a function parse_query_string() that takes a query string and returns a _RequestArgs dictionary containing the query arguments. You should be able to use that to parse the ticketlink_query option, then override the autoqueried field and finally use href to construct the link.

by osimons, 16 years ago

Cumulative patch using new parse_query_string.

comment:36 by osimons, 16 years ago

Updated patch with a few additions:

  • A new [query] ticketlink_query = option
  • Using new parse_query_string()
  • Minor changes to parse_query_string to a) discard starting ?, and b) better handle empty query string.

Thanks for input everyone. I think the patch should be good enough now. Testing is most welcome, but suggestions for additional features or reworked implementation is not… ;-)

in reply to:  36 ; comment:37 by Remy Blank, 16 years ago

Replying to osimons:

  • Minor changes to parse_query_string to a) discard starting ?, and b) better handle empty query string.

Looks very good!

I have a minor nitpick, though. At some point, when #6436 will be solved, we'll be able to also support query language in [query] ticketlink_query, in the same way as default_query, and we'll differentiate between both syntaxes by the leading ?. So I would strip the ? in _query_link() and _query_link_words() instead of parse_query_string().

And BTW, you don't need a replace() for that, just do a query_string[1:] :-)

in reply to:  37 comment:38 by osimons, 16 years ago

Replying to rblank:

So I would strip the ? in _query_link() and _query_link_words() instead of parse_query_string().

Oki.

And BTW, you don't need a replace() for that, just do a query_string[1:] :-)

I use .replace() in order to use string methods instead of slicing an array, as I seem to remember seeing and fixing some issues at some stage whereby some Asian two-byte charsets evaluated this differently. I'd much rather do it the easy way, and in fact I had that as well before I got thinking. Is [1:] always safe? That would be good to know.

comment:39 by osimons, 16 years ago

I suppose it is just me complicating strings much more than necessary - at the point where we evaluate it all should be Unicode anyway… Oki, I'll fix last minor details and get this committed.

comment:40 by osimons, 16 years ago

Resolution: fixed
Status: reopenedclosed

Committed in [7560]. Closing.

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Christopher Lenz.
The resolution will be deleted. Next status will be 'reopened'.
to The owner will be changed from Christopher Lenz to the specified user.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.