implement +lookup view for itemid/revid/... based lookup
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 %}