implement +lookup view for itemid/revid/... based lookup
authorThomas Waldmann <tw AT waldmann-edv DOT de>
Mon, 07 May 2012 00:32:59 +0200
changeset 1347cd22cf9e8dd7
parent 1346 62bfa171319f
child 1348 04f567afe65f
child 1357 5b88a6ae67a5
implement +lookup view for itemid/revid/... based lookup
MoinMoin/apps/frontend/views.py
MoinMoin/templates/lookup.html
     1.1 --- a/MoinMoin/apps/frontend/views.py	Sun May 06 17:25:16 2012 +0200
     1.2 +++ b/MoinMoin/apps/frontend/views.py	Mon May 07 00:32:59 2012 +0200
     1.3 @@ -39,7 +39,7 @@
     1.4  import pytz
     1.5  from babel import Locale
     1.6  
     1.7 -from whoosh.query import Term, And, Or, DateRange
     1.8 +from whoosh.query import Term, Prefix, And, Or, DateRange
     1.9  
    1.10  from MoinMoin import log
    1.11  logging = log.getLogger(__name__)
    1.12 @@ -124,6 +124,85 @@
    1.13      return app.send_static_file('logos/favicon.ico')
    1.14  
    1.15  
    1.16 +class LookupForm(Form):
    1.17 +    name = String.using(label=L_('name'), optional=True)
    1.18 +    name_exact = String.using(label=L_('name_exact'), optional=True)
    1.19 +    itemid = String.using(label=L_('itemid'), optional=True)
    1.20 +    revid = String.using(label=L_('revid'), optional=True)
    1.21 +    history = Boolean.using(label=L_('search also in non-current revisions'), optional=True)
    1.22 +    submit = String.using(default=L_('Lookup'), optional=True)
    1.23 +
    1.24 +
    1.25 +@frontend.route('/+lookup', methods=['GET', 'POST'])
    1.26 +def lookup():
    1.27 +    """
    1.28 +    lookup is like search, but it only deals with specific fields that identify
    1.29 +    an item / revision. no query string parsing.
    1.30 +
    1.31 +    for uuid fields, it performs a prefix search, so you can just give the
    1.32 +    first few digits. same is done for name_exact field.
    1.33 +    if you give a complete uuid or you do a lookup via the name field, it
    1.34 +    will use a simple search term.
    1.35 +    for one result, it directly redirects to the item/revision found.
    1.36 +    for none or multipe results, a result page is shown.
    1.37 +
    1.38 +    usually this is used for links with a query string, like:
    1.39 +    /+lookup?itemid=123cba  (prefix match on itemid 123cba.......)
    1.40 +    /+lookup?revid=c0ddcda9a092499c92920cc4a9b11704  (full uuid simple term match)
    1.41 +    /+lookup?name_exact=FooBar/  (prefix match on name_exact FooBar/...)
    1.42 +
    1.43 +    When giving history=1 it will use the all revisions index for lookup.
    1.44 +    """
    1.45 +    status = 200
    1.46 +    title_name = _("Lookup")
    1.47 +    lookup_form = LookupForm.from_flat(request.values)
    1.48 +    valid = lookup_form.validate()
    1.49 +    lookup_form['submit'].set_default() # XXX from_flat() kills all values
    1.50 +    if valid:
    1.51 +        history = bool(request.values.get('history'))
    1.52 +        idx_name = ALL_REVS if history else LATEST_REVS
    1.53 +        terms = []
    1.54 +        for key in [NAME, NAME_EXACT, ITEMID, REVID, ]:
    1.55 +            value = lookup_form[key].value
    1.56 +            if value:
    1.57 +                if (key in [ITEMID, REVID, ] and len(value) < crypto.UUID_LEN
    1.58 +                    or
    1.59 +                    key in [NAME_EXACT]):
    1.60 +                    term = Prefix(key, value)
    1.61 +                else:
    1.62 +                    term = Term(key, value)
    1.63 +                terms.append(term)
    1.64 +        if terms:
    1.65 +            terms.append(Term(WIKINAME, app.cfg.interwikiname))
    1.66 +            q = And(terms)
    1.67 +            with flaskg.storage.indexer.ix[idx_name].searcher() as searcher:
    1.68 +                flaskg.clock.start('lookup')
    1.69 +                results = searcher.search(q, limit=100)
    1.70 +                flaskg.clock.stop('lookup')
    1.71 +                num_results = results.scored_length()
    1.72 +                if num_results == 1:
    1.73 +                    result = results[0]
    1.74 +                    rev = result[REVID] if history else CURRENT
    1.75 +                    url = url_for('.show_item', item_name=result[NAME], rev=rev)
    1.76 +                    return redirect(url)
    1.77 +                else:
    1.78 +                    flaskg.clock.start('lookup render')
    1.79 +                    html = render_template('lookup.html',
    1.80 +                                           title_name=title_name,
    1.81 +                                           lookup_form=lookup_form,
    1.82 +                                           results=results,
    1.83 +                                          )
    1.84 +                    flaskg.clock.stop('lookup render')
    1.85 +                    if not num_results:
    1.86 +                        status = 404
    1.87 +                    return Response(html, status)
    1.88 +    html = render_template('lookup.html',
    1.89 +                           title_name=title_name,
    1.90 +                           lookup_form=lookup_form,
    1.91 +                          )
    1.92 +    return Response(html, status)
    1.93 +
    1.94 +
    1.95  @frontend.route('/+search', methods=['GET', 'POST'])
    1.96  def search():
    1.97      title_name = _("Search")
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/MoinMoin/templates/lookup.html	Mon May 07 00:32:59 2012 +0200
     2.3 @@ -0,0 +1,44 @@
     2.4 +{% extends theme("layout.html") %}
     2.5 +{% import "utils.html" as utils %}
     2.6 +{% import "forms.html" as forms %}
     2.7 +{% block content %}
     2.8 +    {% if results is not defined %}
     2.9 +    <h1>{{ _("Lookup") }}</h1>
    2.10 +    {{ gen.form.open(lookup_form, id='moin-lookup-form', method='get', action=url_for('frontend.lookup')) }}
    2.11 +        {{ forms.render_errors(lookup_form) }}
    2.12 +        <dl>
    2.13 +            {{ forms.render_field(gen, lookup_form['name'], 'text') }}
    2.14 +            {{ forms.render_field(gen, lookup_form['name_exact'], 'text') }}
    2.15 +            {{ forms.render_field(gen, lookup_form['itemid'], 'text') }}
    2.16 +            {{ forms.render_field(gen, lookup_form['revid'], 'text') }}
    2.17 +            {{ forms.render_field_without_markup(gen, lookup_form['history'], 'checkbox') }}
    2.18 +        </dl>
    2.19 +        {{ gen.input(lookup_form['submit'], type='submit') }}
    2.20 +    {{ gen.form.close() }}
    2.21 +    {% else %}
    2.22 +    {% if not results %}
    2.23 +    <h1>{{ _("No results") }}</h1>
    2.24 +    {% else %}
    2.25 +    <h1>{{ _("More than one result") }}</h1>
    2.26 +    <div class="lookupresults">
    2.27 +        <table>
    2.28 +            {% for result in results %}
    2.29 +                {% if result['wikiname'] == cfg.interwikiname %}
    2.30 +                    <tr>
    2.31 +                        <td class="moin-wordbreak">{{ result.pos + 1 }}
    2.32 +                        <a href="{{ url_for_item(item_name=result['name'], wiki_name='Self', rev=result['revid']) }}"><b>{{ result['name'] }}</b></a>
    2.33 +                        </td>
    2.34 +                    </tr>
    2.35 +                {% else %}
    2.36 +                    <tr>
    2.37 +                        <td class="moin-wordbreak">{{ result.pos + 1 }}
    2.38 +                        <a class="moin-interwiki" href="{{ url_for_item(item_name=result['name'], wiki_name=result['wikiname'], rev=result['revid']) }}"><b>{{ "%s:%s" % (result['wikiname'], result['name']) }}</b></a>
    2.39 +                        </td>
    2.40 +                    </tr>
    2.41 +                {% endif %}
    2.42 +            {% endfor %}
    2.43 +        </table>
    2.44 +    </div>
    2.45 +    {% endif %}
    2.46 +    {% endif %}
    2.47 +{% endblock %}