views.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. from django.core.urlresolvers import reverse
  2. from django.http import Http404
  3. from django.shortcuts import redirect
  4. from django.template import RequestContext
  5. from django.utils import timezone
  6. from django.utils.translation import ugettext as _
  7. from haystack.inputs import AutoQuery
  8. from haystack.query import SearchQuerySet, RelatedSearchQuerySet
  9. from misago.acl.exceptions import ACLError403, ACLError404
  10. from misago.conf import settings
  11. from misago.decorators import block_crawlers
  12. from misago.models import Forum, Thread, Post, User
  13. from misago.search import SearchException
  14. from misago.shortcuts import render_to_response
  15. from misago.utils.pagination import make_pagination
  16. from misago.apps.errors import error403, error404
  17. from misago.apps.profiles.views import list as users_list
  18. from misago.apps.search.forms import QuickSearchForm
  19. class ViewBase(object):
  20. search_route = 'search'
  21. def check_acl(self):
  22. pass
  23. def make_query(self, search_query):
  24. sqs = SearchQuerySet()
  25. if self.request.POST.get('search_thread_titles'):
  26. sqs = sqs.filter(thread_name=AutoQuery(search_query), start_post=1)
  27. else:
  28. sqs = sqs.auto_query(search_query)
  29. if self.request.POST.get('search_in') == 'private_threads':
  30. if not (self.request.acl.private_threads.can_participate()
  31. and settings.enable_private_threads):
  32. raise ACLError404()
  33. sqs = sqs.filter(thread__in=[t.pk for t in self.request.user.private_thread_set.all()])
  34. elif self.request.POST.get('search_in') == 'reports':
  35. if not self.request.acl.reports.can_handle():
  36. raise ACLError404()
  37. sqs = sqs.filter(forum=Forum.objects.special_pk('reports'))
  38. elif self.request.POST.get('search_in') == 'thread':
  39. try:
  40. thread_id = int(self.request.POST.get('search_thread'))
  41. thread_clean = Thread.objects.get(id=thread_id)
  42. readable_forums = Forum.objects.readable_forums(self.request.acl, True)
  43. starter_readable_forums = Forum.objects.starter_readable_forums(self.request.acl)
  44. if not thread_clean.forum_id in readable_forums:
  45. if not (thread_clean.forum_id in starter_readable_forums
  46. and thread_clean.start_poster_id
  47. and thread_clean.start_poster_id == self.request.user.id):
  48. raise ACLError404()
  49. self.thread_clean = thread_clean
  50. sqs = sqs.filter(thread=thread_clean.pk)
  51. except (TypeError, Thread.DoesNotExist):
  52. raise ACLError404()
  53. else:
  54. readable_forums = Forum.objects.readable_forums(self.request.acl)
  55. starter_readable_forums = Forum.objects.starter_readable_forums(self.request.acl)
  56. if not readable_forums and not readable_forums:
  57. return error403(request, _("You cannot search any forums."))
  58. if readable_forums and starter_readable_forums:
  59. sqs = sqs.filter(forum__in=starter_readable_forums, thread_starter=self.request.user.id)
  60. sqs = sqs.filter_or(forum__in=readable_forums)
  61. elif starter_readable_forums:
  62. if not self.request.user.is_authenticated():
  63. return error403(request, _("You cannot search any forums."))
  64. sqs = sqs.filter(forum__in=starter_readable_forums, thread_starter=self.request.user.id)
  65. else:
  66. sqs = sqs.filter(forum__in=readable_forums)
  67. if self.request.POST.get('search_author'):
  68. sqs = sqs.filter(author__exact=self.request.POST.get('search_author'))
  69. return sqs
  70. def render_to_response(self, template, form, context):
  71. for i in ('search_query', 'search_in', 'search_author', 'search_thread_titles'):
  72. if self.request.POST.get(i):
  73. context[i] = self.request.POST.get(i)
  74. try:
  75. context['search_thread'] = self.thread_clean
  76. except AttributeError:
  77. pass
  78. return render_to_response('search/%s.html' % template,
  79. context,
  80. context_instance=RequestContext(self.request))
  81. def __new__(cls, request, **kwargs):
  82. obj = super(ViewBase, cls).__new__(cls)
  83. return obj(request, **kwargs)
  84. def __call__(self, request, **kwargs):
  85. try:
  86. if request.user.is_crawler():
  87. raise ACLError404()
  88. self.check_acl()
  89. if not request.acl.search.can_search():
  90. raise ACLError403(_("You don't have permission to search community."))
  91. self.request = request
  92. return self.call(**kwargs)
  93. except ACLError403 as e:
  94. return error403(request, unicode(e))
  95. except ACLError404 as e:
  96. return error404(request, unicode(e))
  97. class QuickSearchView(ViewBase):
  98. def call(self, **kwargs):
  99. form_type = QuickSearchForm
  100. if self.request.method != "POST":
  101. form = QuickSearchForm(request=self.request)
  102. return self.render_to_response('home', form,
  103. {'search_result': self.request.session.get('search_results')})
  104. try:
  105. form = QuickSearchForm(self.request.POST, request=self.request)
  106. if form.is_valid():
  107. if form.mode == 'forum':
  108. jump_to = Forum.objects.forum_by_name(form.target, self.request.acl)
  109. if jump_to:
  110. if jump_to.level == 1:
  111. return redirect(reverse('index') + ('#%s' % jump_to.slug))
  112. return redirect(jump_to.url)
  113. else:
  114. raise SearchException(_('Forum "%(forum)s" could not be found.') % {'forum': form.target})
  115. if form.mode == 'user':
  116. self.request.POST = self.request.POST.copy()
  117. self.request.POST['username'] = form.target
  118. return users_list(self.request)
  119. sqs = self.make_query(form.cleaned_data['search_query']).load_all()[:60]
  120. if self.request.user.is_authenticated():
  121. self.request.user.last_search = timezone.now()
  122. self.request.user.save(force_update=True)
  123. if self.request.user.is_anonymous():
  124. self.request.session['last_search'] = timezone.now()
  125. if not sqs:
  126. raise SearchException(_("Search returned no results. Change search query and try again."))
  127. self.request.session['search_results'] = {
  128. 'search_query': form.cleaned_data['search_query'],
  129. 'search_in': self.request.POST.get('search_in'),
  130. 'search_author': self.request.POST.get('search_author'),
  131. 'search_thread_titles': self.request.POST.get('search_thread_titles'),
  132. 'search_results': [p.object for p in sqs],
  133. }
  134. try:
  135. self.request.session['search_results']['search_thread'] = self.thread_clean
  136. except AttributeError:
  137. pass
  138. return redirect(reverse('search_results'))
  139. else:
  140. if 'search_query' in form.errors:
  141. raise SearchException(form.errors['search_query'][0])
  142. raise SearchException(form.errors['__all__'][0])
  143. except SearchException as e:
  144. return self.render_to_response('error', form,
  145. {'message': unicode(e)})
  146. class SearchResultsView(ViewBase):
  147. def call(self, **kwargs):
  148. result = self.request.session.get('search_results')
  149. if not result:
  150. form = QuickSearchForm(request=self.request)
  151. return self.render_to_response('error', form,
  152. {'message': _("No search results were found.")})
  153. items = result['search_results']
  154. items_total = len(items);
  155. try:
  156. pagination = make_pagination(kwargs.get('page', 0), items_total, 12)
  157. except Http404:
  158. return redirect(reverse('search_results'))
  159. form = QuickSearchForm(request=self.request, initial={'search_query': result['search_query']})
  160. return self.render_to_response('results', form,
  161. {
  162. 'search_query': result['search_query'],
  163. 'search_in': result.get('search_in'),
  164. 'search_author': result.get('search_author'),
  165. 'search_thread_titles': result.get('search_thread_titles'),
  166. 'search_thread': result.get('search_thread'),
  167. 'results': items[pagination['start']:pagination['stop']],
  168. 'items_total': items_total,
  169. 'pagination': pagination,
  170. })