# encoding:utf-8 import os.path import time, datetime, calendar, random import logging from urllib import quote, unquote from django.conf import settings from django.core.files.storage import default_storage from django.shortcuts import render_to_response, get_object_or_404 from django.contrib.auth.decorators import login_required from django.http import HttpResponseRedirect, HttpResponse,Http404 from django.core.paginator import Paginator, EmptyPage, InvalidPage from django.template import RequestContext from django.utils.html import * from django.utils import simplejson from django.core import serializers from django.db import transaction from django.contrib.contenttypes.models import ContentType from django.utils.translation import ugettext as _ from django.template.defaultfilters import slugify from utils.html import sanitize_html from markdown2 import Markdown #from lxml.html.diff import htmldiff from forum.diff import textDiff as htmldiff from forum.forms import * from forum.models import * from forum.auth import * from forum.const import * from forum.user import * from forum import auth # used in index page INDEX_PAGE_SIZE = 20 INDEX_AWARD_SIZE = 15 INDEX_TAGS_SIZE = 100 # used in tags list DEFAULT_PAGE_SIZE = 60 # used in questions QUESTIONS_PAGE_SIZE = 10 # used in users USERS_PAGE_SIZE = 35 # used in answers ANSWERS_PAGE_SIZE = 10 markdowner = Markdown(html4tags=True) question_type = ContentType.objects.get_for_model(Question) answer_type = ContentType.objects.get_for_model(Answer) comment_type = ContentType.objects.get_for_model(Comment) question_revision_type = ContentType.objects.get_for_model(QuestionRevision) answer_revision_type = ContentType.objects.get_for_model(AnswerRevision) repute_type =ContentType.objects.get_for_model(Repute) question_type_id = question_type.id answer_type_id = answer_type.id comment_type_id = comment_type.id question_revision_type_id = question_revision_type.id answer_revision_type_id = answer_revision_type.id repute_type_id = repute_type.id def _get_tags_cache_json(): 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 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 = "-last_activity_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) # RISK - inner join queries questions = questions.select_related() tags = Tag.objects.get_valid_tags(INDEX_TAGS_SIZE) awards = Award.objects.get_recent_awards() return render_to_response('index.html', { "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)) def privacy(request): return render_to_response('privacy.html', context_instance=RequestContext(request)) def unanswered(request): return questions(request, unanswered=True) def questions(request, tagname=None, unanswered=False): """ List of Questions, Tagged questions, and Unanswered questions. """ # template file # "questions.html" or "unanswered.html" template_file = "questions.html" # Set flag to False by default. If it is equal to True, then need to be saved. pagesize_changed = False # get pagesize from session, if failed then get default value pagesize = request.session.get("pagesize",10) try: page = int(request.GET.get('page', '1')) 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" # check if request is from tagged questions 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) # RISK - inner join queries objects = objects.select_related(depth=1); objects_list = Paginator(objects, pagesize) questions = objects_list.page(page) # Get related tags from this page objects if questions.object_list.count() > 0: 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)) def create_new_answer( question=None, author=None,\ added_at=None, wiki=False,\ text='', email_notify=False): html = sanitize_html(markdowner.convert(text)) #create answer answer = Answer( question = question, author = author, added_at = added_at, wiki = wiki, html = html ) if answer.wiki: answer.last_edited_by = answer.author answer.last_edited_at = added_at answer.wikified_at = added_at answer.save() #update question data question.last_activity_at = added_at question.last_activity_by = author question.save() Question.objects.update_answer_count(question) #update revision AnswerRevision.objects.create( answer = answer, revision = 1, author = author, revised_at = added_at, summary = CONST['default_version'], text = text ) #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() 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() except: pass def create_new_question(title=None,author=None,added_at=None, wiki=False,tagnames=None,summary=None, text=None): """this is not a view and maybe should become one of the methods on Question object? """ html = sanitize_html(markdowner.convert(text)) question = Question( title = title, author = author, added_at = added_at, last_activity_at = added_at, last_activity_by = author, wiki = wiki, tagnames = tagnames, html = html, summary = summary ) if question.wiki: question.last_edited_by = question.author question.last_edited_at = added_at question.wikified_at = added_at question.save() # create the first revision QuestionRevision.objects.create( question = question, revision = 1, title = question.title, author = author, revised_at = added_at, tagnames = question.tagnames, summary = CONST['default_version'], text = text ) return question #TODO: allow anynomus user to ask question by providing email and username. #@login_required def ask(request): if request.method == "POST": form = AskForm(request.POST) if form.is_valid(): added_at = datetime.datetime.now() title = strip_tags(form.cleaned_data['title']) wiki = form.cleaned_data['wiki'] tagnames = form.cleaned_data['tags'].strip() text = form.cleaned_data['text'] html = sanitize_html(markdowner.convert(text)) summary = strip_tags(html)[:120] if request.user.is_authenticated(): author = request.user question = create_new_question( title = title, author = author, added_at = added_at, wiki = wiki, tagnames = tagnames, summary = summary, text = text ) return HttpResponseRedirect(question.get_absolute_url()) else: request.session.flush() session_key = request.session.session_key question = AnonymousQuestion( session_key = session_key, title = title, tagnames = tagnames, wiki = wiki, text = text, summary = summary, added_at = added_at, ip_addr = request.META['REMOTE_ADDR'], ) question.save() return HttpResponseRedirect('/%s%s%s' % ( _('account/'),_('signin/'),_('newquestion/'))) else: form = AskForm() tags = _get_tags_cache_json() return render_to_response('ask.html', { 'form' : form, 'tags' : tags, }, 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" } try: orderby = view_dic[view_id] except KeyError: view_id = "votes" orderby = "-score" question = get_object_or_404(Question, id=id) if question.deleted and not can_view_deleted_post(request.user, question): raise Http404 answer_form = AnswerForm(question,request.user) answers = Answer.objects.get_answers_from_question(question, request.user) answers = answers.select_related(depth=1) favorited = question.has_favorite_by_user(request.user) if request.user.is_authenticated(): question_vote = question.votes.select_related().filter(user=request.user) else: question_vote = None #is this correct? if question_vote is not None and question_vote.count() > 0: question_vote = question_vote[0] user_answer_votes = {} for answer in answers: vote = answer.get_user_vote(request.user) if vote is not None and not user_answer_votes.has_key(answer.id): vote_value = -1 if vote.is_upvote(): vote_value = 1 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: if answer.author_id == request.user.id: filtered_answers.append(answer) else: filtered_answers.append(answer) objects_list = Paginator(filtered_answers, ANSWERS_PAGE_SIZE) page_objects = objects_list.page(page) # update view count Question.objects.update_view_count(question) return render_to_response('question.html', { "question" : question, "question_vote" : question_vote, "question_comment_count":question.comments.count(), "answer" : answer_form, "answers" : page_objects.object_list, "user_answer_votes": user_answer_votes, "tags" : question.tags.all(), "tab_id" : view_id, "favorited" : favorited, "similar_questions" : Question.objects.get_similar_questions(question), "context" : { 'is_paginated' : True, 'pages': objects_list.num_pages, 'page': page, 'has_previous': page_objects.has_previous(), 'has_next': page_objects.has_next(), 'previous': page_objects.previous_page_number(), 'next': page_objects.next_page_number(), 'base_url' : request.path + '?sort=%s&' % view_id, 'extend_url' : "#sort-top" } }, context_instance=RequestContext(request)) @login_required def close(request, id): question = get_object_or_404(Question, id=id) if not can_close_question(request.user, question): return HttpResponse('Permission denied.') if request.method == 'POST': form = CloseForm(request.POST) if form.is_valid(): reason = form.cleaned_data['reason'] question.closed = True question.closed_by = request.user question.closed_at = datetime.datetime.now() question.close_reason = reason question.save() return HttpResponseRedirect(question.get_absolute_url()) else: form = CloseForm() return render_to_response('close.html', { 'form' : form, 'question' : question, }, context_instance=RequestContext(request)) @login_required def reopen(request, id): question = get_object_or_404(Question, id=id) # open question if not can_reopen_question(request.user, question): return HttpResponse('Permission denied.') if request.method == 'POST' : Question.objects.filter(id=question.id).update(closed=False, closed_by=None, closed_at=None, close_reason=None) return HttpResponseRedirect(question.get_absolute_url()) else: return render_to_response('reopen.html', { 'question' : question, }, context_instance=RequestContext(request)) @login_required def edit_question(request, id): question = get_object_or_404(Question, id=id) if question.deleted and not can_view_deleted_post(request.user, question): raise Http404 if can_edit_post(request.user, question): return _edit_question(request, question) elif can_retag_questions(request.user): return _retag_question(request, question) else: raise Http404 def _retag_question(request, question): if request.method == 'POST': form = RetagQuestionForm(question, request.POST) if form.is_valid(): if form.has_changed(): latest_revision = question.get_latest_revision() retagged_at = datetime.datetime.now() # Update the Question itself Question.objects.filter(id=question.id).update( tagnames = form.cleaned_data['tags'], last_edited_at = retagged_at, last_edited_by = request.user, last_activity_at = retagged_at, last_activity_by = request.user ) # Update the Question's tag associations tags_updated = Question.objects.update_tags(question, form.cleaned_data['tags'], request.user) # Create a new revision QuestionRevision.objects.create( question = question, title = latest_revision.title, author = request.user, revised_at = retagged_at, tagnames = form.cleaned_data['tags'], summary = CONST['retagged'], text = latest_revision.text ) # send tags updated singal tags_updated.send(sender=question.__class__, question=question) return HttpResponseRedirect(question.get_absolute_url()) else: form = RetagQuestionForm(question) return render_to_response('question_retag.html', { 'question': question, 'form' : form, 'tags' : _get_tags_cache_json(), }, context_instance=RequestContext(request)) def _edit_question(request, question): latest_revision = question.get_latest_revision() revision_form = None if request.method == 'POST': if 'select_revision' in request.POST: # user has changed revistion number revision_form = RevisionForm(question, latest_revision, request.POST) if revision_form.is_valid(): # Replace with those from the selected revision form = EditQuestionForm(question, QuestionRevision.objects.get(question=question, revision=revision_form.cleaned_data['revision'])) else: form = EditQuestionForm(question, latest_revision, request.POST) else: # Always check modifications against the latest revision form = EditQuestionForm(question, latest_revision, request.POST) if form.is_valid(): html = sanitize_html(markdowner.convert(form.cleaned_data['text'])) if form.has_changed(): edited_at = datetime.datetime.now() tags_changed = (latest_revision.tagnames != form.cleaned_data['tags']) tags_updated = False # Update the Question itself updated_fields = { 'title': form.cleaned_data['title'], 'last_edited_at': edited_at, 'last_edited_by': request.user, 'last_activity_at': edited_at, 'last_activity_by': request.user, 'tagnames': form.cleaned_data['tags'], 'summary': strip_tags(html)[:120], 'html': html, } # only save when it's checked # because wiki doesn't allow to be edited if last version has been enabled already # and we make sure this in forms. if ('wiki' in form.cleaned_data and form.cleaned_data['wiki']): updated_fields['wiki'] = True updated_fields['wikified_at'] = edited_at Question.objects.filter( id=question.id).update(**updated_fields) # Update the Question's tag associations if tags_changed: tags_updated = Question.objects.update_tags( question, form.cleaned_data['tags'], request.user) # Create a new revision revision = QuestionRevision( question = question, title = form.cleaned_data['title'], author = request.user, revised_at = edited_at, tagnames = form.cleaned_data['tags'], text = form.cleaned_data['text'], ) if form.cleaned_data['summary']: revision.summary = form.cleaned_data['summary'] else: revision.summary = 'No.%s Revision' % latest_revision.revision revision.save() return HttpResponseRedirect(question.get_absolute_url()) else: revision_form = RevisionForm(question, latest_revision) form = EditQuestionForm(question, latest_revision) return render_to_response('question_edit.html', { 'question': question, 'revision_form': revision_form, 'form' : form, 'tags' : _get_tags_cache_json() }, context_instance=RequestContext(request)) @login_required def edit_answer(request, id): answer = get_object_or_404(Answer, id=id) if answer.deleted and not can_view_deleted_post(request.user, answer): raise Http404 elif not can_edit_post(request.user, answer): raise Http404 else: latest_revision = answer.get_latest_revision() if request.method == "POST": if 'select_revision' in request.POST: # user has changed revistion number revision_form = RevisionForm(answer, latest_revision, request.POST) if revision_form.is_valid(): # Replace with those from the selected revision form = EditAnswerForm(answer, AnswerRevision.objects.get(answer=answer, revision=revision_form.cleaned_data['revision'])) else: form = EditAnswerForm(answer, latest_revision, request.POST) else: form = EditAnswerForm(answer, latest_revision, request.POST) if form.is_valid(): html = sanitize_html(markdowner.convert(form.cleaned_data['text'])) if form.has_changed(): edited_at = datetime.datetime.now() updated_fields = { 'last_edited_at': edited_at, 'last_edited_by': request.user, 'html': html, } Answer.objects.filter(id=answer.id).update(**updated_fields) revision = AnswerRevision( answer = answer, author = request.user, revised_at = edited_at, text = form.cleaned_data['text'] ) if form.cleaned_data['summary']: revision.summary = form.cleaned_data['summary'] else: revision.summary = 'No.%s Revision' % latest_revision.revision revision.save() answer.question.last_activity_at = edited_at answer.question.last_activity_by = request.user answer.question.save() return HttpResponseRedirect(answer.get_absolute_url()) else: revision_form = RevisionForm(answer, latest_revision) form = EditAnswerForm(answer, latest_revision) return render_to_response('answer_edit.html', { 'answer': answer, 'revision_form': revision_form, 'form' : form, }, context_instance=RequestContext(request)) QUESTION_REVISION_TEMPLATE = ('

