def test_tagged_feed(self): """Test the tagged feed.""" t = tag(name='green', slug='green', save=True) q = question(save=True) q.tags.add('green') items = TaggedQuestionsFeed().items(t) eq_(1, len(items)) eq_(q.id, items[0].id) cache.clear() q = question(save=True) q.tags.add('green') q.updated = datetime.now() + timedelta(days=1) q.save() items = TaggedQuestionsFeed().items(t) eq_(2, len(items)) eq_(q.id, items[0].id)
def test_tagged_feed(self): """Test the tagged feed.""" t = TagFactory(name="green", slug="green") q = QuestionFactory() q.tags.add("green") items = TaggedQuestionsFeed().items(t) eq_(1, len(items)) eq_(q.id, items[0].id) cache.clear() q = QuestionFactory() q.tags.add("green") q.updated = datetime.now() + timedelta(days=1) q.save() items = TaggedQuestionsFeed().items(t) eq_(2, len(items)) eq_(q.id, items[0].id)
from django.contrib.contenttypes.models import ContentType from kitsune.questions.feeds import (QuestionsFeed, AnswersFeed, TaggedQuestionsFeed) from kitsune.questions.models import Question, Answer from kitsune.flagit import views as flagit_views from kitsune.sumo.views import handle404 if settings.DISABLE_FEEDS: questions_feed_view = handle404 answers_feed_view = handle404 tagged_feed_view = handle404 else: questions_feed_view = QuestionsFeed() answers_feed_view = AnswersFeed() tagged_feed_view = TaggedQuestionsFeed() urlpatterns = patterns( 'kitsune.questions.views', url(r'^$', 'product_list', name='questions.home'), url(r'^/answer-preview-async$', 'answer_preview_async', name='questions.answer_preview_async'), url(r'^/dashboard/metrics$', 'metrics', name='questions.metrics'), url(r'^/dashboard/metrics/(?P<locale_code>[^/]+)$', 'metrics', name='questions.locale_metrics'), # AAQ url(r'^/new$', 'aaq', name='questions.aaq_step1'), url(r'^/new/confirm$', 'aaq_confirm', name='questions.aaq_confirm'),
url(r'^/(?P<question_id>\d+)/add-tag$', 'add_tag', name='questions.add_tag'), url(r'^/(?P<question_id>\d+)/remove-tag$', 'remove_tag', name='questions.remove_tag'), url(r'^/(?P<question_id>\d+)/add-tag-async$', 'add_tag_async', name='questions.add_tag_async'), url(r'^/(?P<question_id>\d+)/remove-tag-async$', 'remove_tag_async', name='questions.remove_tag_async'), # Feeds # Note: this needs to be above questions.list because "feed" # matches the product slug regex. url(r'^/feed$', QuestionsFeed(), name='questions.feed'), url(r'^/(?P<question_id>\d+)/feed$', AnswersFeed(), name='questions.answers.feed'), url(r'^/tagged/(?P<tag_slug>[\w\-]+)/feed$', TaggedQuestionsFeed(), name='questions.tagged_feed'), # Mark as spam url(r'^/mark_spam$', 'mark_spam', name='questions.mark_spam'), url(r'^/unmark_spam$', 'unmark_spam', name='questions.unmark_spam'), # Question lists url(r'^/(?P<product_slug>[\w+\-\,]+)$', 'question_list', name='questions.list'), # Flag content ("Report this post") url(r'^/(?P<object_id>\d+)/flag$', flagit_views.flag, {'content_type': ContentType.objects.get_for_model(Question).id}, name='questions.flag'), url(r'^/(?P<question_id>\d+)/flag/(?P<object_id>\d+)$', flagit_views.flag,
def question_list(request, product_slug): """View the list of questions.""" if settings.DISABLE_QUESTIONS_LIST_GLOBAL: messages.add_message(request, messages.WARNING, "You cannot list questions at this time.") return HttpResponseRedirect("/") filter_ = request.GET.get("filter") owner = request.GET.get("owner", request.session.get("questions_owner", "all")) show = request.GET.get("show") # Show defaults to NEEDS ATTENTION if show not in FILTER_GROUPS: show = "needs-attention" tagged = request.GET.get("tagged") tags = None topic_slug = request.GET.get("topic") order = request.GET.get("order", "updated") if order not in ORDER_BY: order == "updated" sort = request.GET.get("sort", "desc") product_slugs = product_slug.split(",") products = [] if len(product_slugs) > 1 or product_slugs[0] != "all": for slug in product_slugs: products.append(get_object_or_404(Product, slug=slug)) multiple = len(products) > 1 else: # We want all products (no product filtering at all). if settings.DISABLE_QUESTIONS_LIST_ALL: messages.add_message( request, messages.WARNING, "You cannot list all questions at this time.") return HttpResponseRedirect("/") products = None multiple = True if topic_slug and not multiple: # We don't support topics when there is more than one product. # There is no way to know what product the topic applies to. try: topic = Topic.objects.get(slug=topic_slug, product=products[0]) except Topic.DoesNotExist: topic = None else: topic = None question_qs = Question.objects if filter_ not in FILTER_GROUPS[show]: filter_ = None if filter_ == "new": question_qs = question_qs.new() elif filter_ == "unhelpful-answers": question_qs = question_qs.unhelpful_answers() elif filter_ == "needsinfo": question_qs = question_qs.needs_info() elif filter_ == "solution-provided": question_qs = question_qs.solution_provided() elif filter_ == "solved": question_qs = question_qs.solved() elif filter_ == "locked": question_qs = question_qs.locked() elif filter_ == "recently-unanswered": question_qs = question_qs.recently_unanswered() else: if show == "needs-attention": question_qs = question_qs.needs_attention() if show == "responded": question_qs = question_qs.responded() if show == "done": question_qs = question_qs.done() question_qs = question_qs.select_related("creator", "last_answer", "last_answer__creator") question_qs = question_qs.prefetch_related("topic", "topic__product") question_qs = question_qs.filter(creator__is_active=1) if not request.user.has_perm("flagit.can_moderate"): question_qs = question_qs.filter(is_spam=False) if owner == "mine" and request.user.is_authenticated: criteria = Q(answers__creator=request.user) | Q(creator=request.user) question_qs = question_qs.filter(criteria).distinct() else: owner = None feed_urls = (( urlparams(reverse("questions.feed"), product=product_slug, topic=topic_slug), QuestionsFeed().title(), ), ) if tagged: tag_slugs = tagged.split(",") tags = Tag.objects.filter(slug__in=tag_slugs) if tags: for t in tags: question_qs = question_qs.filter(tags__name__in=[t.name]) if len(tags) == 1: feed_urls += (( reverse("questions.tagged_feed", args=[tags[0].slug]), TaggedQuestionsFeed().title(tags[0]), ), ) else: question_qs = Question.objects.none() # Exclude questions over 90 days old without an answer. oldest_date = date.today() - timedelta(days=90) question_qs = question_qs.exclude(created__lt=oldest_date, num_answers=0) # Filter by products. if products: # This filter will match if any of the products on a question have the # correct id. question_qs = question_qs.filter(product__in=products).distinct() # Filter by topic. if topic: # This filter will match if any of the topics on a question have the # correct id. question_qs = question_qs.filter(topic__id=topic.id) # Filter by locale for AAQ locales, and by locale + default for others. if request.LANGUAGE_CODE in QuestionLocale.objects.locales_list(): locale_query = Q(locale=request.LANGUAGE_CODE) else: locale_query = Q(locale=request.LANGUAGE_CODE) locale_query |= Q(locale=settings.WIKI_DEFAULT_LANGUAGE) question_qs = question_qs.filter(locale_query) # Set the order. # Set a default value if a user requested a non existing order parameter order_by = ORDER_BY.get(order, ["updated"])[0] question_qs = question_qs.order_by(order_by if sort == "asc" else "-%s" % order_by) try: questions_page = simple_paginate(request, question_qs, per_page=config.QUESTIONS_PER_PAGE) except (PageNotAnInteger, EmptyPage): # If we aren't on page 1, redirect there. # TODO: Is 404 more appropriate? if request.GET.get("page", "1") != "1": url = build_paged_url(request) return HttpResponseRedirect(urlparams(url, page=1)) # Recent answered stats extra_filters = locale_query if products: extra_filters &= Q(product__in=products) recent_asked_count = Question.recent_asked_count(extra_filters) recent_unanswered_count = Question.recent_unanswered_count(extra_filters) if recent_asked_count: recent_answered_percent = int( (float(recent_asked_count - recent_unanswered_count) / recent_asked_count) * 100) else: recent_answered_percent = 0 # List of products to fill the selector. product_list = Product.objects.filter(visible=True) # List of topics to fill the selector. Only shows if there is exactly # one product selected. if products and not multiple: topic_list = Topic.objects.filter(visible=True, product=products[0])[:10] else: topic_list = [] # Store current filters in the session if request.user.is_authenticated: request.session["questions_owner"] = owner data = { "questions": questions_page, "feeds": feed_urls, "filter": filter_, "owner": owner, "show": show, "filters": FILTER_GROUPS[show], "order": order, "orders": ORDER_BY, "sort": sort, "tags": tags, "tagged": tagged, "recent_asked_count": recent_asked_count, "recent_unanswered_count": recent_unanswered_count, "recent_answered_percent": recent_answered_percent, "product_list": product_list, "products": products, "product_slug": product_slug, "multiple_products": multiple, "all_products": product_slug == "all", "topic_list": topic_list, "topic": topic, } return render(request, "questions/question_list.html", data)
{'content_type': ContentType.objects.get_for_model(Question).id}, name='questions.flag'), url(r'^/(?P<question_id>\d+)/flag/(?P<object_id>\d+)$', flagit_views.flag, {'content_type': ContentType.objects.get_for_model(Answer).id}, name='questions.answer_flag'), # Subcribe by email url(r'^/(?P<question_id>\d+)/watch$', 'watch_question', name='questions.watch'), url(r'^/(?P<question_id>\d+)/unwatch$', 'unwatch_question', name='questions.unwatch'), url(r'^/confirm/(?P<watch_id>\d+)/(?P<secret>\w+)$', 'activate_watch', name='questions.activate_watch'), url(r'^/unsubscribe/(?P<watch_id>\d+)/(?P<secret>\w+)$', 'unsubscribe_watch', name='questions.unsubscribe'), # Feeds url(r'^/feed$', QuestionsFeed(), name='questions.feed'), url(r'^/(?P<question_id>\d+)/feed$', AnswersFeed(), name='questions.answers.feed'), url(r'^/tagged/(?P<tag_slug>[\w\-]+)/feed$', TaggedQuestionsFeed(), name='questions.tagged_feed'), )