]> git.ipfire.org Git - people/shoehn/ipfire.org.git/commitdiff
planet: Add proper full-text search.
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 16 Apr 2014 15:49:31 +0000 (17:49 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 16 Apr 2014 15:49:31 +0000 (17:49 +0200)
templates/modules/planet/search-box.html [new file with mode: 0644]
templates/planet/index.html
templates/planet/search.html
webapp/__init__.py
webapp/backend/planet.py
webapp/handlers_planet.py
webapp/ui_modules.py

diff --git a/templates/modules/planet/search-box.html b/templates/modules/planet/search-box.html
new file mode 100644 (file)
index 0000000..6d4f36b
--- /dev/null
@@ -0,0 +1,26 @@
+<div class="row">
+       <div class="col-lg-6 col-md-6 col-lg-offset-3 ac">
+               <form class="form-inline" action="/search" method="GET">
+                       <div class="form-group">
+                               <label class="sr-only" for="searchBox">{{ _("Search") }}</label>
+                               <input type="text" class="form-control" name="q" id="searchBox"
+                                       placeholder="{{ _("Search") }}" autocomplete="off" {% if query %}value="{{ query }}"{% end %}>
+                               <button type="submit" class="btn btn-default">
+                                       <i class="glyphicon glyphicon-search"></i>
+                               </button>
+
+                               <div class="btn-group">
+                                       <a class="btn btn-default dropdown-toggle" data-toggle="dropdown" href="#">
+                                               {{ _("All posts from") }}
+                                               <span class="caret"></span>
+                                       </a>
+                                       <ul class="dropdown-menu">
+                                               {% for y in years %}
+                                                       <li><a href="/year/{{ y }}">{{ y }}</a></li>
+                                               {% end %}
+                                       </ul>
+                               </div>
+                       </div>
+               </form>
+       </div>
+</div>
index 15cebd6764efb7c9fd74543d134a2aaa716b62d6..6e585e5f3430746bd56dba3157bea4d8a5ae7853 100644 (file)
        </p>
        <br>
 
-       <div class="row">
-               <div class="col-lg-6 col-md-6 col-lg-offset-3 ac">
-                       <form class="form-inline" action="/search" method="GET">
-                               <div class="form-group">
-                                       <label class="sr-only" for="searchBox">{{ _("Search") }}</label>
-                                       <input type="text" class="form-control planet-search-autocomplete" name="q" id="searchBox"
-                                               placeholder="{{ _("Search") }}" autocomplete="off">
-                                       <button type="submit" class="btn btn-default">
-                                               <i class="glyphicon glyphicon-search"></i>
-                                       </button>
-
-                                       <div class="btn-group">
-                                               <a class="btn btn-default dropdown-toggle" data-toggle="dropdown" href="#">
-                                                       {{ _("All posts from") }}
-                                                       <span class="caret"></span>
-                                               </a>
-                                               <ul class="dropdown-menu">
-                                                       {% for y in years %}
-                                                               <li><a href="/year/{{ y }}">{{ y }}</a></li>
-                                                       {% end %}
-                                               </ul>
-                                       </div>
-                               </div>
-                       </form>
-               </div>
-       </div>
+       {% module PlanetSearchBox() %}
 
        <hr class="separator">
 
index a3e79ab5c9a71d25bac2190545c5b1a096c93995..e221109c601f4613ed769e3ba4de4b4159e1b484 100644 (file)
@@ -7,6 +7,10 @@
 {% end block %}
 
 {% block body %}
+       {% module PlanetSearchBox(query=query) %}
+
+       <hr class="separator">
+
        {% if entries %}
                {% for entry in entries %}
                        {% module PlanetEntry(entry) %}
index 36bd58ee7ce7ab32cff3976475da89edf23e556d..d8904249314d8a7c106d6af42d01db82dfcb1f99 100644 (file)
@@ -49,6 +49,7 @@ class Application(tornado.web.Application):
                                "NewsTable"            : NewsTableModule,
                                "NewsYearNavigation"   : NewsYearNavigationModule,
                                "PlanetEntry"          : PlanetEntryModule,
+                               "PlanetSearchBox"      : PlanetSearchBoxModule,
                                "ReleaseItem"          : ReleaseItemModule,
                                "SidebarBanner"        : SidebarBannerModule,
                                "SidebarRelease"       : SidebarReleaseModule,
@@ -138,9 +139,6 @@ class Application(tornado.web.Application):
                        (r"/search", PlanetSearchHandler),
                        (r"/year/(\d+)", PlanetYearHandler),
 
-                       # API
-                       (r"/api/planet/search/autocomplete", PlanetAPISearchAutocomplete),
-
                        # RSS
                        (r"/rss", RSSPlanetAllHandler),
                        (r"/user/([a-z0-9_-]+)/rss", RSSPlanetUserHandler),
@@ -244,7 +242,6 @@ class Application(tornado.web.Application):
                        (r"/downloads", AdminDownloadsHandler),
                        (r"/downloads/mirrors", AdminDownloadsMirrorsHandler),
                        # API
-                       (r"/api/planet/search/autocomplete", PlanetAPISearchAutocomplete),
                        (r"/api/planet/render", AdminApiPlanetRenderMarkupHandler)
                ] + static_handlers)
 
