diff --git a/apps/search/__init__.py b/apps/search/__init__.py index 2d9286beab1..876f8ae0507 100644 --- a/apps/search/__init__.py +++ b/apps/search/__init__.py @@ -1,7 +1,6 @@ from .utils import crc32 # TODO: use lazy gettext, as in zamboni -import gettext from django.utils.translation import ugettext WHERE_WIKI = 1 @@ -42,20 +41,27 @@ ) # reverse lookup STATUS_ALIAS_REVERSE = { + STATUS_ALIAS_NO: (), STATUS_ALIAS_NH: (STATUS_NORMAL, STATUS_ORIGINALREPLY), STATUS_ALIAS_HA: (STATUS_PROPOSED, STATUS_REQUEST), STATUS_ALIAS_SO: (STATUS_SOLVED,), STATUS_ALIAS_AR: (STATUS_ARCHIVE,), - STATUS_ALIAS_OT: (STATUS_LOCKED, STATUS_STICKY, STATUS_ANNOUNCE, STATUS_INVALID, STATUS_HOT), + STATUS_ALIAS_OT: (STATUS_LOCKED, STATUS_STICKY, STATUS_ANNOUNCE, + STATUS_INVALID, STATUS_HOT,), } +CREATED_NONE = 0 +CREATED_BEFORE = 1 +CREATED_AFTER = 2 CREATED_LIST = ( - (0, ugettext('Don\'t filter')), - (1, ugettext('Before')), - (2, ugettext('After')), + (CREATED_NONE, ugettext('Don\'t filter')), + (CREATED_BEFORE, ugettext('Before')), + (CREATED_AFTER, ugettext('After')), ) +# multiplier +LUP_MULTIPLIER = 86400 # one day LUP_LIST = ( (0, "Don't filter"), (1, "Last 24 hours"), diff --git a/apps/search/templates/form.html b/apps/search/templates/form.html index ed350139708..ea7709b51a5 100644 --- a/apps/search/templates/form.html +++ b/apps/search/templates/form.html @@ -69,7 +69,7 @@
{{ search_form.created.label_tag()|safe }} {{ search_form.created|safe }} - +
diff --git a/apps/search/views.py b/apps/search/views.py index 7319c539170..2c27b2d434a 100644 --- a/apps/search/views.py +++ b/apps/search/views.py @@ -10,6 +10,7 @@ from django.core.urlresolvers import reverse import jingo +import time from sumo.utils import paginate from sumo.models import ForumThread, WikiPage, Forum, Category @@ -24,26 +25,30 @@ def search(request): + """Performs search or displays the search form""" + + # set up form search_form = SearchForm(request.GET.copy()) + # set up query variables q = request.GET.get('q', '') - refine_query = {'q': q} locale = request.GET.get('locale', request.LANGUAGE_CODE) - sphinx_locale = (crc32(locale),) - refine_query['locale'] = locale + language = request.GET.get('language', locale) + sphinx_locale = (crc32(language),) where = int(request.GET.get('w', CONSTANTS.WHERE_ALL)) - refine_query['w'] = where page = int(request.GET.get('page', 1)) page = max(page, 1) offset = (page-1) * settings.SEARCH_RESULTS_PER_PAGE - if (len(q) <= 0 or (request.GET.get('a', '0') == '1')): + # no query or advanced search? + # => return empty form + if (not q or (request.GET.get('a', '0') == '1')): return jingo.render(request, 'form.html', {'locale': request.LANGUAGE_CODE, - 'advanced': request.GET.get('a', '0'), + 'advanced': request.GET.get('a'), 'request': request, 'w': where, 'search_form': search_form, }) @@ -54,18 +59,14 @@ def search(request): wc = WikiClient() # Wiki SearchClient instance filters_w = [] # filters for the wiki search - # Category filter - categories = request.GET.get('category[]', - settings.SEARCH_DEFAULT_CATEGORIES) + # Category filter + categories = request.GET.getlist('category') or \ + settings.SEARCH_DEFAULT_CATEGORIES filters_w.append({ 'filter': 'category', - 'value': map(int, - categories.split(',')), + 'value': map(int, categories), }) - refine_query['category[]'] = categories - #for category in categories: - # refine_query['category[]'].append(category) # Locale filter @@ -74,15 +75,15 @@ def search(request): 'value': sphinx_locale, }) + # Tag filter - tag = request.GET.get('tag', '') - if (tag is not None) and len(tag) > 0: + tag = request.GET.get('tag', None) + if tag: filters_w.append({ 'filter': 'tag', 'value': map(crc32, request.GET.get('tag').split(',')), }) - refine_query['tag'] = tag # execute the query and append to documents documents += wc.query(q, filters_w) @@ -95,34 +96,90 @@ def search(request): filters_f.append({ 'filter': 'forumId', 'value': map(int, - request.GET.get('forums', - settings.SEARCH_DEFAULT_FORUM).split(',')), + request.GET.getlist('fid') or \ + settings.SEARCH_DEFAULT_FORUMS), }) # Status filter - if request.GET.get('status') is not None: - """filters_f.append({ - 'filter': 'status', - 'value': STATUS_LIST[request.GET.get('status')], - })""" + status = int(request.GET.get('status')) + # no replies case is not stored in status + if status == CONSTANTS.STATUS_ALIAS_NR: + filters_f.append({ + 'filter': 'replies', + 'value': (0,), + }) - refine_query['status'] = request.GET.get('status', '0') + # avoid filtering by status + status = None + + if status: + filters_f.append({ + 'filter': 'status', + 'value': CONSTANTS.STATUS_ALIAS_REVERSE[int( + request.GET.get('status'))], + }) # Author filter - if request.GET.get('author') is not None: + if request.GET.get('author'): filters_f.append({ - 'filter': 'author', + 'filter': 'author_ord', 'value': (crc32(request.GET.get('author')), crc32(request.GET.get('author') + ' (anon)'),), }) - refine_query['author'] = request.GET.get('author', '') - + unix_now = int(time.time()) # Created filter - if request.GET.get('created') is not None: + created = int(request.GET.get('created')) + created_date = request.GET.get('created_date') + + if not created_date: + # no date => no filtering + created = None + else: + try: + created_date = int(time.mktime( + time.strptime(created_date, '%m/%d/%Y'), + )) + except ValueError: + created = None + + + if not created: pass - refine_query['created'] = request.GET.get('created', '') + elif created == CONSTANTS.CREATED_BEFORE: + filters_f.append({ + 'range': True, + 'filter': 'created', + 'min': 0, + 'max': created_date, + }) + + elif created == CONSTANTS.CREATED_AFTER: + filters_f.append({ + 'range': True, + 'filter': 'created', + 'min': created_date, + 'max': int(unix_now), + }) + + + # Last modified filter + lastmodif = int(request.GET.get('lastmodif')) + + if not lastmodif: + pass + + else: + filters_f.append({ + 'range': True, + 'filter': 'created', + 'min': unix_now - CONSTANTS.LUP_MULTIPLIER * lastmodif, + 'max': unix_now, + }) + + # Sort results by + documents += fc.query(q, filters_f) diff --git a/apps/sumo/models.py b/apps/sumo/models.py index 3b3fb9ea1ca..53e3b8f6bbe 100644 --- a/apps/sumo/models.py +++ b/apps/sumo/models.py @@ -52,7 +52,8 @@ class Forum(ModelBase): moderator_group = models.CharField(max_length=200, null=True) approval_type = models.CharField(max_length=20, null=True) outbound_address = models.CharField(max_length=250, null=True) - outbound_mails_for_inbound_mails = models.CharField(max_length=1, null=True) + outbound_mails_for_inbound_mails = models.CharField(max_length=1, + null=True) outbound_mails_reply_link = models.CharField(max_length=1, null=True) outbound_from = models.CharField(max_length=250, null=True) inbound_pop_server = models.CharField(max_length=250, null=True) @@ -124,10 +125,6 @@ def __unicode__(self): def name(self): return self.title - @property - def search_summary(self): - return self.summary - def get_url(self): """ TODO: Once we can use reverse(), use reverse() @@ -192,4 +189,3 @@ class Meta: def __unicode__(self): return self.name - diff --git a/settings.py b/settings.py index 861791a075e..2efbf46bf6c 100644 --- a/settings.py +++ b/settings.py @@ -7,7 +7,7 @@ LOG_LEVEL = logging.DEBUG ROOT = os.path.dirname(os.path.abspath(__file__)) -path = lambda *a: os.path.join(ROOT, *a) +path = lambda * a: os.path.join(ROOT, * a) ADMINS = ( # ('Your Name', 'your_email@domain.com'), @@ -17,12 +17,18 @@ DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': 'kitsune', # Or path to database file if using sqlite3. - 'USER': '', # Not used with sqlite3. - 'PASSWORD': '', # Not used with sqlite3. - 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. - 'PORT': '', # Set to empty string for default. Not used with sqlite3. + # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. + 'ENGINE': 'django.db.backends.mysql', + # Or path to database file if using sqlite3. + 'NAME': 'kitsune', + # Not used with sqlite3. + 'USER': '', + # Not used with sqlite3. + 'PASSWORD': '', + # Set to empty string for localhost. Not used with sqlite3. + 'HOST': '', + # Set to empty string for default. Not used with sqlite3. + 'PORT': '', 'OPTIONS': {'init_command': 'SET storage_engine=InnoDB'}, } } @@ -83,7 +89,7 @@ 'django.core.context_processors.debug', 'django.core.context_processors.media', 'django.core.context_processors.request', - 'django.contrib.messages.context_processors.messages' + 'django.contrib.messages.context_processors.messages', ) MIDDLEWARE_CLASSES = ( @@ -135,8 +141,9 @@ # # Search default settings -SEARCH_DEFAULT_CATEGORIES = '1,17,18' # comma-separated string of category IDs -SEARCH_DEFAULT_FORUM = '1' # default forum ID (eg: 1 on sumo, 5 on mosumo) +# comma-separated tuple of category IDs +SEARCH_DEFAULT_CATEGORIES = (1, 17, 18) +SEARCH_DEFAULT_FORUMS = (1,) # default forum ID (eg: 1 on sumo, 5 on mosumo) SEARCH_SUMMARY_LENGTH = 275 # because of markup cleanup, search summaries lengths vary quite a bit # so we extract longer excerpts and perform truncation to the length above