diff options
author | Adolfo Fitoria <fitoria@fitoria-laptop.(none)> | 2010-02-09 14:12:05 -0600 |
---|---|---|
committer | Adolfo Fitoria <fitoria@fitoria-laptop.(none)> | 2010-02-09 14:12:05 -0600 |
commit | 8de2b9131ddcef647799cf8e1e79921284523073 (patch) | |
tree | 81e17d84530990e35a0accba3a7886266a601482 /forum/views.py | |
parent | 7e95e6481d1e81e43d4b442cbcf3fe37f20d89cc (diff) | |
parent | 9d1fb9890b97beb55461ca34f9757bc685461130 (diff) | |
download | askbot-8de2b9131ddcef647799cf8e1e79921284523073.tar.gz askbot-8de2b9131ddcef647799cf8e1e79921284523073.tar.bz2 askbot-8de2b9131ddcef647799cf8e1e79921284523073.zip |
Merge branch 'evgenyfadeev/master'
Conflicts:
.gitignore
INSTALL
TODO
cnprog.wsgi
django_authopenid/urls.py
django_authopenid/views.py
drop-all-tables.sh
forum/auth.py
forum/managers.py
forum/models.py
forum/templatetags/extra_tags.py
forum/views.py
locale/es/LC_MESSAGES/django.mo
locale/es/LC_MESSAGES/django.po
settings.py
settings_local.py.dist
sql_scripts/update_2009_01_25_001.sql
sql_scripts/update_2009_02_26_001.sql
sql_scripts/update_2009_04_10_001.sql
templates/authopenid/confirm_email.txt
templates/authopenid/sendpw_email.txt
templates/content/js/compress.bat
templates/content/js/flot-build.bat
templates/content/style/style.css
templates/footer.html
templates/question.html
templates/user_reputation.html
templates/user_stats.html
templates/user_votes.html
templates/users_questions.html
urls.py
Diffstat (limited to 'forum/views.py')
-rw-r--r-- | forum/views.py | 1204 |
1 files changed, 737 insertions, 467 deletions
diff --git a/forum/views.py b/forum/views.py index 6c79bfbd..65b80d0e 100644 --- a/forum/views.py +++ b/forum/views.py @@ -2,20 +2,23 @@ import calendar from django.conf import settings from django.contrib.auth.decorators import login_required -from django.contrib.contenttypes.models import ContentType -from django.core.files.storage import default_storage -from django.core.paginator import EmptyPage -from django.core.paginator import InvalidPage -from django.core.paginator import Paginator -from django.http import Http404 -from django.http import HttpResponse -from django.http import HttpResponseRedirect -from django.shortcuts import get_object_or_404 -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.utils import simplejson +from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404 +from django.core.paginator import Paginator, EmptyPage, InvalidPage +from django.template import RequestContext, loader from django.utils.html import * +from django.utils import simplejson +from django.core import serializers +from django.core.mail import mail_admins +from django.db import transaction +from django.db.models import Count, Q +from django.contrib.contenttypes.models import ContentType from django.utils.translation import ugettext as _ +from django.utils.datastructures import SortedDict +from django.template.defaultfilters import slugify +from django.core.exceptions import PermissionDenied + +from utils.html import sanitize_html +from utils.decorators import ajax_method, ajax_login_required from markdown2 import Markdown import os.path import random @@ -29,7 +32,8 @@ from forum.diff import textDiff as htmldiff from forum.forms import * from forum.models import * from forum.user import * -from utils.html import sanitize_html +from forum import auth +from django_authopenid.util import get_next_url # used in index page INDEX_PAGE_SIZE = 20 @@ -65,42 +69,85 @@ def _get_tags_cache_json(): tags = simplejson.dumps(tags_list) return tags +def _get_and_remember_questions_sort_method(request, view_dic, default): + 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] + def index(request): - view_id = request.GET.get('sort', None) view_dic = { - "latest":"-last_activity_at", - "hottest":"-answer_count", - "mostvoted":"-score", - "trans": "-last_activity_at" - } - try: - orderby = view_dic[view_id] - except KeyError: - view_id = "latest" - orderby = "-added_at" - # group questions by author_id of 28,29 - if view_id == 'trans': - questions = Question.objects.get_translation_questions(orderby, INDEX_PAGE_SIZE) - else: - questions = Question.objects.get_questions_by_pagesize(orderby, INDEX_PAGE_SIZE) + "latest":"-last_activity_at", + "hottest":"-answer_count", + "mostvoted":"-score", + } + view_id, orderby = _get_and_remember_questions_sort_method(request, view_dic, 'latest') + + page_size = request.session.get('pagesize', QUESTIONS_PAGE_SIZE) + questions = Question.objects.exclude(deleted=True).order_by(orderby)[:page_size] # RISK - inner join queries questions = questions.select_related() tags = Tag.objects.get_valid_tags(INDEX_TAGS_SIZE) awards = Award.objects.get_recent_awards() + (interesting_tag_names, ignored_tag_names) = (None, None) + if request.user.is_authenticated(): + pt = MarkedTag.objects.filter(user=request.user) + interesting_tag_names = pt.filter(reason='good').values_list('tag__name', flat=True) + ignored_tag_names = pt.filter(reason='bad').values_list('tag__name', flat=True) + + tags_autocomplete = _get_tags_cache_json() + return render_to_response('index.html', { - "questions": questions, - "tab_id": view_id, - "tags": tags, - "awards": awards[:INDEX_AWARD_SIZE], - }, context_instance=RequestContext(request)) + 'interesting_tag_names': interesting_tag_names, + 'tags_autocomplete': tags_autocomplete, + 'ignored_tag_names': ignored_tag_names, + "questions" : questions, + "tab_id" : view_id, + "tags" : tags, + "awards" : awards[:INDEX_AWARD_SIZE], + }, context_instance=RequestContext(request)) def about(request): return render_to_response('about.html', context_instance=RequestContext(request)) def faq(request): - return render_to_response('faq.html', context_instance=RequestContext(request)) + data = { + 'gravatar_faq_url': reverse('faq') + '#gravatar', + 'send_email_key_url': reverse('send_email_key'), + 'ask_question_url': reverse('ask'), + } + return render_to_response('faq.html', data, context_instance=RequestContext(request)) + +def feedback(request): + data = {} + form = None + if request.method == "POST": + form = FeedbackForm(request.POST) + if form.is_valid(): + if not request.user.is_authenticated: + data['email'] = form.cleaned_data.get('email',None) + data['message'] = form.cleaned_data['message'] + data['name'] = form.cleaned_data.get('name',None) + message = render_to_response('feedback_email.txt',data,context_instance=RequestContext(request)) + mail_admins(_('Q&A forum feedback'), message) + msg = _('Thanks for the feedback!') + request.user.message_set.create(message=msg) + return HttpResponseRedirect(get_next_url(request)) + else: + form = FeedbackForm(initial={'next':get_next_url(request)}) + + data['form'] = form + return render_to_response('feedback.html', data, context_instance=RequestContext(request)) +feedback.CANCEL_MESSAGE=_('We look forward to hearing your feedback! Please, give it next time :)') def privacy(request): return render_to_response('privacy.html', context_instance=RequestContext(request)) @@ -113,7 +160,7 @@ def questions(request, tagname=None, unanswered=False): List of Questions, Tagged questions, and Unanswered questions. """ # template file - # "questions.html" or "unanswered.html" + # "questions.html" or maybe index.html in the future template_file = "questions.html" # get pagesize from session, if failed then get default value pagesize = request.session.get("pagesize", 10) @@ -122,27 +169,65 @@ def questions(request, tagname=None, unanswered=False): except ValueError: page = 1 - view_id = request.GET.get('sort', None) - view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score"} - try: - orderby = view_dic[view_id] - except KeyError: - view_id = "latest" - orderby = "-added_at" + view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" } + view_id, orderby = _get_and_remember_questions_sort_method(request,view_dic,'latest') # check if request is from tagged questions + qs = Question.objects.exclude(deleted=True) + if tagname is not None: - objects = Question.objects.get_questions_by_tag(tagname, orderby) - elif unanswered: - #check if request is from unanswered questions - template_file = "unanswered.html" - objects = Question.objects.get_unanswered_questions(orderby) - else: - objects = Question.objects.get_questions(orderby) + qs = qs.filter(tags__name = unquote(tagname)) - # RISK - inner join queries - objects = objects.select_related(depth=1); - objects_list = Paginator(objects, pagesize) + if unanswered: + qs = qs.exclude(answer_accepted=True) + + author_name = None + #user contributed questions & answers + if 'user' in request.GET: + try: + author_name = request.GET['user'] + u = User.objects.get(username=author_name) + qs = qs.filter(Q(author=u) | Q(answers__author=u)) + except User.DoesNotExist: + author_name = None + + if request.user.is_authenticated(): + uid_str = str(request.user.id) + qs = qs.extra( + select = SortedDict([ + ( + 'interesting_score', + 'SELECT COUNT(1) FROM forum_markedtag, question_tags ' + + 'WHERE forum_markedtag.user_id = %s ' + + 'AND forum_markedtag.tag_id = question_tags.tag_id ' + + 'AND forum_markedtag.reason = "good" ' + + 'AND question_tags.question_id = question.id' + ), + ]), + select_params = (uid_str,), + ) + if request.user.hide_ignored_questions: + ignored_tags = Tag.objects.filter(user_selections__reason='bad', + user_selections__user = request.user) + qs = qs.exclude(tags__in=ignored_tags) + else: + qs = qs.extra( + select = SortedDict([ + ( + 'ignored_score', + 'SELECT COUNT(1) FROM forum_markedtag, question_tags ' + + 'WHERE forum_markedtag.user_id = %s ' + + 'AND forum_markedtag.tag_id = question_tags.tag_id ' + + 'AND forum_markedtag.reason = "bad" ' + + 'AND question_tags.question_id = question.id' + ) + ]), + select_params = (uid_str, ) + ) + + qs = qs.select_related(depth=1).order_by(orderby) + + objects_list = Paginator(qs, pagesize) questions = objects_list.page(page) # Get related tags from this page objects @@ -150,28 +235,41 @@ def questions(request, tagname=None, unanswered=False): related_tags = Tag.objects.get_tags_by_questions(questions.object_list) else: related_tags = None - return render_to_response(template_file, { - "questions": questions, - "tab_id": view_id, - "questions_count": objects_list.count, - "tags": related_tags, - "searchtag": tagname, - "is_unanswered": unanswered, - "context": { - 'is_paginated': True, - 'pages': objects_list.num_pages, - 'page': page, - 'has_previous': questions.has_previous(), - 'has_next': questions.has_next(), - 'previous': questions.previous_page_number(), - 'next': questions.next_page_number(), - 'base_url': request.path + '?sort=%s&' % view_id, - 'pagesize': pagesize - }}, context_instance=RequestContext(request)) + tags_autocomplete = _get_tags_cache_json() + + # get the list of interesting and ignored tags + (interesting_tag_names, ignored_tag_names) = (None, None) + if request.user.is_authenticated(): + pt = MarkedTag.objects.filter(user=request.user) + interesting_tag_names = pt.filter(reason='good').values_list('tag__name', flat=True) + ignored_tag_names = pt.filter(reason='bad').values_list('tag__name', flat=True) -def create_new_answer(question=None, author=None, \ - added_at=None, wiki=False, \ - text='', email_notify=False): + return render_to_response(template_file, { + "questions" : questions, + "author_name" : author_name, + "tab_id" : view_id, + "questions_count" : objects_list.count, + "tags" : related_tags, + "tags_autocomplete" : tags_autocomplete, + "searchtag" : tagname, + "is_unanswered" : unanswered, + "interesting_tag_names": interesting_tag_names, + 'ignored_tag_names': ignored_tag_names, + "context" : { + 'is_paginated' : True, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': questions.has_previous(), + 'has_next': questions.has_next(), + 'previous': questions.previous_page_number(), + 'next': questions.next_page_number(), + 'base_url' : request.path + '?sort=%s&' % view_id, + 'pagesize' : pagesize + }}, context_instance=RequestContext(request)) + +def create_new_answer( question=None, author=None,\ + added_at=None, wiki=False,\ + text='', email_notify=False): html = sanitize_html(markdowner.convert(text)) @@ -208,16 +306,12 @@ def create_new_answer(question=None, author=None, \ #set notification/delete if email_notify: - try: - EmailFeed.objects.get(feed_id=question.id, subscriber_id=author.id, feed_content_type=question_type) - except EmailFeed.DoesNotExist: - feed = EmailFeed(content=question, subscriber=author) - feed.save() + if author not in question.followed_by.all(): + question.followed_by.add(author) else: #not sure if this is necessary. ajax should take care of this... try: - feed = Email.objects.get(feed_id=question.id, subscriber_id=author.id, feed_content_type=question_type) - feed.delete() + question.followed_by.remove(author) except: pass @@ -267,7 +361,7 @@ def ask(request): if form.is_valid(): added_at = datetime.datetime.now() - title = strip_tags(form.cleaned_data['title']).strip() + title = strip_tags(form.cleaned_data['title'].strip()) wiki = form.cleaned_data['wiki'] tagnames = form.cleaned_data['tags'].strip() text = form.cleaned_data['text'] @@ -301,28 +395,42 @@ def ask(request): ip_addr=request.META['REMOTE_ADDR'], ) question.save() - return HttpResponseRedirect('%s%s%s' % (_('/account/'), _('signin/'), ('newquestion/'))) + return HttpResponseRedirect(reverse('user_signin_new_question')) else: form = AskForm() tags = _get_tags_cache_json() return render_to_response('ask.html', { - 'form': form, - 'tags': tags, - }, context_instance=RequestContext(request)) + 'form' : form, + 'tags' : tags, + 'email_validation_faq_url':reverse('faq') + '#validate', + }, context_instance=RequestContext(request)) def question(request, id): try: page = int(request.GET.get('page', '1')) except ValueError: page = 1 - view_id = request.GET.get('sort', 'votes') - view_dic = {"latest":"-added_at", "oldest":"added_at", "votes":"-score"} + + view_id = request.GET.get('sort', None) + view_dic = {"latest":"-added_at", "oldest":"added_at", "votes":"-score" } try: orderby = view_dic[view_id] except KeyError: - view_id = "votes" - orderby = "-score" + qsm = request.session.get('questions_sort_method',None) + if qsm in ('mostvoted','latest'): + logging.debug('loaded from session ' + qsm) + if qsm == 'mostvoted': + view_id = 'votes' + orderby = '-score' + else: + view_id = 'latest' + orderby = '-added_at' + else: + view_id = "votes" + orderby = "-score" + + logging.debug('view_id=' + str(view_id)) question = get_object_or_404(Question, id=id) if question.deleted and not can_view_deleted_post(request.user, question): @@ -345,8 +453,11 @@ def question(request, id): vote_value = -1 if vote.is_upvote(): vote_value = 1 - user_answer_votes[vote.object_id] = vote_value - + user_answer_votes[answer.id] = vote_value + + if answers is not None: + answers = answers.order_by("-accepted", orderby) + filtered_answers = [] for answer in answers: if answer.deleted == True: @@ -357,8 +468,38 @@ def question(request, id): objects_list = Paginator(filtered_answers, ANSWERS_PAGE_SIZE) page_objects = objects_list.page(page) - # update view count - Question.objects.update_view_count(question) + + #todo: merge view counts per user and per session + #1) view count per session + update_view_count = False + if 'question_view_times' not in request.session: + request.session['question_view_times'] = {} + + last_seen = request.session['question_view_times'].get(question.id,None) + updated_when, updated_who = question.get_last_update_info() + + if updated_who != request.user: + if last_seen: + if last_seen < updated_when: + update_view_count = True + else: + update_view_count = True + + request.session['question_view_times'][question.id] = datetime.datetime.now() + + if update_view_count: + question.view_count += 1 + question.save() + + #2) question view count per user + if request.user.is_authenticated(): + try: + question_view = QuestionView.objects.get(who=request.user, question=question) + except QuestionView.DoesNotExist: + question_view = QuestionView(who=request.user, question=question) + question_view.when = datetime.datetime.now() + question_view.save() + return render_to_response('question.html', { "question": question, "question_vote": question_vote, @@ -472,7 +613,6 @@ def _retag_question(request, question): 'tags': _get_tags_cache_json(), }, context_instance=RequestContext(request)) - def _edit_question(request, question): latest_revision = question.get_latest_revision() revision_form = None @@ -617,6 +757,7 @@ QUESTION_REVISION_TEMPLATE = ('<h1>%(title)s</h1>\n' def question_revisions(request, id): post = get_object_or_404(Question, id=id) revisions = list(post.revisions.all()) + revisions.reverse() for i, revision in enumerate(revisions): revision.html = QUESTION_REVISION_TEMPLATE % { 'title': revision.title, @@ -625,16 +766,15 @@ def question_revisions(request, id): for tag in revision.tagnames.split(' ')]), } if i > 0: - revisions[i - 1].diff = htmldiff(revision.html, - revisions[i - 1].html) + revisions[i].diff = htmldiff(revisions[i-1].html, revision.html) else: - revisions[i - 1].diff = QUESTION_REVISION_TEMPLATE % { + revisions[i].diff = QUESTION_REVISION_TEMPLATE % { 'title': revisions[0].title, 'html': sanitize_html(markdowner.convert(revisions[0].text)), 'tags': ' '.join(['<a class="post-tag">%s</a>' % tag for tag in revisions[0].tagnames.split(' ')]), } - revisions[i - 1].summary = None + revisions[i].summary = _('initial version') return render_to_response('revisions_question.html', { 'post': post, 'revisions': revisions, @@ -644,16 +784,16 @@ ANSWER_REVISION_TEMPLATE = ('<div class="text">%(html)s</div>') def answer_revisions(request, id): post = get_object_or_404(Answer, id=id) revisions = list(post.revisions.all()) + revisions.reverse() for i, revision in enumerate(revisions): revision.html = ANSWER_REVISION_TEMPLATE % { 'html': sanitize_html(markdowner.convert(revision.text)) } if i > 0: - revisions[i - 1].diff = htmldiff(revision.html, - revisions[i - 1].html) + revisions[i].diff = htmldiff(revisions[i-1].html, revision.html) else: - revisions[i - 1].diff = revisions[i-1].text - revisions[i - 1].summary = None + revisions[i].diff = revisions[i].text + revisions[i].summary = _('initial version') return render_to_response('revisions_answer.html', { 'post': post, 'revisions': revisions, @@ -691,8 +831,7 @@ def answer(request, id): ip_addr=request.META['REMOTE_ADDR'], ) anon.save() - return HttpResponseRedirect('/%s%s%s%s' % ( _('account/'), - _('signin/'),'?next=', question.get_absolute_url())) + return HttpResponseRedirect(reverse('user_signin_new_answer')) return HttpResponseRedirect(question.get_absolute_url()) @@ -707,7 +846,7 @@ def tags(request): if request.method == "GET": stag = request.GET.get("q", "").strip() - if len(stag) > 0: + if stag != '': objects_list = Paginator(Tag.objects.filter(deleted=False).exclude(used_count=0).extra(where=['name like %s'], params=['%' + stag + '%']), DEFAULT_PAGE_SIZE) else: if sortby == "used": @@ -721,22 +860,21 @@ def tags(request): tags = objects_list.page(objects_list.num_pages) return render_to_response('tags.html', { - "tags": tags, - "stag": stag, - "tab_id": sortby, - "keywords": stag, - "context": { - 'is_paginated': is_paginated, - 'pages': objects_list.num_pages, - 'page': page, - 'has_previous': tags.has_previous(), - 'has_next': tags.has_next(), - 'previous': tags.previous_page_number(), - 'next': tags.next_page_number(), - 'base_url': '/tags/?sort=%s&' % sortby - } - - }, context_instance=RequestContext(request)) + "tags" : tags, + "stag" : stag, + "tab_id" : sortby, + "keywords" : stag, + "context" : { + 'is_paginated' : is_paginated, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': tags.has_previous(), + 'has_next': tags.has_next(), + 'previous': tags.previous_page_number(), + 'next': tags.next_page_number(), + 'base_url' : reverse('tags') + '?sort=%s&' % sortby + } + }, context_instance=RequestContext(request)) def tag(request, tag): return questions(request, tagname=tag) @@ -925,7 +1063,8 @@ def vote(request, id): if not can_delete_post(request.user, post): response_data['allowed'] = -2 - elif post.deleted: + elif post.deleted == True: + logging.debug('debug restoring post in view') onDeleteCanceled(post, request.user) response_data['status'] = 1 else: @@ -934,13 +1073,19 @@ def vote(request, id): elif vote_type == '11':#subscribe q updates user = request.user if user.is_authenticated(): - try: - EmailFeed.objects.get(feed_id=question.id, subscriber_id=user.id, feed_content_type=question_type) - except EmailFeed.DoesNotExist: - feed = EmailFeed(subscriber=user, content=question) - feed.save() + if user not in question.followed_by.all(): + question.followed_by.add(user) if settings.EMAIL_VALIDATION == 'on' and user.email_isvalid == False: - response_data['message'] = _('subscription saved, %(email)s needs validation') % {'email':user.email} + response_data['message'] = \ + _('subscription saved, %(email)s needs validation, see %(details_url)s') \ + % {'email':user.email,'details_url':reverse('faq') + '#validate'} + feed_setting = EmailFeedSetting.objects.get(subscriber=user,feed_type='q_sel') + if feed_setting.frequency == 'n': + feed_setting.frequency = 'd' + feed_setting.save() + if 'message' in response_data: + response_data['message'] += '<br/>' + response_data['message'] = _('email update frequency has been set to daily') #response_data['status'] = 1 #responst_data['allowed'] = 1 else: @@ -950,12 +1095,8 @@ def vote(request, id): elif vote_type == '12':#unsubscribe q updates user = request.user if user.is_authenticated(): - try: - feed = EmailFeed.objects.get(feed_id=question.id, subscriber_id=user.id) - feed.delete() - except EmailFeed.DoesNotExist: - pass - + if user in question.followed_by.all(): + question.followed_by.remove(user) else: response_data['success'] = 0 response_data['message'] = u'Request mode is not supported. Please try again.' @@ -967,6 +1108,42 @@ def vote(request, id): data = simplejson.dumps(response_data) return HttpResponse(data, mimetype="application/json") +@ajax_login_required +def mark_tag(request, tag=None, **kwargs): + action = kwargs['action'] + ts = MarkedTag.objects.filter(user=request.user, tag__name=tag) + if action == 'remove': + logging.debug('deleting tag %s' % tag) + ts.delete() + else: + reason = kwargs['reason'] + if len(ts) == 0: + try: + t = Tag.objects.get(name=tag) + mt = MarkedTag(user=request.user, reason=reason, tag=t) + mt.save() + except: + pass + else: + ts.update(reason=reason) + return HttpResponse(simplejson.dumps(''), mimetype="application/json") + +@ajax_login_required +def ajax_toggle_ignored_questions(request): + if request.user.hide_ignored_questions: + new_hide_setting = False + else: + new_hide_setting = True + request.user.hide_ignored_questions = new_hide_setting + request.user.save() + +@ajax_method +def ajax_command(request): + if 'command' not in request.POST: + return HttpResponseForbidden(mimetype="application/json") + if request.POST['command'] == 'toggle-ignored-questions': + return ajax_toggle_ignored_questions(request) + def users(request): is_paginated = True sortby = request.GET.get('sort', 'reputation') @@ -986,11 +1163,11 @@ def users(request): # default else: objects_list = Paginator(User.objects.all().order_by('-reputation'), USERS_PAGE_SIZE) - base_url = '/%s?sort=%s&' % (_('users/'), sortby) + base_url = reverse('users') + '?sort=%s&' % sortby else: sortby = "reputation" objects_list = Paginator(User.objects.extra(where=['username like %s'], params=['%' + suser + '%']).order_by('-reputation'), USERS_PAGE_SIZE) - base_url = '/%s?name=%s&sort=%s&' % (_('users/'), suser, sortby) + base_url = reverse('users') + '?name=%s&sort=%s&' % (suser, sortby) try: users = objects_list.page(page) @@ -998,22 +1175,22 @@ def users(request): users = objects_list.page(objects_list.num_pages) return render_to_response('users.html', { - "users": users, - "suser": suser, - "keywords": suser, - "tab_id": sortby, - "context": { - 'is_paginated': is_paginated, - 'pages': objects_list.num_pages, - 'page': page, - 'has_previous': users.has_previous(), - 'has_next': users.has_next(), - 'previous': users.previous_page_number(), - 'next': users.next_page_number(), - 'base_url': base_url - } - - }, context_instance=RequestContext(request)) + "users" : users, + "suser" : suser, + "keywords" : suser, + "tab_id" : sortby, + "context" : { + 'is_paginated' : is_paginated, + 'pages': objects_list.num_pages, + 'page': page, + 'has_previous': users.has_previous(), + 'has_next': users.has_next(), + 'previous': users.previous_page_number(), + 'next': users.next_page_number(), + 'base_url' : base_url + } + + }, context_instance=RequestContext(request)) def user(request, id): sort = request.GET.get('sort', 'stats') @@ -1023,6 +1200,26 @@ def user(request, id): return func(request, id, user_view) @login_required +def moderate_user(request, id): + """ajax handler of user moderation + """ + if not auth.can_moderate_users(request.user) or request.method != 'POST': + raise Http404 + if not request.is_ajax(): + return HttpResponseForbidden(mimetype="application/json") + + user = get_object_or_404(User, id=id) + form = ModerateUserForm(request.POST, instance=user) + + if form.is_valid(): + form.save() + logging.debug('data saved') + response = HttpResponse(simplejson.dumps(''), mimetype="application/json") + else: + response = HttpResponseForbidden(mimetype="application/json") + return response + +@login_required def edit_user(request, id): user = get_object_or_404(User, id=id) if request.user != user: @@ -1035,6 +1232,7 @@ def edit_user(request, id): from django_authopenid.views import set_new_email set_new_email(user, new_email) + user.username = sanitize_html(form.cleaned_data['username']) user.real_name = sanitize_html(form.cleaned_data['realname']) user.website = sanitize_html(form.cleaned_data['website']) user.location = sanitize_html(form.cleaned_data['city']) @@ -1052,8 +1250,9 @@ def edit_user(request, id): else: form = EditUserForm(user) return render_to_response('user_edit.html', { - 'form': form, - }, context_instance=RequestContext(request)) + 'form' : form, + 'gravatar_faq_url' : reverse('faq') + '#gravatar', + }, context_instance=RequestContext(request)) def user_stats(request, user_id, user_view): user = get_object_or_404(User, id=user_id) @@ -1097,74 +1296,99 @@ def user_stats(request, user_id, user_view): 'la_user_reputation')[:100] answered_questions = Question.objects.extra( - select={ - 'vote_up_count': 'answer.vote_up_count', - 'vote_down_count': 'answer.vote_down_count', - 'answer_id': 'answer.id', - 'accepted': 'answer.accepted', - 'vote_count': 'answer.score', - 'comment_count': 'answer.comment_count' - }, - tables=['question', 'answer'], - where=['answer.deleted=0 AND answer.author_id=%s AND answer.question_id=question.id'], - params=[user_id], - order_by=['-vote_count', '-answer_id'], - select_params=[user_id] - ).distinct().values('comment_count', - 'id', - 'answer_id', - 'title', - 'author_id', - 'accepted', - 'vote_count', - 'answer_count', - 'vote_up_count', - 'vote_down_count')[:100] + select={ + 'vote_up_count' : 'answer.vote_up_count', + 'vote_down_count' : 'answer.vote_down_count', + 'answer_id' : 'answer.id', + 'accepted' : 'answer.accepted', + 'vote_count' : 'answer.score', + 'comment_count' : 'answer.comment_count' + }, + tables=['question', 'answer'], + where=['answer.deleted=0 AND question.deleted=0 AND answer.author_id=%s AND answer.question_id=question.id'], + params=[user_id], + order_by=['-vote_count', '-answer_id'], + select_params=[user_id] + ).distinct().values('comment_count', + 'id', + 'answer_id', + 'title', + 'author_id', + 'accepted', + 'vote_count', + 'answer_count', + 'vote_up_count', + 'vote_down_count')[:100] + up_votes = Vote.objects.get_up_vote_count_from_user(user) down_votes = Vote.objects.get_down_vote_count_from_user(user) votes_today = Vote.objects.get_votes_count_today_from_user(user) votes_total = VOTE_RULES['scope_votes_per_user_per_day'] - tags = user.created_tags.all().order_by('-used_count')[:50] + question_id_set = set(map(lambda v: v['id'], list(questions))) \ + | set(map(lambda v: v['id'], list(answered_questions))) + + user_tags = Tag.objects.filter(questions__id__in = question_id_set) try: from django.db.models import Count awards = Award.objects.extra( - select={'id': 'badge.id', 'name':'badge.name', 'description': 'badge.description', 'type': 'badge.type'}, - tables=['award', 'badge'], - order_by=['-awarded_at'], - where=['user_id=%s AND badge_id=badge.id'], - params=[user.id] - ).values('id', 'name', 'description', 'type') + select={'id': 'badge.id', + 'name':'badge.name', + 'description': 'badge.description', + 'type': 'badge.type'}, + tables=['award', 'badge'], + order_by=['-awarded_at'], + where=['user_id=%s AND badge_id=badge.id'], + params=[user.id] + ).values('id', 'name', 'description', 'type') total_awards = awards.count() - awards = awards.annotate(count=Count('badge__id')) + awards = awards.annotate(count = Count('badge__id')) + user_tags = user_tags.annotate(user_tag_usage_count=Count('name')) + except ImportError: awards = Award.objects.extra( - select={'id': 'badge.id', 'count': 'count(badge_id)', 'name':'badge.name', 'description': 'badge.description', 'type': 'badge.type'}, - tables=['award', 'badge'], - order_by=['-awarded_at'], - where=['user_id=%s AND badge_id=badge.id'], - params=[user.id] - ).values('id', 'count', 'name', 'description', 'type') + select={'id': 'badge.id', + 'count': 'count(badge_id)', + 'name':'badge.name', + 'description': 'badge.description', + 'type': 'badge.type'}, + tables=['award', 'badge'], + order_by=['-awarded_at'], + where=['user_id=%s AND badge_id=badge.id'], + params=[user.id] + ).values('id', 'count', 'name', 'description', 'type') total_awards = awards.count() awards.query.group_by = ['badge_id'] + user_tags = user_tags.extra( + select={'user_tag_usage_count': 'COUNT(1)',}, + order_by=['-user_tag_usage_count'], + ) + user_tags.query.group_by = ['name'] - return render_to_response(user_view.template_file, { - "tab_name": user_view.id, - "tab_description": user_view.tab_description, - "page_title": user_view.page_title, - "view_user": user, - "questions": questions, - "answered_questions": answered_questions, - "up_votes": up_votes, - "down_votes": down_votes, - "total_votes": up_votes + down_votes, - "votes_today_left": votes_total-votes_today, - "votes_total_per_day": votes_total, - "tags": tags, - "awards": awards, - "total_awards": total_awards, - }, context_instance=RequestContext(request)) + if auth.can_moderate_users(request.user): + moderate_user_form = ModerateUserForm(instance=user) + else: + moderate_user_form = None + + return render_to_response(user_view.template_file,{ + 'moderate_user_form': moderate_user_form, + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "view_user" : user, + "questions" : questions, + "answered_questions" : answered_questions, + "up_votes" : up_votes, + "down_votes" : down_votes, + "total_votes": up_votes + down_votes, + "votes_today_left": votes_total-votes_today, + "votes_total_per_day": votes_total, + "user_tags" : user_tags[:50], + "tags" : tags, + "awards": awards, + "total_awards" : total_awards, + }, context_instance=RequestContext(request)) def user_recent(request, user_id, user_view): user = get_object_or_404(User, id=user_id) @@ -1180,8 +1404,10 @@ def user_recent(request, user_id, user_view): self.type_id = type self.title = title self.summary = summary - self.title_link = u'/questions/%s/%s#%s' % (question_id, title, answer_id)\ - if int(answer_id) > 0 else u'/questions/%s/%s' % (question_id, title) + slug_title = slugify(title) + self.title_link = reverse('question', kwargs={'id':question_id}) + u'%s' % slug_title + if int(answer_id) > 0: + self.title_link += '#%s' % answer_id class AwardEvent: def __init__(self, time, type, id): @@ -1193,23 +1419,23 @@ def user_recent(request, user_id, user_view): activities = [] # ask questions questions = Activity.objects.extra( - select={ - 'title': 'question.title', - 'question_id': 'question.id', - 'active_at': 'activity.active_at', - 'activity_type': 'activity.activity_type' - }, - tables=['activity', 'question'], - where=['activity.content_type_id = %s AND activity.object_id = ' + - 'question.id AND activity.user_id = %s AND activity.activity_type = %s'], - params=[question_type_id, user_id, TYPE_ACTIVITY_ASK_QUESTION], - order_by=['-activity.active_at'] - ).values( - 'title', - 'question_id', - 'active_at', - 'activity_type' - ) + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'active_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'question'], + where=['activity.content_type_id = %s AND activity.object_id = ' + + 'question.id AND question.deleted=0 AND activity.user_id = %s AND activity.activity_type = %s'], + params=[question_type_id, user_id, TYPE_ACTIVITY_ASK_QUESTION], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'active_at', + 'activity_type' + ) if len(questions) > 0: questions = [(Event(q['active_at'], q['activity_type'], q['title'], '', '0', \ q['question_id'])) for q in questions] @@ -1217,25 +1443,26 @@ def user_recent(request, user_id, user_view): # answers answers = Activity.objects.extra( - select={ - 'title': 'question.title', - 'question_id': 'question.id', - 'answer_id': 'answer.id', - 'active_at': 'activity.active_at', - 'activity_type': 'activity.activity_type' - }, - tables=['activity', 'answer', 'question'], - where=['activity.content_type_id = %s AND activity.object_id = answer.id AND ' + - 'answer.question_id=question.id AND activity.user_id=%s AND activity.activity_type=%s'], - params=[answer_type_id, user_id, TYPE_ACTIVITY_ANSWER], - order_by=['-activity.active_at'] - ).values( - 'title', - 'question_id', - 'answer_id', - 'active_at', - 'activity_type' - ) + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'active_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'answer', 'question'], + where=['activity.content_type_id = %s AND activity.object_id = answer.id AND ' + + 'answer.question_id=question.id AND answer.deleted=0 AND activity.user_id=%s AND '+ + 'activity.activity_type=%s AND question.deleted=0'], + params=[answer_type_id, user_id, TYPE_ACTIVITY_ANSWER], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'active_at', + 'activity_type' + ) if len(answers) > 0: answers = [(Event(q['active_at'], q['activity_type'], q['title'], '', q['answer_id'], \ q['question_id'])) for q in answers] @@ -1243,25 +1470,26 @@ def user_recent(request, user_id, user_view): # question comments comments = Activity.objects.extra( - select={ - 'title': 'question.title', - 'question_id': 'comment.object_id', - 'added_at': 'comment.added_at', - 'activity_type': 'activity.activity_type' - }, - tables=['activity', 'question', 'comment'], - - where=['activity.content_type_id = %s AND activity.object_id = comment.id AND ' + - 'activity.user_id = comment.user_id AND comment.object_id=question.id AND ' + - 'comment.content_type_id=%s AND activity.user_id = %s AND activity.activity_type=%s'], - params=[comment_type_id, question_type_id, user_id, TYPE_ACTIVITY_COMMENT_QUESTION], - order_by=['-comment.added_at'] - ).values( - 'title', - 'question_id', - 'added_at', - 'activity_type' - ) + select={ + 'title' : 'question.title', + 'question_id' : 'comment.object_id', + 'added_at' : 'comment.added_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'question', 'comment'], + + where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+ + 'activity.user_id = comment.user_id AND comment.object_id=question.id AND '+ + 'comment.content_type_id=%s AND activity.user_id = %s AND activity.activity_type=%s AND ' + + 'question.deleted=0'], + params=[comment_type_id, question_type_id, user_id, TYPE_ACTIVITY_COMMENT_QUESTION], + order_by=['-comment.added_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'activity_type' + ) if len(comments) > 0: comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \ @@ -1270,28 +1498,29 @@ def user_recent(request, user_id, user_view): # answer comments comments = Activity.objects.extra( - select={ - 'title': 'question.title', - 'question_id': 'question.id', - 'answer_id': 'answer.id', - 'added_at': 'comment.added_at', - 'activity_type': 'activity.activity_type' - }, - tables=['activity', 'question', 'answer', 'comment'], - - where=['activity.content_type_id = %s AND activity.object_id = comment.id AND ' + - 'activity.user_id = comment.user_id AND comment.object_id=answer.id AND ' + - 'comment.content_type_id=%s AND question.id = answer.question_id AND ' + - 'activity.user_id = %s AND activity.activity_type=%s'], - params=[comment_type_id, answer_type_id, user_id, TYPE_ACTIVITY_COMMENT_ANSWER], - order_by=['-comment.added_at'] - ).values( - 'title', - 'question_id', - 'answer_id', - 'added_at', - 'activity_type' - ) + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'added_at' : 'comment.added_at', + 'activity_type' : 'activity.activity_type' + }, + tables=['activity', 'question', 'answer', 'comment'], + + where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+ + 'activity.user_id = comment.user_id AND comment.object_id=answer.id AND '+ + 'comment.content_type_id=%s AND question.id = answer.question_id AND '+ + 'activity.user_id = %s AND activity.activity_type=%s AND '+ + 'answer.deleted=0 AND question.deleted=0'], + params=[comment_type_id, answer_type_id, user_id, TYPE_ACTIVITY_COMMENT_ANSWER], + order_by=['-comment.added_at'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'added_at', + 'activity_type' + ) if len(comments) > 0: comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', q['answer_id'], \ @@ -1300,26 +1529,27 @@ def user_recent(request, user_id, user_view): # question revisions revisions = Activity.objects.extra( - select={ - 'title': 'question_revision.title', - 'question_id': 'question_revision.question_id', - 'added_at': 'activity.active_at', - 'activity_type': 'activity.activity_type', - 'summary': 'question_revision.summary' - }, - tables=['activity', 'question_revision'], - where=['activity.content_type_id = %s AND activity.object_id = question_revision.id AND ' + - 'activity.user_id = question_revision.author_id AND activity.user_id = %s AND ' + - 'activity.activity_type=%s'], - params=[question_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_QUESTION], - order_by=['-activity.active_at'] - ).values( - 'title', - 'question_id', - 'added_at', - 'activity_type', - 'summary' - ) + select={ + 'title' : 'question_revision.title', + 'question_id' : 'question_revision.question_id', + 'added_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type', + 'summary' : 'question_revision.summary' + }, + tables=['activity', 'question_revision', 'question'], + where=['activity.content_type_id = %s AND activity.object_id = question_revision.id AND '+ + 'question_revision.id=question.id AND question.deleted=0 AND '+ + 'activity.user_id = question_revision.author_id AND activity.user_id = %s AND '+ + 'activity.activity_type=%s'], + params=[question_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_QUESTION], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'activity_type', + 'summary' + ) if len(revisions) > 0: revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], '0', \ @@ -1328,30 +1558,31 @@ def user_recent(request, user_id, user_view): # answer revisions revisions = Activity.objects.extra( - select={ - 'title': 'question.title', - 'question_id': 'question.id', - 'answer_id': 'answer.id', - 'added_at': 'activity.active_at', - 'activity_type': 'activity.activity_type', - 'summary': 'answer_revision.summary' - }, - tables=['activity', 'answer_revision', 'question', 'answer'], - - where=['activity.content_type_id = %s AND activity.object_id = answer_revision.id AND ' + - 'activity.user_id = answer_revision.author_id AND activity.user_id = %s AND ' + - 'answer_revision.answer_id=answer.id AND answer.question_id = question.id AND ' + - 'activity.activity_type=%s'], - params=[answer_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_ANSWER], - order_by=['-activity.active_at'] - ).values( - 'title', - 'question_id', - 'added_at', - 'answer_id', - 'activity_type', - 'summary' - ) + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'added_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type', + 'summary' : 'answer_revision.summary' + }, + tables=['activity', 'answer_revision', 'question', 'answer'], + + where=['activity.content_type_id = %s AND activity.object_id = answer_revision.id AND '+ + 'activity.user_id = answer_revision.author_id AND activity.user_id = %s AND '+ + 'answer_revision.answer_id=answer.id AND answer.question_id = question.id AND '+ + 'question.deleted=0 AND answer.deleted=0 AND '+ + 'activity.activity_type=%s'], + params=[answer_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_ANSWER], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'answer_id', + 'activity_type', + 'summary' + ) if len(revisions) > 0: revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], \ @@ -1360,24 +1591,25 @@ def user_recent(request, user_id, user_view): # accepted answers accept_answers = Activity.objects.extra( - select={ - 'title': 'question.title', - 'question_id': 'question.id', - 'added_at': 'activity.active_at', - 'activity_type': 'activity.activity_type', - }, - tables=['activity', 'answer', 'question'], - where=['activity.content_type_id = %s AND activity.object_id = answer.id AND ' + - 'activity.user_id = question.author_id AND activity.user_id = %s AND ' + - 'answer.question_id=question.id AND activity.activity_type=%s'], - params=[answer_type_id, user_id, TYPE_ACTIVITY_MARK_ANSWER], - order_by=['-activity.active_at'] - ).values( - 'title', - 'question_id', - 'added_at', - 'activity_type', - ) + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'added_at' : 'activity.active_at', + 'activity_type' : 'activity.activity_type', + }, + tables=['activity', 'answer', 'question'], + where=['activity.content_type_id = %s AND activity.object_id = answer.id AND '+ + 'activity.user_id = question.author_id AND activity.user_id = %s AND '+ + 'answer.deleted=0 AND question.deleted=0 AND '+ + 'answer.question_id=question.id AND activity.activity_type=%s'], + params=[answer_type_id, user_id, TYPE_ACTIVITY_MARK_ANSWER], + order_by=['-activity.active_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'activity_type', + ) if len(accept_answers) > 0: accept_answers = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \ q['question_id'])) for q in accept_answers] @@ -1405,13 +1637,13 @@ def user_recent(request, user_id, user_view): activities.sort(lambda x, y: cmp(y.time, x.time)) - return render_to_response(user_view.template_file, { - "tab_name": user_view.id, - "tab_description": user_view.tab_description, - "page_title": user_view.page_title, - "view_user": user, - "activities": activities[:user_view.data_size] - }, context_instance=RequestContext(request)) + return render_to_response(user_view.template_file,{ + "tab_name" : user_view.id, + "tab_description" : user_view.tab_description, + "page_title" : user_view.page_title, + "view_user" : user, + "activities" : activities[:user_view.data_size] + }, context_instance=RequestContext(request)) def user_responses(request, user_id, user_view): """ @@ -1421,9 +1653,9 @@ def user_responses(request, user_id, user_view): def __init__(self, type, title, question_id, answer_id, time, username, user_id, content): self.type = type self.title = title - self.titlelink = u'/%s%s/%s#%s' % (_('questions/'), question_id, slugify(title), answer_id) + self.titlelink = reverse('question', args=[question_id]) + u'%s#%s' % (slugify(title), answer_id) self.time = time - self.userlink = u'/%s%s/%s/' % (_('users/'), user_id, username) + self.userlink = reverse('users') + u'%s/%s/' % (user_id, username) self.username = username self.content = u'%s ...' % strip_tags(content)[:300] @@ -1433,30 +1665,31 @@ def user_responses(request, user_id, user_view): user = get_object_or_404(User, id=user_id) responses = [] answers = Answer.objects.extra( - select={ - 'title': 'question.title', - 'question_id': 'question.id', - 'answer_id': 'answer.id', - 'added_at': 'answer.added_at', - 'html': 'answer.html', - 'username': 'auth_user.username', - 'user_id': 'auth_user.id' - }, - select_params=[user_id], - tables=['answer', 'question', 'auth_user'], - where=['answer.question_id = question.id AND answer.deleted=0 AND question.deleted = 0 AND ' + - 'question.author_id = %s AND answer.author_id <> %s AND answer.author_id=auth_user.id'], - params=[user_id, user_id], - order_by=['-answer.id'] - ).values( - 'title', - 'question_id', - 'answer_id', - 'added_at', - 'html', - 'username', - 'user_id' - ) + select={ + 'title' : 'question.title', + 'question_id' : 'question.id', + 'answer_id' : 'answer.id', + 'added_at' : 'answer.added_at', + 'html' : 'answer.html', + 'username' : 'auth_user.username', + 'user_id' : 'auth_user.id' + }, + select_params=[user_id], + tables=['answer', 'question', 'auth_user'], + where=['answer.question_id = question.id AND answer.deleted=0 AND question.deleted = 0 AND '+ + 'question.author_id = %s AND answer.author_id <> %s AND answer.author_id=auth_user.id'], + params=[user_id, user_id], + order_by=['-answer.id'] + ).values( + 'title', + 'question_id', + 'answer_id', + 'added_at', + 'html', + 'username', + 'user_id' + ) + if len(answers) > 0: answers = [(Response(TYPE_RESPONSE['QUESTION_ANSWERED'], a['title'], a['question_id'], a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers] @@ -1465,27 +1698,27 @@ def user_responses(request, user_id, user_view): # question comments comments = Comment.objects.extra( - select={ - 'title': 'question.title', - 'question_id': 'comment.object_id', - 'added_at': 'comment.added_at', - 'comment': 'comment.comment', - 'username': 'auth_user.username', - 'user_id': 'auth_user.id' - }, - tables=['question', 'auth_user', 'comment'], - where=['question.deleted = 0 AND question.author_id = %s AND comment.object_id=question.id AND ' + - 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id'], - params=[user_id, question_type_id, user_id], - order_by=['-comment.added_at'] - ).values( - 'title', - 'question_id', - 'added_at', - 'comment', - 'username', - 'user_id' - ) + select={ + 'title' : 'question.title', + 'question_id' : 'comment.object_id', + 'added_at' : 'comment.added_at', + 'comment' : 'comment.comment', + 'username' : 'auth_user.username', + 'user_id' : 'auth_user.id' + }, + tables=['question', 'auth_user', 'comment'], + where=['question.deleted = 0 AND question.author_id = %s AND comment.object_id=question.id AND '+ + 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id'], + params=[user_id, question_type_id, user_id], + order_by=['-comment.added_at'] + ).values( + 'title', + 'question_id', + 'added_at', + 'comment', + 'username', + 'user_id' + ) if len(comments) > 0: comments = [(Response(TYPE_RESPONSE['QUESTION_COMMENTED'], c['title'], c['question_id'], @@ -1719,88 +1952,117 @@ def user_favorites(request, user_id, user_view): "view_user": user }, context_instance=RequestContext(request)) - -def user_preferences(request, user_id, user_view): +def user_email_subscriptions(request, user_id, user_view): user = get_object_or_404(User, id=user_id) - return render_to_response(user_view.template_file, { - "tab_name": user_view.id, - "tab_description": user_view.tab_description, - "page_title": user_view.page_title, - "view_user": user, - }, context_instance=RequestContext(request)) + if request.method == 'POST': + email_feeds_form = EditUserEmailFeedsForm(request.POST) + tag_filter_form = TagFilterSelectionForm(request.POST, instance=user) + if email_feeds_form.is_valid() and tag_filter_form.is_valid(): + + action_status = None + tag_filter_saved = tag_filter_form.save() + if tag_filter_saved: + action_status = _('changes saved') + if 'save' in request.POST: + feeds_saved = email_feeds_form.save(user) + if feeds_saved: + action_status = _('changes saved') + elif 'stop_email' in request.POST: + email_stopped = email_feeds_form.reset().save(user) + initial_values = EditUserEmailFeedsForm.NO_EMAIL_INITIAL + email_feeds_form = EditUserEmailFeedsForm(initial=initial_values) + if email_stopped: + action_status = _('email updates canceled') + else: + email_feeds_form = EditUserEmailFeedsForm() + email_feeds_form.set_initial_values(user) + tag_filter_form = TagFilterSelectionForm(instance=user) + action_status = None + return render_to_response(user_view.template_file,{ + 'tab_name':user_view.id, + 'tab_description':user_view.tab_description, + 'page_title':user_view.page_title, + 'view_user':user, + 'email_feeds_form':email_feeds_form, + 'tag_filter_selection_form':tag_filter_form, + 'action_status':action_status, + }, context_instance=RequestContext(request)) def question_comments(request, id): question = get_object_or_404(Question, id=id) user = request.user - return __comments(request, question, 'question', user) + return __comments(request, question, 'question') def answer_comments(request, id): answer = get_object_or_404(Answer, id=id) user = request.user - return __comments(request, answer, 'answer', user) + return __comments(request, answer, 'answer') -def __comments(request, obj, type, user): +def __comments(request, obj, type): # only support get comments by ajax now + user = request.user if request.is_ajax(): if request.method == "GET": - return __generate_comments_json(obj, type, user) + response = __generate_comments_json(obj, type, user) elif request.method == "POST": - comment_data = request.POST.get('comment') - comment = Comment(content_object=obj, comment=comment_data, user=request.user) - comment.save() - obj.comment_count = obj.comment_count + 1 - obj.save() - return __generate_comments_json(obj, type, user) + if auth.can_add_comments(user,obj): + comment_data = request.POST.get('comment') + comment = Comment(content_object=obj, comment=comment_data, user=request.user) + comment.save() + obj.comment_count = obj.comment_count + 1 + obj.save() + response = __generate_comments_json(obj, type, user) + else: + response = HttpResponseForbidden(mimetype="application/json") + return response def __generate_comments_json(obj, type, user): - comments = obj.comments.all().order_by('-id') + comments = obj.comments.all().order_by('id') # {"Id":6,"PostId":38589,"CreationDate":"an hour ago","Text":"hello there!","UserDisplayName":"Jarrod Dixon","UserUrl":"/users/3/jarrod-dixon","DeleteUrl":null} json_comments = [] + from forum.templatetags.extra_tags import diff_date for comment in comments: comment_user = comment.user delete_url = "" if user != None and auth.can_delete_comment(user, comment): #/posts/392845/comments/219852/delete - delete_url = "/" + type + "s/%s/comments/%s/delete/" % (obj.id, comment.id) - json_comments.append({"id": comment.id, - "object_id": obj.id, - "add_date": comment.added_at.strftime('%Y-%m-%d'), - "text": comment.comment, - "user_display_name": comment_user.username, - "user_url": "/users/%s/%s" % (comment_user.id, comment_user.username), - "delete_url": delete_url - }) + #todo translate this url + delete_url = reverse(index) + type + "s/%s/comments/%s/delete/" % (obj.id, comment.id) + json_comments.append({"id" : comment.id, + "object_id" : obj.id, + "comment_age" : diff_date(comment.added_at), + "text" : comment.comment, + "user_display_name" : comment_user.username, + "user_url" : comment_user.get_profile_url(), + "delete_url" : delete_url + }) data = simplejson.dumps(json_comments) return HttpResponse(data, mimetype="application/json") -def delete_question_comment(request, question_id, comment_id): - if request.is_ajax(): - question = get_object_or_404(Question, id=question_id) - comment = get_object_or_404(Comment, id=comment_id) - - question.comments.remove(comment) - question.comment_count = question.comment_count - 1 - question.save() - user = request.user - return __generate_comments_json(question, 'question', user) +def delete_comment(request, object_id='', comment_id='', commented_object_type=None): + response = None + commented_object = None + if commented_object_type == 'question': + commented_object = Question + elif commented_object_type == 'answer': + commented_object = Answer -def delete_answer_comment(request, answer_id, comment_id): if request.is_ajax(): - answer = get_object_or_404(Answer, id=answer_id) comment = get_object_or_404(Comment, id=comment_id) - - answer.comments.remove(comment) - answer.comment_count = answer.comment_count - 1 - answer.save() - user = request.user - return __generate_comments_json(answer, 'answer', user) + if auth.can_delete_comment(request.user, comment): + obj = get_object_or_404(commented_object, id=object_id) + obj.comments.remove(comment) + obj.comment_count = obj.comment_count - 1 + obj.save() + user = request.user + return __generate_comments_json(obj, commented_object_type, user) + raise PermissionDenied() def logout(request): - url = request.GET.get('next') return render_to_response('logout.html', { - 'next': url, - }, context_instance=RequestContext(request)) + 'next' : get_next_url(request), + }, context_instance=RequestContext(request)) def badges(request): badges = Badge.objects.all().order_by('type') @@ -1810,9 +2072,10 @@ def badges(request): my_badges.query.group_by = ['badge_id'] return render_to_response('badges.html', { - 'badges': badges, - 'mybadges': my_badges, - }, context_instance=RequestContext(request)) + 'badges' : badges, + 'mybadges' : my_badges, + 'feedback_faq_url' : reverse('feedback'), + }, context_instance=RequestContext(request)) def badge(request, id): badge = get_object_or_404(Badge, id=id) @@ -1863,8 +2126,8 @@ def upload(request): if not file_name_suffix in settings.ALLOW_FILE_TYPES: raise FileTypeNotAllow - # genetate new file name - new_file_name = str(time.time()).replace('.', str(random.randint(0, 100000))) + file_name_suffix + # generate new file name + new_file_name = str(time.time()).replace('.', str(random.randint(0,100000))) + file_name_suffix # use default storage to store file default_storage.save(new_file_name, f) # check file size @@ -1887,7 +2150,7 @@ def upload(request): return HttpResponse(result, mimetype="application/xml") def books(request): - return HttpResponseRedirect("/books/mysql-zhaoyang") + return HttpResponseRedirect(reverse('books') + '/mysql-zhaoyang') def book(request, short_name, unanswered=False): """ @@ -2010,9 +2273,10 @@ def ask_book(request, short_name): tags = _get_tags_cache_json() return render_to_response('ask.html', { - 'form': form, - 'tags': tags, - }, context_instance=RequestContext(request)) + 'form' : form, + 'tags' : tags, + 'email_validation_faq_url': reverse('faq') + '#validate', + }, context_instance=RequestContext(request)) def search(request): """ @@ -2027,11 +2291,11 @@ def search(request): except ValueError: page = 1 if keywords is None: - return HttpResponseRedirect('/') + return HttpResponseRedirect(reverse(index)) if search_type == 'tag': - return HttpResponseRedirect('/%s?q=%s&page=%s' % (_('tags/'), keywords.strip(), page)) + return HttpResponseRedirect(reverse('tags') + '?q=%s&page=%s' % (keywords.strip(), page)) elif search_type == "user": - return HttpResponseRedirect('/%s?q=%s&page=%s' % (_('users/'), keywords.strip(), page)) + return HttpResponseRedirect(reverse('users') + '?q=%s&page=%s' % (keywords.strip(), page)) elif search_type == "question": template_file = "questions.html" @@ -2070,10 +2334,16 @@ def search(request): view_id = "latest" orderby = "-added_at" - objects = Question.objects.filter(deleted=False).extra(where=['title like %s'], params=['%' + keywords + '%']).order_by(orderby) + if settings.USE_SPHINX_SEARCH == True: + #search index is now free of delete questions and answers + #so there is not "antideleted" filtering here + objects = Question.search.query(keywords) + #no related selection either because we're relying on full text search here + else: + objects = Question.objects.filter(deleted=False).extra(where=['title like %s'], params=['%' + keywords + '%']).order_by(orderby) + # RISK - inner join queries + objects = objects.select_related(); - # RISK - inner join queries - objects = objects.select_related(); objects_list = Paginator(objects, pagesize) questions = objects_list.page(page) |