index 0c7565684e6f77a2330f18e95ecac8b89a162c57..47036a10fb0d4af0b766ed11c77c88e544e8c131 100644 (file)
@@ -268,33 +268,14 @@ class Planet(Object):
                return id
 
        def search(self, what):
-               # Split tags.
-               tags = what.split()
-
-               query = "SELECT planet.* FROM planet INNER JOIN ( \
-                               SELECT post_id FROM planet_tags \
-                               INNER JOIN planet ON planet_tags.post_id = planet.id \
-                               WHERE %s GROUP BY post_id HAVING COUNT(post_id) = %%s \
-                       ) pt ON planet.id = pt.post_id ORDER BY published DESC"
-
-               args = (tags, len(tags))
-
-               clauses, args = [], tags
-               for tag in tags:
-                       clauses.append("planet_tags.tag = %s")
-               args.append(len(tags))
-
-               entries = self.db.query(query % " OR ".join(clauses), *args)
-               return [PlanetEntry(self.backend, e) for e in entries]
-
-       def search_autocomplete(self, what):
-               tags = what.split()
-               last_tag = tags.pop()
-
-               res = self.db.query("SELECT tag, COUNT(tag) AS count FROM planet_tags \
-                       WHERE tag LIKE %s GROUP BY tag ORDER BY count DESC", "%s%%" % last_tag)
-
-               if tags:
-                       return ["%s %s" % (" ".join(tags), row.tag) for row in res]
-
-               return [row.tag for row in res]
+               res = self.db.query("WITH \
+                       q      AS (SELECT plainto_tsquery(%s, %s) AS query), \
+                       ranked AS (SELECT id, query, ts_rank_cd(to_tsvector(%s, markdown), query) AS rank \
+                               FROM planet, q WHERE markdown @@ query ORDER BY rank DESC) \
+                       SELECT *, ts_headline(markup, ranked.query, 'MinWords=100, MaxWords=110') AS markup FROM planet \
+                               JOIN ranked ON planet.id = ranked.id \
+                               WHERE status = %s AND published IS NOT NULL AND published <= NOW() \
+                               ORDER BY ranked DESC LIMIT 10",
+                       "english", what, "english", "published")
+
+               return [PlanetEntry(self.backend, e) for e in res]
index 4a6fe5cb61ec251d9960c1dc13f24e42035a6044..18f2d4204c4d8b3f2ddcc809f2cc0565a90de2bf 100644 (file)
@@ -16,10 +16,8 @@ class PlanetMainHandler(PlanetBaseHandler):
                limit = int(self.get_argument("limit", 4))
 
                entries = self.planet.get_entries(offset=offset, limit=limit)
-               years = self.planet.get_years()
 
-               self.render("planet/index.html", entries=entries, years=years,
-                       offset=offset + limit, limit=limit)
+               self.render("planet/index.html", entries=entries, offset=offset + limit, limit=limit)
 
 
 class PlanetUserHandler(PlanetBaseHandler):
@@ -76,18 +74,3 @@ class PlanetYearHandler(PlanetBaseHandler):
                months.sort(reverse=True)
 
                self.render("planet/year.html", months=months, year=year)
-
-
-class PlanetAPISearchAutocomplete(PlanetBaseHandler):
-       def get(self):
-               query = self.get_argument("q")
-               if not query:
-                       raise tornado.web.HTTPError(400)
-
-               results = self.planet.search_autocomplete(query)
-
-               res = {
-                       "query"   : query,
-                       "results" : results,
-               }
-               self.write(res)
index 3cf68d85231f46107ca6b1cae8b5bead815c22ab..da69711c11013b866eb3b6a3f07d44c1ce7c68ed 100644 (file)
@@ -47,6 +47,10 @@ class UIModule(tornado.web.UIModule):
        def news(self):
                return self.handler.news
 
+       @property
+       def planet(self):
+               return self.handler.planet
+
 
 class AdvertisementModule(UIModule):
        def render(self, where):
@@ -148,6 +152,14 @@ class NewsYearNavigationModule(UIModule):
                        active=active, years=self.news.years)
 
 
+class PlanetSearchBoxModule(UIModule):
+       def render(self, query=None):
+               years = self.planet.get_years()
+
+               return self.render_string("modules/planet/search-box.html",
+                       query=query, years=years)
+
+
 class SidebarItemModule(UIModule):
        def render(self):
                return self.render_string("modules/sidebar-item.html")