def _thread_list(request, mlist, threads, template_name='hyperkitty/thread_list.html', extra_context=None): threads = paginate(threads, request.GET.get('page'), results_per_page=request.GET.get('count')) for thread in threads: # Favorites thread.favorite = False if request.user.is_authenticated(): try: Favorite.objects.get(thread=thread, user=request.user) except Favorite.DoesNotExist: pass else: thread.favorite = True # Category thread.category_hk, thread.category_form = \ get_category_widget(request, thread.category) context = { 'mlist' : mlist, 'threads': threads, 'months_list': get_months(mlist), } if extra_context is not None: context.update(extra_context) return render(request, template_name, context)
def last_views(request): store = get_store(request) # Last viewed threads try: last_views = LastView.objects.filter(user=request.user ).order_by("view_date") except Favorite.DoesNotExist: last_views = [] last_views = paginate(last_views, request.GET.get('lvpage')) for last_view in last_views: thread = store.get_thread(last_view.list_address, last_view.threadid) last_view.thread = thread if thread is None: last_view.delete() continue if thread.date_active.replace(tzinfo=utc) > last_view.view_date: # small optimization: only query the replies if necessary # XXX: Storm-specific (count method) thread.unread = thread.replies_after(last_view.view_date).count() else: thread.unread = 0 last_views = [ lv for lv in last_views if lv.thread is not None ] return render(request, 'ajax/last_views.html', { "last_views": last_views, })
def last_views(request): # Last viewed threads lviews = LastView.objects.filter(user=request.user).order_by("-view_date") lviews = paginate(lviews, request.GET.get('lvpage')) return render(request, 'hyperkitty/ajax/last_views.html', { "last_views": lviews, })
def _thread_list(request, mlist, threads, template_name='hyperkitty/thread_list.html', extra_context=None): categories = [ (c.name, c.name.upper()) for c in ThreadCategory.objects.all() ] \ + [("", "no category")] threads = paginate(threads, request.GET.get('page')) for thread in threads: # Favorites thread.favorite = False if request.user.is_authenticated(): try: Favorite.objects.get(thread=thread, user=request.user) except Favorite.DoesNotExist: pass else: thread.favorite = True # Category thread.category_hk, thread.category_form = \ get_category_widget(request, thread.category, categories) flash_messages = [] flash_msg = request.GET.get("msg") if flash_msg: flash_msg = { "type": FLASH_MESSAGES[flash_msg][0], "msg": FLASH_MESSAGES[flash_msg][1] } flash_messages.append(flash_msg) context = { 'mlist' : mlist, 'threads': threads, 'months_list': get_months(mlist), 'flash_messages': flash_messages, } if extra_context is not None: context.update(extra_context) return render(request, template_name, context)
def last_views(request): # Last viewed threads lviews = LastView.objects.filter(user=request.user ).order_by("-view_date") lviews = paginate(lviews, request.GET.get('lvpage')) return render(request, 'hyperkitty/ajax/last_views.html', { "last_views": lviews, })
def favorites(request): # Favorite threads favs = Favorite.objects.filter(user=request.user ).order_by("-thread__date_active") favs = paginate(favs, request.GET.get('favpage')) return render(request, 'hyperkitty/ajax/favorites.html', { "favorites": favs, })
def _thread_list(request, mlist, threads, template_name='thread_list.html', extra_context={}): if mlist is None: raise Http404("No archived mailing-list by that name.") store = get_store(request) threads = paginate(threads, request.GET.get('page')) participants = set() for thread in threads: if "participants" not in extra_context: participants.update(thread.participants) # Votes set_thread_votes(thread) # Favorites thread.favorite = False if request.user.is_authenticated(): try: Favorite.objects.get(list_address=mlist.name, threadid=thread.thread_id, user=request.user) except Favorite.DoesNotExist: pass else: thread.favorite = True # Tags try: thread.tags = Tag.objects.filter(threadid=thread.thread_id, list_address=mlist.name) except Tag.DoesNotExist: thread.tags = [] # Category thread.category_hk, thread.category_form = \ get_category_widget(request, thread.category) # Unread status thread.unread = is_thread_unread(request, mlist.name, thread) flash_messages = [] flash_msg = request.GET.get("msg") if flash_msg: flash_msg = { "type": FLASH_MESSAGES[flash_msg][0], "msg": FLASH_MESSAGES[flash_msg][1] } flash_messages.append(flash_msg) context = { 'mlist' : mlist, 'threads': threads, 'participants': len(participants), 'months_list': get_months(store, mlist.name), 'flash_messages': flash_messages, } context.update(extra_context) return render(request, template_name, context)
def votes(request): store = get_store(request) if "user_id" not in request.session: return HttpResponse("Could not find or create your user ID in Mailman", content_type="text/plain", status=500) user = store.get_user(request.session["user_id"]) votes = paginate(user.votes, request.GET.get('vpage')) return render(request, 'ajax/votes.html', { "votes": votes, })
def _thread_list(request, mlist, threads, template_name='thread_list.html', extra_context={}): if mlist is None: raise Http404("No archived mailing-list by that name.") store = get_store(request) threads = paginate(threads, request.GET.get('page')) participants = set() for thread in threads: if "participants" not in extra_context: participants.update(thread.participants) # Favorites thread.favorite = False if request.user.is_authenticated(): try: Favorite.objects.get(list_address=mlist.name, threadid=thread.thread_id, user=request.user) except Favorite.DoesNotExist: pass else: thread.favorite = True # Tags try: thread.tags = Tag.objects.filter(threadid=thread.thread_id, list_address=mlist.name) except Tag.DoesNotExist: thread.tags = [] # Category thread.category_hk, thread.category_form = \ get_category_widget(request, thread.category) # Unread status thread.unread = is_thread_unread(request, mlist.name, thread) flash_messages = [] flash_msg = request.GET.get("msg") if flash_msg: flash_msg = { "type": FLASH_MESSAGES[flash_msg][0], "msg": FLASH_MESSAGES[flash_msg][1] } flash_messages.append(flash_msg) context = { 'mlist' : mlist, 'threads': threads, 'participants': len(participants), 'months_list': get_months(store, mlist.name), 'flash_messages': flash_messages, } context.update(extra_context) return render(request, template_name, context)
def posts(request, user_id): store = get_store(request) mlist_fqdn = request.GET.get("list") if mlist_fqdn is None: mlist = None return HttpResponse("Not implemented yet", status=500) else: mlist = store.get_list(mlist_fqdn) if mlist is None: raise Http404("No archived mailing-list by that name.") if not is_mlist_authorized(request, mlist): return render(request, "errors/private.html", { "mlist": mlist, }, status=403) # Get the user's full name try: client = mailmanclient.Client('%s/3.0' % settings.MAILMAN_REST_SERVER, settings.MAILMAN_API_USER, settings.MAILMAN_API_PASS) mm_user = client.get_user(user_id) except HTTPError: raise Http404("No user with this ID: %s" % user_id) except mailmanclient.MailmanConnectionError: fullname = None else: fullname = mm_user.display_name if not fullname: fullname = store.get_sender_name(user_id) # Get the messages and paginate them messages = store.get_messages_by_user_id(user_id, mlist_fqdn) try: page_num = int(request.GET.get('page', "1")) except ValueError: page_num = 1 messages = paginate(messages, page_num) for message in messages: message.myvote = message.get_vote_by_user_id( request.session.get("user_id")) context = { 'user_id': user_id, 'mlist' : mlist, 'messages': messages, 'fullname': fullname, } return render(request, "user_posts.html", context)
def votes(request): store = get_store(request) # Votes try: votes = Rating.objects.filter(user=request.user) except Rating.DoesNotExist: votes = [] votes = paginate(votes, request.GET.get('vpage')) for vote in votes: vote.message = store.get_message_by_hash_from_list( vote.list_address, vote.messageid) if vote.message is None: vote.delete() votes = [ v for v in votes if v.message is not None ] return render(request, 'ajax/votes.html', { "votes": votes, })
def _thread_list(request, mlist, threads, template_name='hyperkitty/thread_list.html', extra_context=None): categories = [ (c.name, c.name.upper()) for c in ThreadCategory.objects.all() ] \ + [("", "no category")] threads = paginate(threads, request.GET.get('page'), results_per_page=request.GET.get('count')) for thread in threads: # Favorites thread.favorite = False if request.user.is_authenticated(): try: Favorite.objects.get(thread=thread, user=request.user) except Favorite.DoesNotExist: pass else: thread.favorite = True # Category thread.category_hk, thread.category_form = \ get_category_widget(request, thread.category, categories) flash_messages = [] flash_msg = request.GET.get("msg") if flash_msg: flash_msg = { "type": FLASH_MESSAGES[flash_msg][0], "msg": FLASH_MESSAGES[flash_msg][1] } flash_messages.append(flash_msg) context = { 'mlist': mlist, 'threads': threads, 'months_list': get_months(mlist), 'flash_messages': flash_messages, 'per_page_options': [10, 50, 100, 200], } if extra_context is not None: context.update(extra_context) return render(request, template_name, context)
def index(request): mlists = [ml for ml in MailingList.objects.all() if not settings.FILTER_VHOST or show_mlist(ml, request)] # Sorting sort_mode = request.GET.get("sort") if not sort_mode: sort_mode = "popular" if sort_mode == "name": mlists.sort(key=lambda ml: ml.name) elif sort_mode == "active": # Don't show private lists when sorted by activity, to avoid disclosing # info about the private list's activity mlists = [ml for ml in mlists if ml.is_private == False] mlists.sort(key=lambda l: l.recent_threads_count, reverse=True) elif sort_mode == "popular": # Don't show private lists when sorted by popularity, to avoid disclosing # info about the private list's popularity mlists = [l for l in mlists if l.is_private == False] mlists.sort(key=lambda l: l.recent_participants_count, reverse=True) elif sort_mode == "creation": mlists.sort(key=lambda l: l.created_at, reverse=True) else: return HttpResponse("Wrong search parameter", content_type="text/plain", status=500) mlists = paginate(mlists, request.GET.get("page"), results_per_page=request.GET.get("count")) # Permissions for mlist in mlists: if not mlist.is_private: mlist.can_view = True else: if is_mlist_authorized(request, mlist): mlist.can_view = True else: mlist.can_view = False context = {"view_name": "all_lists", "all_lists": mlists, "sort_mode": sort_mode} return render(request, "hyperkitty/index.html", context)
def posts(request, user_id): mlist_fqdn = request.GET.get("list") if mlist_fqdn is None: mlist = None return HttpResponse("Not implemented yet", status=500) else: try: mlist = MailingList.objects.get(name=mlist_fqdn) except MailingList.DoesNotExist: raise Http404("No archived mailing-list by that name.") if not is_mlist_authorized(request, mlist): return render(request, "hyperkitty/errors/private.html", { "mlist": mlist, }, status=403) fullname = Sender.objects.filter(mailman_id=user_id).exclude( name="").values_list("name", flat=True).first() # Get the messages and paginate them messages = Email.objects.filter(mailinglist=mlist, sender__mailman_id=user_id) try: page_num = int(request.GET.get('page', "1")) except ValueError: page_num = 1 messages = paginate(messages, page_num) for message in messages: message.myvote = message.votes.filter(user=request.user).first() context = { 'user_id': user_id, 'mlist': mlist, 'messages': messages, 'fullname': fullname, } return render(request, "hyperkitty/user_posts.html", context)
def posts(request, user_id): mlist_fqdn = request.GET.get("list") if mlist_fqdn is None: mlist = None return HttpResponse("Not implemented yet", status=500) else: try: mlist = MailingList.objects.get(name=mlist_fqdn) except MailingList.DoesNotExist: raise Http404("No archived mailing-list by that name.") if not is_mlist_authorized(request, mlist): return render(request, "hyperkitty/errors/private.html", { "mlist": mlist, }, status=403) fullname = Sender.objects.filter(mailman_id=user_id).exclude(name="" ).values_list("name", flat=True).first() # Get the messages and paginate them messages = Email.objects.filter( mailinglist=mlist, sender__mailman_id=user_id) try: page_num = int(request.GET.get('page', "1")) except ValueError: page_num = 1 messages = paginate(messages, page_num) for message in messages: message.myvote = message.votes.filter( user=request.user).first() context = { 'user_id': user_id, 'mlist' : mlist, 'messages': messages, 'fullname': fullname, } return render(request, "hyperkitty/user_posts.html", context)
def search(request): """ Returns messages corresponding to a query """ mlist_fqdn = request.GET.get("mlist") if mlist_fqdn is None: mlist = None else: try: mlist = MailingList.objects.get(name=mlist_fqdn) except MailingList.DoesNotExist: raise Http404("No archived mailing-list by that name.") if not is_mlist_authorized(request, mlist): return render(request, "hyperkitty/errors/private.html", { "mlist": mlist, }, status=403) query = '' results = EmptySearchQuerySet() sqs = RelatedSearchQuerySet() # Remove private non-subscribed lists if mlist is not None: sqs = sqs.filter(mailinglist__exact=mlist.name) else: excluded_mlists = MailingList.objects.filter( archive_policy=ArchivePolicy.private.value) if request.user.is_authenticated(): subscriptions = request.user.hyperkitty_profile.get_subscriptions() excluded_mlists = excluded_mlists.exclude( list_id__in=subscriptions.keys()) excluded_mlists = excluded_mlists.values_list("name", flat=True) sqs = sqs.exclude(mailinglist__in=excluded_mlists) # Sorting sort_mode = request.GET.get('sort') if sort_mode == "date-asc": sqs = sqs.order_by("date") elif sort_mode == "date-desc": sqs = sqs.order_by("-date") # Handle data if request.GET.get('q'): form = SearchForm( request.GET, searchqueryset=sqs, load_all=True) if form.is_valid(): query = form.cleaned_data['q'] results = form.search() else: form = SearchForm(searchqueryset=sqs, load_all=True) emails = paginate(results, page_num=request.GET.get('page')) for email in emails: if request.user.is_authenticated(): email.object.myvote = email.object.votes.filter(user=request.user).first() else: email.object.myvote = None context = { 'mlist' : mlist, 'form': form, 'emails': emails, 'query': query, 'sort_mode': sort_mode, 'suggestion': None, } if results.query.backend.include_spelling: context['suggestion'] = form.get_suggestion() return render(request, "hyperkitty/search_results.html", context)
def votes(request): all_votes = paginate(request.user.votes.all(), request.GET.get('vpage')) return render(request, 'hyperkitty/ajax/votes.html', { "votes": all_votes, })
def test_page_range(self): objects = range(1000) self.assertEqual(paginate(objects, 1).page_range, [1, 2, 3, 4, '...', 100]) self.assertEqual(paginate(objects, 2).page_range, [1, 2, 3, 4, 5, '...', 100]) self.assertEqual(paginate(objects, 3).page_range, [1, 2, 3, 4, 5, 6, '...', 100]) self.assertEqual(paginate(objects, 4).page_range, [1, 2, 3, 4, 5, 6, 7, '...', 100]) self.assertEqual(paginate(objects, 5).page_range, [1, 2, 3, 4, 5, 6, 7, 8, '...', 100]) self.assertEqual(paginate(objects, 6).page_range, [1, 2, 3, 4, 5, 6, 7, 8, 9, '...', 100]) self.assertEqual(paginate(objects, 7).page_range, [1, '...', 4, 5, 6, 7, 8, 9, 10, '...', 100]) self.assertEqual(paginate(objects, 8).page_range, [1, '...', 5, 6, 7, 8, 9, 10, 11, '...', 100]) self.assertEqual(paginate(objects, 9).page_range, [1, '...', 6, 7, 8, 9, 10, 11, 12, '...', 100]) self.assertEqual(paginate(objects, 10).page_range, [1, '...', 7, 8, 9, 10, 11, 12, 13, '...', 100]) self.assertEqual(paginate(objects, 40).page_range, [1, '...', 37, 38, 39, 40, 41, 42, 43, '...', 100]) self.assertEqual(paginate(objects, 90).page_range, [1, '...', 87, 88, 89, 90, 91, 92, 93, '...', 100]) self.assertEqual(paginate(objects, 91).page_range, [1, '...', 88, 89, 90, 91, 92, 93, 94, '...', 100]) self.assertEqual(paginate(objects, 92).page_range, [1, '...', 89, 90, 91, 92, 93, 94, 95, '...', 100]) self.assertEqual(paginate(objects, 93).page_range, [1, '...', 90, 91, 92, 93, 94, 95, 96, '...', 100]) self.assertEqual(paginate(objects, 94).page_range, [1, '...', 91, 92, 93, 94, 95, 96, 97, '...', 100]) self.assertEqual(paginate(objects, 95).page_range, [1, '...', 92, 93, 94, 95, 96, 97, 98, 99, 100]) self.assertEqual(paginate(objects, 96).page_range, [1, '...', 93, 94, 95, 96, 97, 98, 99, 100]) self.assertEqual(paginate(objects, 97).page_range, [1, '...', 94, 95, 96, 97, 98, 99, 100]) self.assertEqual(paginate(objects, 98).page_range, [1, '...', 95, 96, 97, 98, 99, 100]) self.assertEqual(paginate(objects, 99).page_range, [1, '...', 96, 97, 98, 99, 100]) self.assertEqual(paginate(objects, 100).page_range, [1, '...', 97, 98, 99, 100])
def test_last_page(self): self.assertEqual(paginate(range(100), 1000).number, 10)
def test_default_page(self): self.assertEqual(paginate(range(100), None).number, 1)
def search(request, page=1): """ Returns messages corresponding to a query """ results_per_page = 10 store = get_store(request) query = request.GET.get("query") mlist_fqdn = request.GET.get("list") sort_mode = request.GET.get('sort') if mlist_fqdn is None: mlist = None else: mlist = store.get_list(mlist_fqdn) if mlist is None: raise Http404("No archived mailing-list by that name.") if not is_mlist_authorized(request, mlist): return render(request, "errors/private.html", { "mlist": mlist, }, status=403) if not store.search_index: return render(request, "errors/nosearch.html", {"mlist": mlist}) if not query: return render( request, "search_results.html", { 'mlist': mlist, "query": query or "", 'messages': [], 'total': 0, 'sort_mode': sort_mode, }) try: page_num = int(request.GET.get('page', "1")) except ValueError: page_num = 1 sortedby = None reverse = False if sort_mode == "date-asc": sortedby = "date" elif sort_mode == "date-desc": sortedby = "date" reverse = True query_result = store.search(query, mlist_fqdn, page_num, results_per_page, sortedby=sortedby, reverse=reverse) total = query_result["total"] messages = query_result["results"] for message in messages: message.myvote = message.get_vote_by_user_id( request.session.get("user_id")) paginator = SearchPaginator(messages, 10, total) messages = paginate(messages, page_num, paginator=paginator) context = { 'mlist': mlist, "query": query, 'messages': messages, 'total': total, 'sort_mode': sort_mode, } return render(request, "search_results.html", context)
def test_page_range(self): objects = range(1000) self.assertEqual( paginate(objects, 1).page_range, [1, 2, 3, 4, '...', 100]) self.assertEqual( paginate(objects, 2).page_range, [1, 2, 3, 4, 5, '...', 100]) self.assertEqual( paginate(objects, 3).page_range, [1, 2, 3, 4, 5, 6, '...', 100]) self.assertEqual( paginate(objects, 4).page_range, [1, 2, 3, 4, 5, 6, 7, '...', 100]) self.assertEqual( paginate(objects, 5).page_range, [1, 2, 3, 4, 5, 6, 7, 8, '...', 100]) self.assertEqual( paginate(objects, 6).page_range, [1, 2, 3, 4, 5, 6, 7, 8, 9, '...', 100]) self.assertEqual( paginate(objects, 7).page_range, [1, '...', 4, 5, 6, 7, 8, 9, 10, '...', 100]) self.assertEqual( paginate(objects, 8).page_range, [1, '...', 5, 6, 7, 8, 9, 10, 11, '...', 100]) self.assertEqual( paginate(objects, 9).page_range, [1, '...', 6, 7, 8, 9, 10, 11, 12, '...', 100]) self.assertEqual( paginate(objects, 10).page_range, [1, '...', 7, 8, 9, 10, 11, 12, 13, '...', 100]) self.assertEqual( paginate(objects, 40).page_range, [1, '...', 37, 38, 39, 40, 41, 42, 43, '...', 100]) self.assertEqual( paginate(objects, 90).page_range, [1, '...', 87, 88, 89, 90, 91, 92, 93, '...', 100]) self.assertEqual( paginate(objects, 91).page_range, [1, '...', 88, 89, 90, 91, 92, 93, 94, '...', 100]) self.assertEqual( paginate(objects, 92).page_range, [1, '...', 89, 90, 91, 92, 93, 94, 95, '...', 100]) self.assertEqual( paginate(objects, 93).page_range, [1, '...', 90, 91, 92, 93, 94, 95, 96, '...', 100]) self.assertEqual( paginate(objects, 94).page_range, [1, '...', 91, 92, 93, 94, 95, 96, 97, '...', 100]) self.assertEqual( paginate(objects, 95).page_range, [1, '...', 92, 93, 94, 95, 96, 97, 98, 99, 100]) self.assertEqual( paginate(objects, 96).page_range, [1, '...', 93, 94, 95, 96, 97, 98, 99, 100]) self.assertEqual( paginate(objects, 97).page_range, [1, '...', 94, 95, 96, 97, 98, 99, 100]) self.assertEqual( paginate(objects, 98).page_range, [1, '...', 95, 96, 97, 98, 99, 100]) self.assertEqual( paginate(objects, 99).page_range, [1, '...', 96, 97, 98, 99, 100]) self.assertEqual( paginate(objects, 100).page_range, [1, '...', 97, 98, 99, 100])
def search(request, page=1): """ Returns messages corresponding to a query """ results_per_page = 10 store = get_store(request) query = request.GET.get("query") mlist_fqdn = request.GET.get("list") sort_mode = request.GET.get('sort') if mlist_fqdn is None: mlist = None else: mlist = store.get_list(mlist_fqdn) if mlist is None: raise Http404("No archived mailing-list by that name.") if not is_mlist_authorized(request, mlist): return render(request, "errors/private.html", { "mlist": mlist, }, status=403) if not store.search_index: return render(request, "errors/nosearch.html", {"mlist": mlist}) if not query: return render(request, "search_results.html", { 'mlist' : mlist, "query": query or "", 'messages': [], 'total': 0, 'sort_mode': sort_mode, }) try: page_num = int(request.GET.get('page', "1")) except ValueError: page_num = 1 sortedby = None reverse = False if sort_mode == "date-asc": sortedby = "date" elif sort_mode == "date-desc": sortedby = "date" reverse = True query_result = store.search(query, mlist_fqdn, page_num, results_per_page, sortedby=sortedby, reverse=reverse) total = query_result["total"] messages = query_result["results"] for message in messages: set_message_votes(message, request.user) paginator = SearchPaginator(messages, 10, total) messages = paginate(messages, page_num, paginator=paginator) context = { 'mlist' : mlist, "query": query, 'messages': messages, 'total': total, 'sort_mode': sort_mode, } return render(request, "search_results.html", context)
def search(request): """ Returns messages corresponding to a query """ mlist_fqdn = request.GET.get("mlist") if mlist_fqdn is None: mlist = None else: try: mlist = MailingList.objects.get(name=mlist_fqdn) except MailingList.DoesNotExist: raise Http404("No archived mailing-list by that name.") if not is_mlist_authorized(request, mlist): return render(request, "hyperkitty/errors/private.html", { "mlist": mlist, }, status=403) query = '' results = EmptySearchQuerySet() sqs = RelatedSearchQuerySet() # Remove private non-subscribed lists if mlist is not None: sqs = sqs.filter(mailinglist__exact=mlist.name) else: excluded_mlists = MailingList.objects.filter( archive_policy=ArchivePolicy.private.value) if request.user.is_authenticated(): subscriptions = request.user.hyperkitty_profile.get_subscriptions() excluded_mlists = excluded_mlists.exclude( name__in=subscriptions.keys()) excluded_mlists = excluded_mlists.values_list("name", flat=True) sqs = sqs.exclude(mailinglist__in=excluded_mlists) # Sorting sort_mode = request.GET.get('sort') if sort_mode == "date-asc": sqs = sqs.order_by("date") elif sort_mode == "date-desc": sqs = sqs.order_by("-date") # Handle data if request.GET.get('q'): form = SearchForm( request.GET, searchqueryset=sqs, load_all=True) if form.is_valid(): query = form.cleaned_data['q'] results = form.search() else: form = SearchForm(searchqueryset=sqs, load_all=True) messages = paginate(results, page_num=request.GET.get('page')) for message in messages: if request.user.is_authenticated(): message.object.myvote = message.object.votes.filter(user=request.user).first() else: message.object.myvote = None context = { 'mlist' : mlist, 'form': form, 'messages': messages, 'query': query, 'sort_mode': sort_mode, 'suggestion': None, } if results.query.backend.include_spelling: context['suggestion'] = form.get_suggestion() return render(request, "hyperkitty/search_results.html", context)