-from forum.auth import *
-from forum.const import *
-from forum import auth
-from forum.utils.forms import get_next_url
-
-# used in index page
-#refactor - move these numbers somewhere?
-INDEX_PAGE_SIZE = 30
-INDEX_AWARD_SIZE = 15
-INDEX_TAGS_SIZE = 25
-# used in tags list
-DEFAULT_PAGE_SIZE = 60
-# used in questions
-QUESTIONS_PAGE_SIZE = 30
-# used in answers
-ANSWERS_PAGE_SIZE = 10
-
-markdowner = Markdown(html4tags=True)
-
-#system to display main content
-def _get_tags_cache_json():#service routine used by views requiring tag list in the javascript space
- """returns list of all tags in json format
- no caching yet, actually
- """
- tags = Tag.objects.filter(deleted=False).all()
- tags_list = []
- for tag in tags:
- dic = {'n': tag.name, 'c': tag.used_count}
- tags_list.append(dic)
- tags = simplejson.dumps(tags_list)
- return tags
-
-def _get_and_remember_questions_sort_method(request, view_dic, default):#service routine used by q listing views and question view
- """manages persistence of post sort order
- it is assumed that when user wants newest question -
- then he/she wants newest answers as well, etc.
- how far should this assumption actually go - may be a good question
- """
- if default not in view_dic:
- raise Exception('default value must be in view_dic')
-
- q_sort_method = request.REQUEST.get('sort', None)
- if q_sort_method == None:
- q_sort_method = request.session.get('questions_sort_method', default)
-
- if q_sort_method not in view_dic:
- q_sort_method = default
- request.session['questions_sort_method'] = q_sort_method
- return q_sort_method, view_dic[q_sort_method]
-
-#refactor? - we have these
-#views that generate a listing of questions in one way or another:
-#index, unanswered, questions, search, tag
-#should we dry them up?
-#related topics - information drill-down, search refinement
-
-def index(request):#generates front page - shows listing of questions sorted in various ways
- """index view mapped to the root url of the Q&A site
- """
- view_dic = {
- "latest":"-last_activity_at",
- "hottest":"-answer_count",
- "mostvoted":"-score",
- }
- view_id, orderby = _get_and_remember_questions_sort_method(request, view_dic, 'latest')
-
- pagesize = request.session.get("pagesize",QUESTIONS_PAGE_SIZE)
+from forum.forms import get_next_url
+from forum.actions import QuestionViewAction
+from forum.http_responses import HttpResponseUnauthorized
+from forum.feed import RssQuestionFeed, RssAnswerFeed
+from forum.utils.pagination import generate_uri
+import decorators
+
+class HottestQuestionsSort(pagination.SortBase):
+ def apply(self, questions):
+ return questions.annotate(new_child_count=Count('all_children')).filter(
+ all_children__added_at__gt=datetime.datetime.now() - datetime.timedelta(days=1)).order_by('-new_child_count')
+
+
+class QuestionListPaginatorContext(pagination.PaginatorContext):
+ def __init__(self, id='QUESTIONS_LIST', prefix='', default_pagesize=30):
+ super (QuestionListPaginatorContext, self).__init__(id, sort_methods=(
+ (_('active'), pagination.SimpleSort(_('active'), '-last_activity_at', _("Most <strong>recently updated</strong> questions"))),
+ (_('newest'), pagination.SimpleSort(_('newest'), '-added_at', _("most <strong>recently asked</strong> questions"))),
+ (_('hottest'), HottestQuestionsSort(_('hottest'), _("most <strong>active</strong> questions in the last 24 hours</strong>"))),
+ (_('mostvoted'), pagination.SimpleSort(_('most voted'), '-score', _("most <strong>voted</strong> questions"))),
+ ), pagesizes=(15, 30, 50), default_pagesize=default_pagesize, prefix=prefix)
+
+class AnswerSort(pagination.SimpleSort):
+ def apply(self, answers):
+ if not settings.DISABLE_ACCEPTING_FEATURE:
+ return answers.order_by(*(['-marked'] + list(self._get_order_by())))
+ else:
+ return super(AnswerSort, self).apply(answers)
+
+class AnswerPaginatorContext(pagination.PaginatorContext):
+ def __init__(self, id='ANSWER_LIST', prefix='', default_pagesize=10):
+ super (AnswerPaginatorContext, self).__init__(id, sort_methods=(
+ (_('oldest'), AnswerSort(_('oldest answers'), 'added_at', _("oldest answers will be shown first"))),
+ (_('newest'), AnswerSort(_('newest answers'), '-added_at', _("newest answers will be shown first"))),
+ (_('votes'), AnswerSort(_('popular answers'), ('-score', 'added_at'), _("most voted answers will be shown first"))),
+ ), default_sort=_('votes'), pagesizes=(5, 10, 20), default_pagesize=default_pagesize, prefix=prefix)
+
+class TagPaginatorContext(pagination.PaginatorContext):
+ def __init__(self):
+ super (TagPaginatorContext, self).__init__('TAG_LIST', sort_methods=(
+ (_('name'), pagination.SimpleSort(_('by name'), 'name', _("sorted alphabetically"))),
+ (_('used'), pagination.SimpleSort(_('by popularity'), '-used_count', _("sorted by frequency of tag use"))),
+ ), default_sort=_('used'), pagesizes=(30, 60, 120))
+
+
+def feed(request):
+ return RssQuestionFeed(
+ request,
+ Question.objects.filter_state(deleted=False).order_by('-last_activity_at'),
+ settings.APP_TITLE + _(' - ')+ _('latest questions'),
+ settings.APP_DESCRIPTION)(request)
+
+@decorators.render('index.html')
+def index(request):
+ paginator_context = QuestionListPaginatorContext()
+ paginator_context.base_path = reverse('questions')
+ return question_list(request,
+ Question.objects.all(),
+ base_path=reverse('questions'),
+ feed_url=reverse('latest_questions_feed'),
+ paginator_context=paginator_context)
+
+@decorators.render('questions.html', 'unanswered', _('unanswered'), weight=400)
+def unanswered(request):
+ return question_list(request,
+ Question.objects.exclude(id__in=Question.objects.filter(children__marked=True).distinct()),
+ _('open questions without an accepted answer'),
+ None,
+ _("Unanswered Questions"))
+
+@decorators.render('questions.html', 'questions', _('questions'), weight=0)
+def questions(request):
+ return question_list(request, Question.objects.all(), _('questions'))
+
+@decorators.render('questions.html')
+def tag(request, tag):
+