Browse Source

Beginnings of search feature. #36

Ralfp 12 years ago
parent
commit
a0c5830c43

+ 2 - 1
.gitignore

@@ -172,6 +172,7 @@ coffin/**
 debug_toolbar/**
 debug_toolbar/**
 dev/**
 dev/**
 django/**
 django/**
+haystack/**
 jinja2/**
 jinja2/**
 markdown/**
 markdown/**
 mptt/**
 mptt/**
@@ -179,8 +180,8 @@ pytz/**
 recaptcha/**
 recaptcha/**
 south/**
 south/**
 whoosh/**
 whoosh/**
-haystack/**
 custom/**
 custom/**
+searchindex/**
 static/avatars/protoss
 static/avatars/protoss
 static/avatars/terran
 static/avatars/terran
 static/avatars/zerg
 static/avatars/zerg

+ 10 - 0
deployment/settings.py

@@ -49,6 +49,16 @@ CACHES = {
     }
     }
 }
 }
 
 
+# Search engine
+# Misago relies on 3rd party search engines to index and search your forum content
+# Read following for information on configurating search:
+# http://django-haystack.readthedocs.org/en/latest/tutorial.html#modify-your-settings-py
+HAYSTACK_CONNECTIONS = {
+    'default': {
+        'ENGINE': 'haystack.backends.whoosh_backend.',
+    },
+}
+
 # Cookies configuration
 # Cookies configuration
 COOKIES_DOMAIN = '192.168.33.10' # E.g. a cookie domain for "www.mysite.com" or "forum.mysite.com" is ".mysite.com"
 COOKIES_DOMAIN = '192.168.33.10' # E.g. a cookie domain for "www.mysite.com" or "forum.mysite.com" is ".mysite.com"
 COOKIES_PATH = '/'
 COOKIES_PATH = '/'

+ 0 - 0
misago/apps/search/__init__.py


+ 6 - 0
misago/apps/search/urls.py

@@ -0,0 +1,6 @@
+from django.conf.urls import patterns, url
+
+urlpatterns = patterns('misago.apps.search.views',
+    url(r'^$', 'do_search', name="search"),
+    url(r'^results/$', 'show_sesults', name="search_results"),
+)

+ 19 - 0
misago/apps/search/views.py

@@ -0,0 +1,19 @@
+from django.template import RequestContext
+from haystack.query import RelatedSearchQuerySet
+from misago.models import Post
+
+def do_search(request):
+    query = request.POST.get('search_query')
+    sqs = RelatedSearchQuerySet().auto_query(query).order_by('-id').load_all()
+    sqs = sqs.load_all_queryset(Post, Post.objects.all().select_related('thread', 'forum'))
+
+    return request.theme.render_to_response('search/results.html',
+                                            {
+                                             'search_phrase': query,
+                                             'results': sqs,
+                                            },
+                                            context_instance=RequestContext(request))
+
+
+def show_sesults(request):
+    pass

+ 5 - 0
misago/models/postmodel.py

@@ -2,6 +2,7 @@ from django.db import models
 from django.db.models import F
 from django.db.models import F
 from django.utils import timezone
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
+from misago.markdown import clear_markdown
 from misago.signals import (delete_user_content, merge_post, merge_thread,
 from misago.signals import (delete_user_content, merge_post, merge_thread,
                             move_forum_content, move_post, move_thread,
                             move_forum_content, move_post, move_thread,
                             rename_user, sync_user_profile)
                             rename_user, sync_user_profile)
@@ -56,6 +57,10 @@ class Post(models.Model):
         quote.append('\r\n')
         quote.append('\r\n')
         return '\r\n'.join(quote)
         return '\r\n'.join(quote)
 
 
+    @property
+    def post_clean(self):
+        return clear_markdown(self.post_preparsed)
+
     def move_to(self, thread):
     def move_to(self, thread):
         move_post.send(sender=self, move_to=thread)
         move_post.send(sender=self, move_to=thread)
         self.thread = thread
         self.thread = thread

+ 15 - 0
misago/search_indexes.py

@@ -0,0 +1,15 @@
+from haystack import indexes
+from misago.models import Post
+
+class PostIndex(indexes.SearchIndex, indexes.Indexable):
+    text = indexes.CharField(document=True, use_template=True)
+    forum = indexes.CharField(model_attr='forum')
+    thread = indexes.CharField(model_attr='thread')
+    user = indexes.CharField(model_attr='user_name')
+    date = indexes.DateTimeField(model_attr='date')
+
+    def get_model(self):
+        return Post
+
+    def index_queryset(self, using=None):
+        return self.get_model().objects.all()

+ 4 - 3
misago/settings_base.py

@@ -175,12 +175,13 @@ ROOT_URLCONF = 'misago.urls'
 #Installed applications
 #Installed applications
 INSTALLED_APPS = (
 INSTALLED_APPS = (
     # Applications that have no dependencies first!
     # Applications that have no dependencies first!
-    'south',
-    'coffin',
+    'south', # Database schema building and updating
+    'coffin', # Jinja2 integration
     'django.contrib.staticfiles',
     'django.contrib.staticfiles',
     'django.contrib.humanize',
     'django.contrib.humanize',
     'mptt', # Modified Pre-order Tree Transversal - allows us to nest forums 
     'mptt', # Modified Pre-order Tree Transversal - allows us to nest forums 
-    'debug_toolbar', # Debug toolbar
+    'haystack', # Search engines bridge
+    'debug_toolbar', # Debug toolbar'
     'misago', # Misago Forum App
     'misago', # Misago Forum App
 )
 )
 
 

+ 10 - 1
misago/templatetags/utils.py

@@ -1,4 +1,5 @@
 from coffin.template import Library
 from coffin.template import Library
+from haystack.utils import Highlighter
 from misago.utils.strings import short_string
 from misago.utils.strings import short_string
 
 
 register = Library()
 register = Library()
@@ -14,4 +15,12 @@ def intersect(list_a, list_b):
 
 
 @register.filter(name='short_string')
 @register.filter(name='short_string')
 def make_short(string, length=16):
 def make_short(string, length=16):
-    return short_string(string, length)
+    return short_string(string, length)
+
+
+@register.filter(name='highlight')
+def highlight_result(text, query, length=500):
+    hl = Highlighter(query, html_tag='strong', max_length=length)
+    hl = hl.highlight(text)
+
+    return hl

+ 1 - 0
misago/urls.py

@@ -29,6 +29,7 @@ urlpatterns += patterns('',
     (r'^reset-password/', include('misago.apps.resetpswd.urls')),
     (r'^reset-password/', include('misago.apps.resetpswd.urls')),
     (r'^private-threads/', include('misago.apps.privatethreads.urls')),
     (r'^private-threads/', include('misago.apps.privatethreads.urls')),
     (r'^reports/', include('misago.apps.reports.urls')),
     (r'^reports/', include('misago.apps.reports.urls')),
+    (r'^search/', include('misago.apps.search.urls')),
     (r'^', include('misago.apps.threads.urls')),
     (r'^', include('misago.apps.threads.urls')),
 )
 )
 
 

+ 3 - 2
templates/cranefly/layout.html

@@ -8,9 +8,10 @@
       <div class="container">
       <div class="container">
         <a href="{% url 'index' %}" class="brand">{% if settings.board_header %}{{ settings.board_header }}{% else %}{{ settings.board_name }}{% endif %}</a>
         <a href="{% url 'index' %}" class="brand">{% if settings.board_header %}{{ settings.board_header }}{% else %}{{ settings.board_name }}{% endif %}</a>
         {% if not user.is_crawler() %}
         {% if not user.is_crawler() %}
-        <form action="" method="post" class="navbar-form pull-left">
+        <form action="{% url 'search' %}" method="post" class="navbar-form pull-left">
           <div class="navbar-search-form">
           <div class="navbar-search-form">
-            <input type="text" class="span2" placeholder="{% trans %}Search community...{% endtrans %}">
+            <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+            <input type="text" name="search_query" class="span2" placeholder="{% trans %}Search community...{% endtrans %}"{% if search_phrase is defined %} value="{{ search_phrase }}"{% endif %}>
             <button type="submit" class="btn btn-link"><i class="icon-search"></i></button>
             <button type="submit" class="btn btn-link"><i class="icon-search"></i></button>
           </div>
           </div>
         </form>
         </form>

+ 23 - 0
templates/cranefly/search/results.html

@@ -0,0 +1,23 @@
+{% extends "cranefly/layout.html" %}
+{% import "cranefly/macros.html" as macros with context %}
+
+{% block title %}{{ macros.page_title(title=_('Search Community')) }}{% endblock %}
+
+{% block container %}
+<div class="page-header header-primary">
+  <div class="container">
+    <h1>{% trans %}Search Community{% endtrans %}</h1>
+  </div>
+</div>
+
+<div class="container container-primary">
+  <div class="search-results">
+    {% for result in results %}
+    <h2><a href="">{{ result.object.thread.name }}</a> <a href="">{{ result.object.forum.name }}</a></h2>
+    <p>{{ result.object.post_clean|highlight(search_phrase)|safe }}</p>
+    {% else %}
+    <p class="lead">Nothing was found :C</p>
+    {% endfor %}
+  </div>
+</div>
+{% endblock %}

+ 3 - 0
templates/search/indexes/misago/post_text.txt

@@ -0,0 +1,3 @@
+{{ object.thread.name }}
+{{ object.user.username }}
+{{ object.post_clean }}