diff options
Diffstat (limited to 'forum/views')
-rwxr-xr-x[-rw-r--r--] | forum/views/README | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | forum/views/__init__.py | 1 | ||||
-rw-r--r-- | forum/views/auth.py | 359 | ||||
-rwxr-xr-x[-rw-r--r--] | forum/views/commands.py | 34 | ||||
-rwxr-xr-x[-rw-r--r--] | forum/views/meta.py | 4 | ||||
-rw-r--r-- | forum/views/readers.py | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | forum/views/users.py | 39 | ||||
-rwxr-xr-x[-rw-r--r--] | forum/views/writers.py | 152 |
8 files changed, 452 insertions, 144 deletions
diff --git a/forum/views/README b/forum/views/README index 7b6201cd..5416f88c 100644..100755 --- a/forum/views/README +++ b/forum/views/README @@ -9,4 +9,4 @@ users.py - user views - user listing and profiles meta.py - privacy, about, faq, feedback, logout, badges -books.py - book views - to be moved to a books extension +auth.py - Authentication related views diff --git a/forum/views/__init__.py b/forum/views/__init__.py index 291fee2a..a5f6f99d 100644..100755 --- a/forum/views/__init__.py +++ b/forum/views/__init__.py @@ -3,3 +3,4 @@ import writers import commands import users import meta +import auth diff --git a/forum/views/auth.py b/forum/views/auth.py new file mode 100644 index 00000000..72b0af29 --- /dev/null +++ b/forum/views/auth.py @@ -0,0 +1,359 @@ +from django.shortcuts import render_to_response, get_object_or_404 +from django.template import RequestContext +from django.core.urlresolvers import reverse +from django.contrib.auth.models import User +from django.http import HttpResponseRedirect, Http404 +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext as _ +from django.utils.http import urlquote_plus +from django.contrib.auth.decorators import login_required +from django.contrib.auth import login, logout +from django.http import get_host +import types +import datetime + +from forum.models import AuthKeyUserAssociation, ValidationHash +from forum.authentication.forms import SimpleRegistrationForm, SimpleEmailSubscribeForm, \ + TemporaryLoginRequestForm, ChangePasswordForm, SetPasswordForm +from forum.utils.email import send_email + +from forum.authentication.base import InvalidAuthentication +from forum.authentication import AUTH_PROVIDERS + +from forum.models import Question, Answer + +def signin_page(request, action=None): + if action is None: + request.session['on_signin_url'] = request.META.get('HTTP_REFERER', '/') + else: + request.session['on_signin_action'] = action + request.session['on_signin_url'] = reverse('auth_action_signin', kwargs={'action': action}) + + all_providers = [provider.context for provider in AUTH_PROVIDERS.values()] + + sort = lambda c1, c2: c1.weight - c2.weight + can_show = lambda c: not request.user.is_authenticated() or c.show_to_logged_in_user + + bigicon_providers = sorted([ + context for context in all_providers if context.mode == 'BIGICON' and can_show(context) + ], sort) + + smallicon_providers = sorted([ + context for context in all_providers if context.mode == 'SMALLICON' and can_show(context) + ], sort) + + stackitem_providers = sorted([ + context for context in all_providers if context.mode == 'STACK_ITEM' and can_show(context) + ], sort) + + try: + msg = request.session['auth_error'] + del request.session['auth_error'] + except: + msg = None + + return render_to_response( + 'auth/signin.html', + { + 'msg': msg, + 'all_providers': all_providers, + 'bigicon_providers': bigicon_providers, + 'stackitem_providers': stackitem_providers, + 'smallicon_providers': smallicon_providers, + }, + RequestContext(request)) + +def prepare_provider_signin(request, provider): + force_email_request = request.REQUEST.get('validate_email', 'yes') == 'yes' + request.session['force_email_request'] = force_email_request + + if provider in AUTH_PROVIDERS: + provider_class = AUTH_PROVIDERS[provider].consumer + + try: + request_url = provider_class.prepare_authentication_request(request, + reverse('auth_provider_done', kwargs={'provider': provider})) + + return HttpResponseRedirect(request_url) + except NotImplementedError, e: + return process_provider_signin(request, provider) + except InvalidAuthentication, e: + request.session['auth_error'] = e.message + + return HttpResponseRedirect(reverse('auth_signin')) + + +def process_provider_signin(request, provider): + if provider in AUTH_PROVIDERS: + provider_class = AUTH_PROVIDERS[provider].consumer + + try: + assoc_key = provider_class.process_authentication_request(request) + except InvalidAuthentication, e: + request.session['auth_error'] = e.message + return HttpResponseRedirect(reverse('auth_signin')) + + if request.user.is_authenticated(): + if isinstance(assoc_key, (type, User)): + if request.user != assoc_key: + request.session['auth_error'] = _("Sorry, these login credentials belong to anoother user. Plese terminate your current session and try again.") + else: + request.session['auth_error'] = _("You are already logged in with that user.") + else: + try: + assoc = AuthKeyUserAssociation.objects.get(key=assoc_key) + if assoc.user == request.user: + request.session['auth_error'] = _("These login credentials are already associated with your account.") + else: + request.session['auth_error'] = _("Sorry, these login credentials belong to anoother user. Plese terminate your current session and try again.") + except: + uassoc = AuthKeyUserAssociation(user=request.user, key=assoc_key, provider=provider) + uassoc.save() + request.user.message_set.create(message=_('The new credentials are now associated with your account')) + return HttpResponseRedirect(reverse('user_authsettings')) + + return HttpResponseRedirect(reverse('auth_signin')) + else: + if isinstance(assoc_key, (type, User)): + return login_and_forward(request, assoc_key) + + try: + assoc = AuthKeyUserAssociation.objects.get(key=assoc_key) + user_ = assoc.user + return login_and_forward(request, user_) + except: + request.session['assoc_key'] = assoc_key + request.session['auth_provider'] = provider + return HttpResponseRedirect(reverse('auth_external_register')) + + return HttpResponseRedirect(reverse('auth_signin')) + +def external_register(request): + if request.method == 'POST' and 'bnewaccount' in request.POST: + form1 = SimpleRegistrationForm(request.POST) + email_feeds_form = SimpleEmailSubscribeForm(request.POST) + + if (form1.is_valid() and email_feeds_form.is_valid()): + user_ = User(username=form1.cleaned_data['username'], email=form1.cleaned_data['email']) + user_.email_isvalid = request.session.get('auth_validated_email', '') == form1.cleaned_data['email'] + user_.set_unusable_password() + + user_.save() + + if not user_.email_isvalid: + send_validation_email(user_) + + try: + assoc_key = request.session['assoc_key'] + auth_provider = request.session['auth_provider'] + except: + request.session['auth_error'] = _("Oops, something went wrong in the middle of this process. Please try again.") + return HttpResponseRedirect(request.session.get('on_signin_url', reverse('auth_signin'))) + + uassoc = AuthKeyUserAssociation(user=user_, key=request.session['assoc_key'], provider=request.session['auth_provider']) + uassoc.save() + + email_feeds_form.save(user_) + + del request.session['assoc_key'] + del request.session['auth_provider'] + + if user_.email_isvalid: + return login_and_forward(request, user_) + else: + return HttpResponseRedirect(reverse('index')) + else: + provider_class = AUTH_PROVIDERS[request.session['auth_provider']].consumer + user_data = provider_class.get_user_data(request.session['assoc_key']) + + username = user_data.get('username', '') + email = user_data.get('email', '') + + if not email: + email = request.session.get('auth_email_request', '') + + if email: + request.session['auth_validated_email'] = email + + form1 = SimpleRegistrationForm(initial={ + 'next': '/', + 'username': username, + 'email': email, + }) + email_feeds_form = SimpleEmailSubscribeForm() + + provider_context = AUTH_PROVIDERS[request.session['auth_provider']].context + + return render_to_response('auth/complete.html', { + 'form1': form1, + 'email_feeds_form': email_feeds_form, + 'provider':mark_safe(provider_context.human_name), + 'login_type':provider_context.id, + 'gravatar_faq_url':reverse('faq') + '#gravatar', + }, context_instance=RequestContext(request)) + +def request_temp_login(request): + if request.method == 'POST': + form = TemporaryLoginRequestForm(request.POST) + + if form.is_valid(): + user = form.user_cache + + try: + hash = get_object_or_404(ValidationHash, user=user, type='templogin') + if hash.expiration < datetime.datetime.now(): + hash.delete() + return request_temp_login(request) + except: + hash = ValidationHash.objects.create_new(user, 'templogin', [user.id]) + + send_email(_("Temporary login link"), [user.email], "auth/temp_login_email.html", { + 'temp_login_code': hash, + 'user': user + }) + + request.user.message_set.create(message=_("An email has been sent with your temporary login key")) + + return HttpResponseRedirect(reverse('index')) + else: + form = TemporaryLoginRequestForm() + + return render_to_response( + 'auth/temp_login_request.html', {'form': form}, + context_instance=RequestContext(request)) + +def temp_signin(request, user, code): + user = get_object_or_404(User, id=user) + + if (ValidationHash.objects.validate(code, user, 'templogin', [user.id])): + return login_and_forward(request, user, reverse('user_authsettings'), + _("You are logged in with a temporary access key, please take the time to fix your issue with authentication.")) + else: + raise Http404() + +def send_validation_email(user): + hash = ValidationHash.objects.create_new(user, 'email', [user.email]) + send_email(_("Email Validation"), [user.email], "auth/email_validation.html", { + 'validation_code': hash, + 'user': user + }) + +def validate_email(request, user, code): + user = get_object_or_404(User, id=user) + + if (ValidationHash.objects.validate(code, user, 'email', [user.email])): + user.email_isvalid = True + user.save() + return login_and_forward(request, user, None, _("Thank you, your email is now validated.")) + else: + raise Http404() + +@login_required +def auth_settings(request): + """ + change password view. + + url : /changepw/ + template: authopenid/changepw.html + """ + user_ = request.user + auth_keys = user_.auth_keys.all() + + if user_.has_usable_password(): + FormClass = ChangePasswordForm + else: + FormClass = SetPasswordForm + + if request.POST: + form = FormClass(request.POST, user=user_) + if form.is_valid(): + if user_.has_usable_password(): + request.user.message_set.create(message=_("Your password was changed")) + else: + request.user.message_set.create(message=_("New password set")) + form = ChangePasswordForm(user=user_) + + user_.set_password(form.cleaned_data['password1']) + user_.save() + return HttpResponseRedirect(reverse('user_authsettings')) + else: + form = FormClass(user=user_) + + auth_keys_list = [] + + for k in auth_keys: + provider = AUTH_PROVIDERS.get(k.provider, None) + + if provider is not None: + name = "%s: %s" % (provider.context.human_name, provider.context.readable_key(k)) + else: + from forum.authentication.base import ConsumerTemplateContext + "unknown: %s" % ConsumerTemplateContext.readable_key(k) + + auth_keys_list.append({ + 'name': name, + 'id': k.id + }) + + return render_to_response('auth/auth_settings.html', { + 'form': form, + 'has_password': user_.has_usable_password(), + 'auth_keys': auth_keys_list, + }, context_instance=RequestContext(request)) + +def remove_external_provider(request, id): + association = get_object_or_404(AuthKeyUserAssociation, id=id) + request.user.message_set.create(message=_("You removed the association with %s") % association.provider) + association.delete() + return HttpResponseRedirect(reverse('user_authsettings')) + +def newquestion_signin_action(user): + question = Question.objects.filter(author=user).order_by('-added_at')[0] + return question.get_absolute_url() + +def newanswer_signin_action(user): + answer = Answer.objects.filter(author=user).order_by('-added_at')[0] + return answer.get_absolute_url() + +POST_SIGNIN_ACTIONS = { + 'newquestion': newquestion_signin_action, + 'newanswer': newanswer_signin_action, +} + +def login_and_forward(request, user, forward=None, message=None): + old_session = request.session.session_key + user.backend = "django.contrib.auth.backends.ModelBackend" + login(request, user) + + from forum.models import user_logged_in + user_logged_in.send(user=user,session_key=old_session,sender=None) + + if not forward: + signin_action = request.session.get('on_signin_action', None) + if not signin_action: + forward = request.session.get('on_signin_url', None) + + if not forward: + forward = reverse('index') + else: + try: + forward = POST_SIGNIN_ACTIONS[signin_action](user) + except: + forward = reverse('index') + + if message is None: + message = _("Welcome back %s, you are now logged in") % user.username + + request.user.message_set.create(message=message) + return HttpResponseRedirect(forward) + +@login_required +def signout(request): + """ + signout from the website. Remove openid from session and kill it. + + url : /signout/" + """ + + logout(request) + return HttpResponseRedirect(reverse('index'))
\ No newline at end of file diff --git a/forum/views/commands.py b/forum/views/commands.py index 88c2c077..ca6569e2 100644..100755 --- a/forum/views/commands.py +++ b/forum/views/commands.py @@ -13,7 +13,7 @@ from django.contrib.auth.decorators import login_required from forum.utils.decorators import ajax_method, ajax_login_required import logging -def vote(request, id):#refactor - pretty incomprehensible view used by various ajax calls +def vote(request, id):#todo: pretty incomprehensible view used by various ajax calls #issues: this subroutine is too long, contains many magic numbers and other issues #it's called "vote" but many actions processed here have nothing to do with voting """ @@ -106,23 +106,12 @@ def vote(request, id):#refactor - pretty incomprehensible view used by various a # 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) + fave = request.user.toggle_favorite_question(question) + response_data['count'] = FavoriteQuestion.objects.filter( + question = question + ).count() + if fave == False: + response_data['status'] = 1 elif vote_type in ['1', '2', '5', '6']: post_id = id @@ -141,7 +130,13 @@ def vote(request, id):#refactor - pretty incomprehensible view used by various a elif not __can_vote(vote_score, request.user): response_data['allowed'] = -2 elif post.votes.filter(user=request.user).count() > 0: + #todo: I think we have a bug here + #we need to instead select vote on that particular post + #not just the latest vote, although it is a good shortcut. + #The problem is that this vote is deleted in one of + #the on...Canceled() functions vote = post.votes.filter(user=request.user)[0] + # get latest vote by the current user # unvote should be less than certain time if (datetime.datetime.now().day - vote.voted_at.day) >= auth.VOTE_RULES['scope_deny_unvote_days']: response_data['status'] = 2 @@ -189,8 +184,6 @@ def vote(request, id):#refactor - pretty incomprehensible view used by various a item = FlaggedItem(user=request.user, content_object=post, flagged_at=datetime.datetime.now()) auth.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 @@ -206,7 +199,6 @@ def vote(request, id):#refactor - pretty incomprehensible view used by various a response_data['status'] = 1 else: auth.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(): diff --git a/forum/views/meta.py b/forum/views/meta.py index b4c7a37f..6417e8f5 100644..100755 --- a/forum/views/meta.py +++ b/forum/views/meta.py @@ -15,7 +15,7 @@ def about(request): def faq(request): data = { 'gravatar_faq_url': reverse('faq') + '#gravatar', - 'send_email_key_url': reverse('send_email_key'), + #'send_email_key_url': reverse('send_email_key'), 'ask_question_url': reverse('ask'), } return render_to_response('faq.html', data, context_instance=RequestContext(request)) @@ -58,7 +58,7 @@ def logout(request):#refactor/change behavior? }, context_instance=RequestContext(request)) def badges(request):#user status/reputation system - badges = Badge.objects.all().order_by('type') + badges = Badge.objects.all().order_by('name') my_badges = [] if request.user.is_authenticated(): my_badges = Award.objects.filter(user=request.user).values('badge_id') diff --git a/forum/views/readers.py b/forum/views/readers.py index 6b0da476..938fa133 100644 --- a/forum/views/readers.py +++ b/forum/views/readers.py @@ -14,6 +14,7 @@ from django.utils.translation import ugettext as _ from django.template.defaultfilters import slugify from django.core.urlresolvers import reverse from django.utils.datastructures import SortedDict +from django.views.decorators.cache import cache_page from forum.utils.html import sanitize_html from markdown2 import Markdown @@ -87,7 +88,7 @@ def index(request):#generates front page - shows listing of questions sorted in } view_id, orderby = _get_and_remember_questions_sort_method(request, view_dic, 'latest') - pagesize = request.session.get("pagesize",QUESTIONS_PAGE_SIZE) + pagesize = QUESTIONS_PAGE_SIZE #request.session.get("pagesize",QUESTIONS_PAGE_SIZE) try: page = int(request.GET.get('page', '1')) except ValueError: @@ -145,7 +146,7 @@ def questions(request, tagname=None, unanswered=False):#a view generating listin # 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",QUESTIONS_PAGE_SIZE) + pagesize = QUESTIONS_PAGE_SIZE #request.session.get("pagesize",QUESTIONS_PAGE_SIZE) try: page = int(request.GET.get('page', '1')) except ValueError: diff --git a/forum/views/users.py b/forum/views/users.py index cc05c19e..ff92803c 100644..100755 --- a/forum/views/users.py +++ b/forum/views/users.py @@ -6,11 +6,13 @@ from django.contrib.contenttypes.models import ContentType from django.core.urlresolvers import reverse from django.shortcuts import render_to_response, get_object_or_404 from django.template import RequestContext -from django.http import HttpResponse, HttpResponseForbidden +from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect, Http404 from django.utils.translation import ugettext as _ +from django.utils.http import urlquote_plus from django.utils.html import strip_tags from django.core.urlresolvers import reverse -from forum.forms import *#incomplete list is EditUserForm, ModerateUserForm, TagFilterSelectionForm, +from forum.forms import *#incomplete list is EditUserForm, ModerateUserForm, TagFilterSelectionForm, +from forum.utils.html import sanitize_html from forum import auth import calendar from django.contrib.contenttypes.models import ContentType @@ -98,6 +100,14 @@ def moderate_user(request, id): response = HttpResponseForbidden(mimetype="application/json") return response +def set_new_email(user, new_email, nomessage=False): + if new_email != user.email: + user.email = new_email + user.email_isvalid = False + user.save() + #if settings.EMAIL_VALIDATION == 'on': + # send_new_email_key(user,nomessage=nomessage) + @login_required def edit_user(request, id): user = get_object_or_404(User, id=id) @@ -108,7 +118,6 @@ def edit_user(request, id): 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.username = sanitize_html(form.cleaned_data['username']) @@ -938,10 +947,32 @@ USER_TEMPLATE_VIEWS = ( ) ) -def user(request, id): +def user(request, id, slug=None): 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.views import users func = user_view.view_func return func(request, id, user_view) +@login_required +def account_settings(request): + """ + index pages to changes some basic account settings : + - change password + - change email + - associate a new openid + - delete account + + url : / + + template : authopenid/settings.html + """ + logging.debug('') + msg = request.GET.get('msg', '') + is_openid = False + + return render_to_response('account_settings.html', { + 'msg': msg, + 'is_openid': is_openid + }, context_instance=RequestContext(request)) + diff --git a/forum/views/writers.py b/forum/views/writers.py index c8ddc079..a9406fdc 100644..100755 --- a/forum/views/writers.py +++ b/forum/views/writers.py @@ -13,8 +13,6 @@ from django.utils.translation import ugettext as _ from django.core.urlresolvers import reverse from django.core.exceptions import PermissionDenied -from forum.utils.html import sanitize_html -from markdown2 import Markdown from forum.forms import * from forum.models import * from forum.auth import * @@ -34,8 +32,6 @@ QUESTIONS_PAGE_SIZE = 10 # used in answers ANSWERS_PAGE_SIZE = 10 -markdowner = Markdown(html4tags=True) - def upload(request):#ajax upload file to a question or answer class FileTypeNotAllow(Exception): pass @@ -94,12 +90,16 @@ def ask(request):#view used to ask a new question if form.is_valid(): added_at = datetime.datetime.now() + #todo: move this to clean_title title = strip_tags(form.cleaned_data['title'].strip()) wiki = form.cleaned_data['wiki'] + #todo: move this to clean_tagnames tagnames = form.cleaned_data['tags'].strip() text = form.cleaned_data['text'] - html = sanitize_html(markdowner.convert(text)) - summary = strip_tags(html)[:120] + + #todo: move this to AskForm.clean_text + #todo: make custom MarkDownField + text = form.cleaned_data['text'] if request.user.is_authenticated(): author = request.user @@ -110,14 +110,14 @@ def ask(request):#view used to ask a new question added_at = added_at, wiki = wiki, tagnames = tagnames, - summary = summary, - text = text + text = text, ) return HttpResponseRedirect(question.get_absolute_url()) else: request.session.flush() session_key = request.session.session_key + summary = strip_tags(text)[:120] question = AnonymousQuestion( session_key = session_key, title = title, @@ -129,7 +129,7 @@ def ask(request):#view used to ask a new question ip_addr = request.META['REMOTE_ADDR'], ) question.save() - return HttpResponseRedirect(reverse('user_signin_new_question')) + return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newquestion'})) else: form = AskForm() @@ -162,32 +162,11 @@ def _retag_question(request, question):#non-url subview of edit question - just 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 + question.retag( + retagged_by = request.user, + retagged_at = datetime.datetime.now(), + tagnames = form.cleaned_data['tags'], ) - # send tags updated singal - tags_updated.send(sender=question.__class__, question=question) - return HttpResponseRedirect(question.get_absolute_url()) else: form = RetagQuestionForm(question) @@ -201,7 +180,7 @@ def _edit_question(request, question):#non-url subview of edit_question - just e latest_revision = question.get_latest_revision() revision_form = None if request.method == 'POST': - if 'select_revision' in request.POST: + if 'select_revision' in request.POST:#revert-type edit # user has changed revistion number revision_form = RevisionForm(question, latest_revision, request.POST) if revision_form.is_valid(): @@ -211,60 +190,26 @@ def _edit_question(request, question):#non-url subview of edit_question - just e revision=revision_form.cleaned_data['revision'])) else: form = EditQuestionForm(question, latest_revision, request.POST) - else: + else:#new content edit # 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'], + edited_by = request.user + question.apply_edit( + edited_at = edited_at, + edited_by = edited_by, + title = form.cleaned_data['title'], + text = form.cleaned_data['text'], + #todo: summary name clash in question and question revision + comment = form.cleaned_data['summary'], + tags = form.cleaned_data['tags'], + wiki = form.cleaned_data.get('wiki',False), ) - 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', { @@ -297,33 +242,15 @@ def edit_answer(request, id): 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() - + answer.apply_edit( + edited_at = edited_at, + edited_by = request.user, + text = form.cleaned_data['text'], + comment = form.cleaned_data['summary'], + wiki = False,#todo: fix this there is no "wiki" field on "edit answer" + ) return HttpResponseRedirect(answer.get_absolute_url()) else: revision_form = RevisionForm(answer, latest_revision) @@ -354,18 +281,16 @@ def answer(request, id):#process a new answer ) 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, + summary=strip_tags(text)[:120], session_key=request.session.session_key, ip_addr=request.META['REMOTE_ADDR'], ) anon.save() - return HttpResponseRedirect(reverse('user_signin_new_answer')) + return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newanswer'})) return HttpResponseRedirect(question.get_absolute_url()) @@ -412,11 +337,10 @@ def __comments(request, obj, type):#non-view generic ajax handler to load commen response = __generate_comments_json(obj, type, user) elif request.method == "POST": 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() + obj.add_comment( + comment = request.POST.get('comment'), + user = request.user, + ) response = __generate_comments_json(obj, type, user) else: response = HttpResponseForbidden(mimetype="application/json") |