%(title)s

\n' '
%(html)s
\n' '
%(tags)s
') def question_revisions(request, id): post = get_object_or_404(Question, id=id) revisions = list(post.revisions.all()) for i, revision in enumerate(revisions): revision.html = QUESTION_REVISION_TEMPLATE % { 'title': revision.title, 'html': sanitize_html(markdowner.convert(revision.text)), 'tags': ' '.join(['%s' % tag for tag in revision.tagnames.split(' ')]), } if i > 0: revisions[i - 1].diff = htmldiff(revision.html, revisions[i - 1].html) else: revisions[i - 1].diff = QUESTION_REVISION_TEMPLATE % { 'title': revisions[0].title, 'html': sanitize_html(markdowner.convert(revisions[0].text)), 'tags': ' '.join(['%s' % tag for tag in revisions[0].tagnames.split(' ')]), } revisions[i - 1].summary = None return render_to_response('revisions_question.html', { 'post': post, 'revisions': revisions, }, context_instance=RequestContext(request)) ANSWER_REVISION_TEMPLATE = ('
%(html)s
') def answer_revisions(request, id): post = get_object_or_404(Answer, id=id) revisions = list(post.revisions.all()) 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) else: revisions[i - 1].diff = revisions[i-1].text revisions[i - 1].summary = None return render_to_response('revisions_answer.html', { 'post': post, 'revisions': revisions, }, context_instance=RequestContext(request)) def answer(request, id): question = get_object_or_404(Question, id=id) if request.method == "POST": form = AnswerForm(question, request.user, request.POST) if form.is_valid(): wiki = form.cleaned_data['wiki'] text = form.cleaned_data['text'] update_time = datetime.datetime.now() if request.user.is_authenticated(): create_new_answer( question=question, author=request.user, added_at=update_time, wiki=wiki, text=text, email_notify=form.cleaned_data['email_notify'] ) else: request.session.flush() html = sanitize_html(markdowner.convert(text)) summary = strip_tags(html)[:120] anon = AnonymousAnswer( question = question, wiki = wiki, text = text, summary = summary, session_key = request.session.session_key, ip_addr = request.META['REMOTE_ADDR'], ) anon.save() return HttpResponseRedirect('/%s%s%s' % ( _('account/'), _('signin/'),_('newquestion/'))) return HttpResponseRedirect(question.get_absolute_url()) def tags(request): stag = "" is_paginated = True sortby = request.GET.get('sort', 'used') try: page = int(request.GET.get('page', '1')) except ValueError: page = 1 if request.method == "GET": stag = request.GET.get("q", "").strip() if stag is not None: 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 == "name": objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("name"), DEFAULT_PAGE_SIZE) else: objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("-used_count"), DEFAULT_PAGE_SIZE) try: tags = objects_list.page(page) except (EmptyPage, InvalidPage): 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' : '/%s?sort=%s&' % (_('tags/'), sortby) } }, context_instance=RequestContext(request)) def tag(request, tag): return questions(request, tagname=tag) def vote(request, id): """ vote_type: acceptAnswer : 0, questionUpVote : 1, questionDownVote : 2, favorite : 4, answerUpVote: 5, answerDownVote:6, offensiveQuestion : 7, offensiveAnswer:8, removeQuestion: 9, removeAnswer:10 questionSubscribeUpdates:11 accept answer code: response_data['allowed'] = -1, Accept his own answer 0, no allowed - Anonymous 1, Allowed - by default response_data['success'] = 0, failed 1, Success - by default response_data['status'] = 0, By default 1, Answer has been accepted already(Cancel) vote code: allowed = -3, Don't have enough votes left -2, Don't have enough reputation score -1, Vote his own post 0, no allowed - Anonymous 1, Allowed - by default status = 0, By default 1, Cancel 2, Vote is too old to be canceled offensive code: allowed = -3, Don't have enough flags left -2, Don't have enough reputation score to do this 0, not allowed 1, allowed status = 0, by default 1, can't do it again """ response_data = { "allowed": 1, "success": 1, "status" : 0, "count" : 0, "message" : '' } def can_vote(vote_score, user): if vote_score == 1: return can_vote_up(request.user) else: return can_vote_down(request.user) try: if not request.user.is_authenticated(): response_data['allowed'] = 0 response_data['success'] = 0 elif request.is_ajax(): question = get_object_or_404(Question, id=id) vote_type = request.POST.get('type') #accept answer if vote_type == '0': answer_id = request.POST.get('postId') answer = get_object_or_404(Answer, id=answer_id) # make sure question author is current user if question.author == request.user: # answer user who is also question author is not allow to accept answer if answer.author == question.author: response_data['success'] = 0 response_data['allowed'] = -1 # check if answer has been accepted already elif answer.accepted: onAnswerAcceptCanceled(answer, request.user) response_data['status'] = 1 else: # set other answers in this question not accepted first for answer_of_question in Answer.objects.get_answers_from_question(question, request.user): if answer_of_question != answer and answer_of_question.accepted: onAnswerAcceptCanceled(answer_of_question, request.user) #make sure retrieve data again after above author changes, they may have related data answer = get_object_or_404(Answer, id=answer_id) onAnswerAccept(answer, request.user) else: response_data['allowed'] = 0 response_data['success'] = 0 # favorite elif vote_type == '4': has_favorited = False fav_questions = FavoriteQuestion.objects.filter(question=question) # if the same question has been favorited before, then delete it if fav_questions is not None: for item in fav_questions: if item.user == request.user: item.delete() response_data['status'] = 1 response_data['count'] = len(fav_questions) - 1 if response_data['count'] < 0: response_data['count'] = 0 has_favorited = True # if above deletion has not been executed, just insert a new favorite question if not has_favorited: new_item = FavoriteQuestion(question=question, user=request.user) new_item.save() response_data['count'] = FavoriteQuestion.objects.filter(question=question).count() Question.objects.update_favorite_count(question) elif vote_type in ['1', '2', '5', '6']: post_id = id post = question vote_score = 1 if vote_type in ['5', '6']: answer_id = request.POST.get('postId') answer = get_object_or_404(Answer, id=answer_id) post_id = answer_id post = answer if vote_type in ['2', '6']: vote_score = -1 if post.author == request.user: response_data['allowed'] = -1 elif not can_vote(vote_score, request.user): response_data['allowed'] = -2 elif post.votes.filter(user=request.user).count() > 0: vote = post.votes.filter(user=request.user)[0] # unvote should be less than certain time if (datetime.datetime.now().day - vote.voted_at.day) >= VOTE_RULES['scope_deny_unvote_days']: response_data['status'] = 2 else: voted = vote.vote if voted > 0: # cancel upvote onUpVotedCanceled(vote, post, request.user) else: # cancel downvote onDownVotedCanceled(vote, post, request.user) response_data['status'] = 1 response_data['count'] = post.score elif Vote.objects.get_votes_count_today_from_user(request.user) >= VOTE_RULES['scope_votes_per_user_per_day']: response_data['allowed'] = -3 else: vote = Vote(user=request.user, content_object=post, vote=vote_score, voted_at=datetime.datetime.now()) if vote_score > 0: # upvote onUpVoted(vote, post, request.user) else: # downvote onDownVoted(vote, post, request.user) votes_left = VOTE_RULES['scope_votes_per_user_per_day'] - Vote.objects.get_votes_count_today_from_user(request.user) if votes_left <= VOTE_RULES['scope_warn_votes_left']: response_data['message'] = u'%s votes left' % votes_left response_data['count'] = post.score elif vote_type in ['7', '8']: post = question post_id = id if vote_type == '8': post_id = request.POST.get('postId') post = get_object_or_404(Answer, id=post_id) if FlaggedItem.objects.get_flagged_items_count_today(request.user) >= VOTE_RULES['scope_flags_per_user_per_day']: response_data['allowed'] = -3 elif not can_flag_offensive(request.user): response_data['allowed'] = -2 elif post.flagged_items.filter(user=request.user).count() > 0: response_data['status'] = 1 else: item = FlaggedItem(user=request.user, content_object=post, flagged_at=datetime.datetime.now()) onFlaggedItem(item, post, request.user) response_data['count'] = post.offensive_flag_count # send signal when question or answer be marked offensive mark_offensive.send(sender=post.__class__, instance=post, mark_by=request.user) elif vote_type in ['9', '10']: post = question post_id = id if vote_type == '10': post_id = request.POST.get('postId') post = get_object_or_404(Answer, id=post_id) if not can_delete_post(request.user, post): response_data['allowed'] = -2 elif post.deleted: onDeleteCanceled(post, request.user) response_data['status'] = 1 else: onDeleted(post, request.user) delete_post_or_answer.send(sender=post.__class__, instance=post, delete_by=request.user) 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 settings.EMAIL_VALIDATION == 'on' and user.email_isvalid == False: response_data['message'] = _('subscription saved, %(email)s needs validation') % {'email':user.email} #response_data['status'] = 1 #responst_data['allowed'] = 1 else: pass #response_data['status'] = 0 #response_data['allowed'] = 0 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 else: response_data['success'] = 0 response_data['message'] = u'Request mode is not supported. Please try again.' data = simplejson.dumps(response_data) except Exception, e: response_data['message'] = str(e) data = simplejson.dumps(response_data) return HttpResponse(data, mimetype="application/json") def users(request): is_paginated = True sortby = request.GET.get('sort', 'reputation') suser = request.REQUEST.get('q', "") try: page = int(request.GET.get('page', '1')) except ValueError: page = 1 if suser == "": if sortby == "newest": objects_list = Paginator(User.objects.all().order_by('-date_joined'), USERS_PAGE_SIZE) elif sortby == "last": objects_list = Paginator(User.objects.all().order_by('date_joined'), USERS_PAGE_SIZE) elif sortby == "user": objects_list = Paginator(User.objects.all().order_by('username'), USERS_PAGE_SIZE) # default else: objects_list = Paginator(User.objects.all().order_by('-reputation'), USERS_PAGE_SIZE) base_url = '/%s?sort=%s&' % (_('users/'), 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) try: users = objects_list.page(page) except (EmptyPage, InvalidPage): 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)) def user(request, id): sort = request.GET.get('sort', 'stats') user_view = dict((v.id, v) for v in USER_TEMPLATE_VIEWS).get(sort, USER_TEMPLATE_VIEWS[0]) from forum import views func = getattr(views, user_view.view_name) return func(request, id, user_view) @login_required def edit_user(request, id): user = get_object_or_404(User, id=id) if request.user != user: raise Http404 if request.method == "POST": form = EditUserForm(user, request.POST) if form.is_valid(): new_email = sanitize_html(form.cleaned_data['email']) from django_authopenid.views import set_new_email set_new_email(user, new_email) 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']) user.date_of_birth = sanitize_html(form.cleaned_data['birthday']) if len(user.date_of_birth) == 0: user.date_of_birth = '1900-01-01' user.about = sanitize_html(form.cleaned_data['about']) user.save() # send user updated singal if full fields have been updated if user.email and user.real_name and user.website and user.location and \ user.date_of_birth and user.about: user_updated.send(sender=user.__class__, instance=user, updated_by=user) return HttpResponseRedirect(user.get_profile_url()) else: form = EditUserForm(user) return render_to_response('user_edit.html', { 'form' : form, }, context_instance=RequestContext(request)) def user_stats(request, user_id, user_view): user = get_object_or_404(User, id=user_id) questions = Question.objects.extra( select={ 'vote_count' : 'question.score', 'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s AND f.question_id = question.id', 'la_user_id' : 'auth_user.id', 'la_username' : 'auth_user.username', 'la_user_gold' : 'auth_user.gold', 'la_user_silver' : 'auth_user.silver', 'la_user_bronze' : 'auth_user.bronze', 'la_user_reputation' : 'auth_user.reputation' }, select_params=[user_id], tables=['question', 'auth_user'], where=['question.deleted = 0 AND question.author_id=%s AND question.last_activity_by_id = auth_user.id'], params=[user_id], order_by=['-vote_count', '-last_activity_at'] ).values('vote_count', 'favorited_myself', 'id', 'title', 'author_id', 'added_at', 'answer_accepted', 'answer_count', 'comment_count', 'view_count', 'favourite_count', 'summary', 'tagnames', 'vote_up_count', 'vote_down_count', 'last_activity_at', 'la_user_id', 'la_username', 'la_user_gold', 'la_user_silver', 'la_user_bronze', '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] 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] if settings.DJANGO_VERSION < 1.1: 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') total_awards = awards.count() awards.query.group_by = ['badge_id'] else: 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') total_awards = awards.count() #fixed to work with Django version < 1.1 try: from django.db.models import Count awards = awards.annotate(count = Count('badge__id')) except: pass 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)) def user_recent(request, user_id, user_view): user = get_object_or_404(User, id=user_id) def get_type_name(type_id): for item in TYPE_ACTIVITY: if type_id in item: return item[1] class Event: def __init__(self, time, type, title, summary, answer_id, question_id): self.time = time self.type = get_type_name(type) self.type_id = type self.title = title self.summary = summary slug_title = slugify(title) if int(answer_id) > 0: self.title_link = u'/%s%s/%s#%s' %(_('questions/'),question_id, slug_title, answer_id) else: self.title_link = u'/%s%s/%s' %(_('questions/'),question_id, slug_title) class AwardEvent: def __init__(self, time, type, id): self.time = time self.type = get_type_name(type) self.type_id = type self.badge = get_object_or_404(Badge, id=id) 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' ) if len(questions) > 0: questions = [(Event(q['active_at'], q['activity_type'], q['title'], '', '0', \ q['question_id'])) for q in questions] activities.extend(questions) # 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' ) if len(answers) > 0: answers = [(Event(q['active_at'], q['activity_type'], q['title'], '', q['answer_id'], \ q['question_id'])) for q in answers] activities.extend(answers) # 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' ) if len(comments) > 0: comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \ q['question_id'])) for q in comments] activities.extend(comments) # 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' ) if len(comments) > 0: comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', q['answer_id'], \ q['question_id'])) for q in comments] activities.extend(comments) # 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' ) if len(revisions) > 0: revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], '0', \ q['question_id'])) for q in revisions] activities.extend(revisions) # 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' ) if len(revisions) > 0: revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], \ q['answer_id'], q['question_id'])) for q in revisions] activities.extend(revisions) # 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', ) 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] activities.extend(accept_answers) #award history awards = Activity.objects.extra( select={ 'badge_id' : 'badge.id', 'awarded_at': 'award.awarded_at', 'activity_type' : 'activity.activity_type' }, tables=['activity', 'award', 'badge'], where=['activity.user_id = award.user_id AND activity.user_id = %s AND '+ 'award.badge_id=badge.id AND activity.object_id=award.id AND activity.activity_type=%s'], params=[user_id, TYPE_ACTIVITY_PRIZE], order_by=['-activity.active_at'] ).values( 'badge_id', 'awarded_at', 'activity_type' ) if len(awards) > 0: awards = [(AwardEvent(q['awarded_at'], q['activity_type'], q['badge_id'])) for q in awards] activities.extend(awards) 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)) def user_responses(request, user_id, user_view): """ We list answers for question, comments, and answer accepted by others for this user. """ class Response: 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, title, answer_id) self.time = time self.userlink = u'/%s%s/%s/' % (_('users/'), user_id, username) self.username = username self.content = u'%s ...' % strip_tags(content)[:300] def __unicode__(self): return u'%s %s' % (self.type, self.titlelink) 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' ) 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] responses.extend(answers) # 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' ) if len(comments) > 0: comments = [(Response(TYPE_RESPONSE['QUESTION_COMMENTED'], c['title'], c['question_id'], '', c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments] responses.extend(comments) # answer comments comments = Comment.objects.extra( select={ 'title' : 'question.title', 'question_id' : 'question.id', 'answer_id' : 'answer.id', 'added_at' : 'comment.added_at', 'comment' : 'comment.comment', 'username' : 'auth_user.username', 'user_id' : 'auth_user.id' }, tables=['answer', 'auth_user', 'comment', 'question'], where=['answer.deleted = 0 AND answer.author_id = %s AND comment.object_id=answer.id AND '+ 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id '+ 'AND question.id = answer.question_id'], params=[user_id, answer_type_id, user_id], order_by=['-comment.added_at'] ).values( 'title', 'question_id', 'answer_id', 'added_at', 'comment', 'username', 'user_id' ) if len(comments) > 0: comments = [(Response(TYPE_RESPONSE['ANSWER_COMMENTED'], c['title'], c['question_id'], c['answer_id'], c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments] responses.extend(comments) # answer has been accepted answers = Answer.objects.extra( select={ 'title' : 'question.title', 'question_id' : 'question.id', 'answer_id' : 'answer.id', 'added_at' : 'answer.accepted_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 '+ 'answer.author_id = %s AND answer.accepted=1 AND question.author_id=auth_user.id'], params=[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['ANSWER_ACCEPTED'], a['title'], a['question_id'], a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers] responses.extend(answers) # sort posts by time responses.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, "responses" : responses[:user_view.data_size], }, context_instance=RequestContext(request)) def user_votes(request, user_id, user_view): user = get_object_or_404(User, id=user_id) if not can_view_user_votes(request.user, user): raise Http404 votes = [] question_votes = Vote.objects.extra( select={ 'title' : 'question.title', 'question_id' : 'question.id', 'answer_id' : 0, 'voted_at' : 'vote.voted_at', 'vote' : 'vote', }, select_params=[user_id], tables=['vote', 'question', 'auth_user'], where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = question.id '+ 'AND vote.user_id=auth_user.id'], params=[question_type_id, user_id], order_by=['-vote.id'] ).values( 'title', 'question_id', 'answer_id', 'voted_at', 'vote', ) if(len(question_votes) > 0): votes.extend(question_votes) answer_votes = Vote.objects.extra( select={ 'title' : 'question.title', 'question_id' : 'question.id', 'answer_id' : 'answer.id', 'voted_at' : 'vote.voted_at', 'vote' : 'vote', }, select_params=[user_id], tables=['vote', 'answer', 'question', 'auth_user'], where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = answer.id '+ 'AND answer.question_id = question.id AND vote.user_id=auth_user.id'], params=[answer_type_id, user_id], order_by=['-vote.id'] ).values( 'title', 'question_id', 'answer_id', 'voted_at', 'vote', ) if(len(answer_votes) > 0): votes.extend(answer_votes) votes.sort(lambda x,y: cmp(y['voted_at'], x['voted_at'])) 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, "votes" : votes[:user_view.data_size] }, context_instance=RequestContext(request)) def user_reputation(request, user_id, user_view): user = get_object_or_404(User, id=user_id) reputation = Repute.objects.extra( select={'positive': 'sum(positive)', 'negative': 'sum(negative)', 'question_id':'question_id', 'title': 'question.title'}, tables=['repute', 'question'], order_by=['-reputed_at'], where=['user_id=%s AND question_id=question.id'], params=[user.id] ).values('positive', 'negative', 'question_id', 'title', 'reputed_at', 'reputation') reputation.query.group_by = ['question_id'] rep_list = [] for rep in Repute.objects.filter(user=user).order_by('reputed_at'): dic = '[%s,%s]' % (calendar.timegm(rep.reputed_at.timetuple()) * 1000, rep.reputation) rep_list.append(dic) reps = ','.join(rep_list) reps = '[%s]' % reps 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, "reputation" : reputation, "reps" : reps }, context_instance=RequestContext(request)) def user_favorites(request, user_id, user_view): user = get_object_or_404(User, id=user_id) questions = Question.objects.extra( select={ 'vote_count' : 'question.vote_up_count + question.vote_down_count', 'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s '+ 'AND f.question_id = question.id', 'la_user_id' : 'auth_user.id', 'la_username' : 'auth_user.username', 'la_user_gold' : 'auth_user.gold', 'la_user_silver' : 'auth_user.silver', 'la_user_bronze' : 'auth_user.bronze', 'la_user_reputation' : 'auth_user.reputation' }, select_params=[user_id], tables=['question', 'auth_user', 'favorite_question'], where=['question.deleted = 0 AND question.last_activity_by_id = auth_user.id '+ 'AND favorite_question.question_id = question.id AND favorite_question.user_id = %s'], params=[user_id], order_by=['-vote_count', '-question.id'] ).values('vote_count', 'favorited_myself', 'id', 'title', 'author_id', 'added_at', 'answer_accepted', 'answer_count', 'comment_count', 'view_count', 'favourite_count', 'summary', 'tagnames', 'vote_up_count', 'vote_down_count', 'last_activity_at', 'la_user_id', 'la_username', 'la_user_gold', 'la_user_silver', 'la_user_bronze', 'la_user_reputation') 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, "questions" : questions[:user_view.data_size], "view_user" : user }, context_instance=RequestContext(request)) def user_preferences(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)) def question_comments(request, id): question = get_object_or_404(Question, id=id) user = request.user return __comments(request, question, 'question', user) def answer_comments(request, id): answer = get_object_or_404(Answer, id=id) user = request.user return __comments(request, answer, 'answer', user) def __comments(request, obj, type, user): # only support get comments by ajax now if request.is_ajax(): if request.method == "GET": return __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) def __generate_comments_json(obj, type, user): 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 = [] 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" : "/%s%s/%s" % (_('users/'), comment_user.id, comment_user.username), "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_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) def logout(request): url = request.GET.get('next') return render_to_response('logout.html', { 'next' : url, }, context_instance=RequestContext(request)) def badges(request): badges = Badge.objects.all().order_by('type') my_badges = [] if request.user.is_authenticated(): my_badges = Award.objects.filter(user=request.user) my_badges.query.group_by = ['badge_id'] return render_to_response('badges.html', { 'badges' : badges, 'mybadges' : my_badges, }, context_instance=RequestContext(request)) def badge(request, id): badge = get_object_or_404(Badge, id=id) awards = Award.objects.extra( select={'id': 'auth_user.id', 'name': 'auth_user.username', 'rep':'auth_user.reputation', 'gold': 'auth_user.gold', 'silver': 'auth_user.silver', 'bronze': 'auth_user.bronze'}, tables=['award', 'auth_user'], where=['badge_id=%s AND user_id=auth_user.id'], params=[id] ).values('id').distinct() return render_to_response('badge.html', { 'awards' : awards, 'badge' : badge, }, context_instance=RequestContext(request)) def read_message(request): if request.method == "POST": if request.POST['formdata'] == 'required': request.session['message_silent'] = 1 if request.user.is_authenticated(): request.user.delete_messages() return HttpResponse('') def upload(request): class FileTypeNotAllow(Exception): pass class FileSizeNotAllow(Exception): pass class UploadPermissionNotAuthorized(Exception): pass #%s xml_template = "%s" try: f = request.FILES['file-upload'] # check upload permission if not can_upload_files(request.user): raise UploadPermissionNotAuthorized # check file type file_name_suffix = os.path.splitext(f.name)[1].lower() 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 # use default storage to store file default_storage.save(new_file_name, f) # check file size # byte size = default_storage.size(new_file_name) if size > settings.ALLOW_MAX_FILE_SIZE: default_storage.delete(new_file_name) raise FileSizeNotAllow result = xml_template % ('Good', '', default_storage.url(new_file_name)) except UploadPermissionNotAuthorized: result = xml_template % ('', _('uploading images is limited to users with >60 reputation points'), '') except FileTypeNotAllow: result = xml_template % ('', _("allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'"), '') except FileSizeNotAllow: result = xml_template % ('', _("maximum upload file size is %sK") % settings.ALLOW_MAX_FILE_SIZE / 1024, '') except Exception: result = xml_template % ('', _('Error uploading file. Please contact the site administrator. Thank you. %s' % Exception), '') return HttpResponse(result, mimetype="application/xml") def books(request): return HttpResponseRedirect("/books/mysql-zhaoyang") def book(request, short_name, unanswered=False): """ 1. questions list 2. book info 3. author info and blog rss items """ """ List of Questions, Tagged questions, and Unanswered questions. """ books = Book.objects.extra(where=['short_name = %s'], params=[short_name]) match_count = len(books) if match_count == 0 : raise Http404 else: # the book info book = books[0] # get author info author_info = BookAuthorInfo.objects.get(book=book) # get author rss info author_rss = BookAuthorRss.objects.filter(book=book) # get pagesize from session, if failed then get default value user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE) # set pagesize equal to logon user specified value in database if request.user.is_authenticated() and request.user.questions_per_page > 0: user_page_size = request.user.questions_per_page try: page = int(request.GET.get('page', '1')) 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" # check if request is from tagged questions if unanswered: # check if request is from unanswered questions # Article.objects.filter(publications__id__exact=1) objects = Question.objects.filter(book__id__exact=book.id, deleted=False, answer_count=0).order_by(orderby) else: objects = Question.objects.filter(book__id__exact=book.id, deleted=False).order_by(orderby) # RISK - inner join queries objects = objects.select_related(); objects_list = Paginator(objects, user_page_size) questions = objects_list.page(page) return render_to_response('book.html', { "book" : book, "author_info" : author_info, "author_rss" : author_rss, "questions" : questions, "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' : user_page_size } }, context_instance=RequestContext(request)) @login_required def ask_book(request, short_name): if request.method == "POST": form = AskForm(request.POST) if form.is_valid(): added_at = datetime.datetime.now() html = sanitize_html(markdowner.convert(form.cleaned_data['text'])) question = Question( title = strip_tags(form.cleaned_data['title']), author = request.user, added_at = added_at, last_activity_at = added_at, last_activity_by = request.user, wiki = form.cleaned_data['wiki'], tagnames = form.cleaned_data['tags'].strip(), html = html, summary = strip_tags(html)[:120] ) if question.wiki: question.last_edited_by = question.author question.last_edited_at = added_at question.wikified_at = added_at question.save() # create the first revision QuestionRevision.objects.create( question = question, revision = 1, title = question.title, author = request.user, revised_at = added_at, tagnames = question.tagnames, summary = CONST['default_version'], text = form.cleaned_data['text'] ) books = Book.objects.extra(where=['short_name = %s'], params=[short_name]) match_count = len(books) if match_count == 1: # the book info book = books[0] book.questions.add(question) return HttpResponseRedirect(question.get_absolute_url()) else: form = AskForm() tags = _get_tags_cache_json() return render_to_response('ask.html', { 'form' : form, 'tags' : tags, }, context_instance=RequestContext(request)) def search(request): """ Search by question, user and tag keywords. For questions now we only search keywords in question title. """ if request.method == "GET": keywords = request.GET.get("q") search_type = request.GET.get("t") try: page = int(request.GET.get('page', '1')) except ValueError: page = 1 if keywords is None: return HttpResponseRedirect('/') if search_type == 'tag': return HttpResponseRedirect('/%s?q=%s&page=%s' % (_('tags/'), keywords.strip(), page)) elif search_type == "user": return HttpResponseRedirect('/%s?q=%s&page=%s' % (_('users/'), keywords.strip(), page)) elif search_type == "question": template_file = "questions.html" # Set flag to False by default. If it is equal to True, then need to be saved. pagesize_changed = False # get pagesize from session, if failed then get default value user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE) # set pagesize equal to logon user specified value in database if request.user.is_authenticated() and request.user.questions_per_page > 0: user_page_size = request.user.questions_per_page try: page = int(request.GET.get('page', '1')) # get new pagesize from UI selection pagesize = int(request.GET.get('pagesize', user_page_size)) if pagesize <> user_page_size: pagesize_changed = True except ValueError: page = 1 pagesize = user_page_size # save this pagesize to user database if pagesize_changed: request.session["pagesize"] = pagesize if request.user.is_authenticated(): user = request.user user.questions_per_page = pagesize user.save() 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" objects = Question.objects.filter(deleted=False).extra(where=['title like %s'], params=['%' + keywords + '%']).order_by(orderby) # RISK - inner join queries objects = objects.select_related(); objects_list = Paginator(objects, pagesize) questions = objects_list.page(page) # Get related tags from this page objects related_tags = [] for question in questions.object_list: tags = list(question.tags.all()) for tag in tags: if tag not in related_tags: related_tags.append(tag) return render_to_response(template_file, { "questions" : questions, "tab_id" : view_id, "questions_count" : objects_list.count, "tags" : related_tags, "searchtag" : None, "searchtitle" : keywords, "keywords" : keywords, "is_unanswered" : False, "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 + '?t=question&q=%s&sort=%s&' % (keywords, view_id), 'pagesize' : pagesize }}, context_instance=RequestContext(request)) else: raise Http404