summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-06-03 01:44:36 -0700
committerfadeev <fadeev@bacchus.bio.uci.edu>2010-06-03 01:45:30 -0700
commit02247d157b3da4d0711b8858bf758aefdf64c04d (patch)
treea3231ac1392bc815bdd75a1e2d0ed21fa94fbe4d
parent5dfebd5164518572b9f1c9822990ee476854304d (diff)
downloadaskbot-02247d157b3da4d0711b8858bf758aefdf64c04d.tar.gz
askbot-02247d157b3da4d0711b8858bf758aefdf64c04d.tar.bz2
askbot-02247d157b3da4d0711b8858bf758aefdf64c04d.zip
general debugging, still may be broken
-rw-r--r--forum/__init__.py15
-rw-r--r--forum/admin.py31
-rw-r--r--forum/auth.py241
-rw-r--r--forum/conf/site_settings.py1
-rw-r--r--forum/conf/skin_general_settings.py3
-rw-r--r--forum/const/__init__.py2
-rw-r--r--forum/const/message_keys.py2
-rw-r--r--forum/feed.py28
-rw-r--r--forum/forms.py43
-rw-r--r--forum/importers/stackexchange/management/commands/load_stackexchange.py5
-rw-r--r--forum/management/commands/base_command.py18
-rw-r--r--forum/management/commands/clean_award_badges.py18
-rw-r--r--forum/management/commands/multi_award_badges.py12
-rw-r--r--forum/management/commands/once_award_badges.py98
-rw-r--r--forum/management/commands/send_email_alerts.py20
-rw-r--r--forum/management/commands/subscribe_everyone.py19
-rw-r--r--forum/middleware/anon_user.py22
-rw-r--r--forum/middleware/pagesize.py15
-rw-r--r--forum/middleware/view_log.py4
-rw-r--r--forum/models/__init__.py92
-rw-r--r--forum/models/answer.py28
-rw-r--r--forum/models/base.py158
-rw-r--r--forum/models/content.py22
-rw-r--r--forum/models/meta.py34
-rw-r--r--forum/models/question.py78
-rw-r--r--forum/models/tag.py4
-rw-r--r--forum/models/user.py29
-rw-r--r--forum/search/state_manager.py50
-rw-r--r--forum/skins/__init__.py46
-rw-r--r--forum/skins/utils.py29
-rw-r--r--forum/templatetags/extra_tags.py60
-rw-r--r--forum/tests.py12
-rw-r--r--forum/urls.py231
-rw-r--r--forum/user_messages/context_processors.py1
-rw-r--r--forum/utils/colors.py4
-rw-r--r--forum/utils/email.py2
-rw-r--r--forum/utils/forms.py8
-rw-r--r--forum/utils/markup.py15
-rw-r--r--forum/views/__init__.py13
-rw-r--r--forum/views/commands.py5
-rw-r--r--forum/views/readers.py12
-rw-r--r--forum/views/users.py31
-rw-r--r--forum/views/writers.py91
-rw-r--r--settings.py6
-rwxr-xr-xsettings_local.py.dist5
45 files changed, 966 insertions, 697 deletions
diff --git a/forum/__init__.py b/forum/__init__.py
index 85cd5d26..d4d26875 100644
--- a/forum/__init__.py
+++ b/forum/__init__.py
@@ -1 +1,14 @@
-__all__ = ['admin','auth','const','feed','forms','managers','models','sitemap','urls','views']
+"""aksbot forum module
+"""
+__all__ = [
+ 'admin',
+ 'auth',
+ 'const',
+ 'feed',
+ 'forms',
+ 'managers',
+ 'models',
+ 'sitemap',
+ 'urls',
+ 'views'
+]
diff --git a/forum/admin.py b/forum/admin.py
index 41b68b9a..c5898574 100644
--- a/forum/admin.py
+++ b/forum/admin.py
@@ -1,6 +1,9 @@
+"""
+linking of forum modules to admin interface
+"""
# -*- coding: utf-8 -*-
from django.contrib import admin
-from forum.models import *
+from forum import models
class AnonymousQuestionAdmin(admin.ModelAdmin):
"""AnonymousQuestion admin class"""
@@ -53,19 +56,19 @@ class ActivityAdmin(admin.ModelAdmin):
#class BookAuthorRssAdmin(admin.ModelAdmin):
# """ admin class"""
-admin.site.register(Question, QuestionAdmin)
-admin.site.register(Tag, TagAdmin)
-admin.site.register(Answer, Answerdmin)
-admin.site.register(Comment, CommentAdmin)
-admin.site.register(Vote, VoteAdmin)
-admin.site.register(FlaggedItem, FlaggedItemAdmin)
-admin.site.register(FavoriteQuestion, FavoriteQuestionAdmin)
-admin.site.register(QuestionRevision, QuestionRevisionAdmin)
-admin.site.register(AnswerRevision, AnswerRevisionAdmin)
-admin.site.register(Badge, BadgeAdmin)
-admin.site.register(Award, AwardAdmin)
-admin.site.register(Repute, ReputeAdmin)
-admin.site.register(Activity, ActivityAdmin)
+admin.site.register(models.Question, QuestionAdmin)
+admin.site.register(models.Tag, TagAdmin)
+admin.site.register(models.Answer, Answerdmin)
+admin.site.register(models.Comment, CommentAdmin)
+admin.site.register(models.Vote, VoteAdmin)
+admin.site.register(models.FlaggedItem, FlaggedItemAdmin)
+admin.site.register(models.FavoriteQuestion, FavoriteQuestionAdmin)
+admin.site.register(models.QuestionRevision, QuestionRevisionAdmin)
+admin.site.register(models.AnswerRevision, AnswerRevisionAdmin)
+admin.site.register(models.Badge, BadgeAdmin)
+admin.site.register(models.Award, AwardAdmin)
+admin.site.register(models.Repute, ReputeAdmin)
+admin.site.register(models.Activity, ActivityAdmin)
#admin.site.register(Book, BookAdmin)
#admin.site.register(BookAuthorInfo, BookAuthorInfoAdmin)
#admin.site.register(BookAuthorRss, BookAuthorRssAdmin)
diff --git a/forum/auth.py b/forum/auth.py
index 7664a02e..e88c280e 100644
--- a/forum/auth.py
+++ b/forum/auth.py
@@ -7,11 +7,10 @@ and superuser status.
import datetime
from django.utils.translation import ugettext as _
from django.db import transaction
-from models import Repute
-from models import Question
-from models import Answer
-from models import signals
-from const import TYPE_REPUTATION
+from forum.models import Repute
+from forum.models import Question
+from forum.models import Answer
+from forum.models import signals
import logging
from forum.conf import settings as forum_settings
@@ -31,7 +30,7 @@ def can_flag_offensive(user):
user.reputation >= forum_settings.MIN_REP_TO_FLAG_OFFENSIVE or
user.is_superuser)
-def can_add_comments(user,subject):
+def can_add_comments(user, subject):
"""Determines if a User can add comments to Questions and Answers."""
if user.is_authenticated():
if user.id == subject.author.id:
@@ -40,31 +39,43 @@ def can_add_comments(user,subject):
return True
if user.is_superuser:
return True
- if isinstance(subject,Answer) and subject.question.author.id == user.id:
- return True
+ if isinstance(subject, Answer):
+ if subject.question.author.id == user.id:
+ return True
return False
def can_vote_down(user):
"""Determines if a User can vote Questions and Answers down."""
- return user.is_authenticated() and (
- user.reputation >= forum_settings.MIN_REP_TO_VOTE_DOWN or
- user.is_superuser)
+ if user.is_authenticated():
+ if user.reputation >= forum_settings.MIN_REP_TO_VOTE_DOWN:
+ return True
+ if user.is_superuser:
+ return True
+ return False
def can_retag_questions(user):
"""Determines if a User can retag Questions."""
- return user.is_authenticated() and (
- forum_settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS
- <= user.reputation
- < forum_settings.MIN_REP_TO_EDIT_OTHERS_POSTS or
- user.is_superuser)
+ if user.is_authenticated():
+ if user.reputation >= forum_settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS:
+ if user.reputation < forum_settings.MIN_REP_TO_EDIT_OTHERS_POSTS:
+ return True
+ if user.is_superuser:
+ return True
+ return False
def can_edit_post(user, post):
"""Determines if a User can edit the given Question or Answer."""
- return user.is_authenticated() and (
- user.id == post.author_id or
- (post.wiki and user.reputation >= forum_settings.MIN_REP_TO_EDIT_WIKI) or
- user.reputation >= forum_settings.MIN_REP_TO_EDIT_OTHERS_POSTS or
- user.is_superuser)
+ if user.is_authenticated():
+ if user.id == post.author_id:
+ return True
+ if post.wiki:
+ if user.reputation >= forum_settings.MIN_REP_TO_EDIT_WIKI:
+ return True
+ if user.reputation >= forum_settings.MIN_REP_TO_EDIT_OTHERS_POSTS:
+ return True
+ if user.is_superuser:
+ return True
+ return False
def can_delete_comment(user, comment):
"""Determines if a User can delete the given Comment."""
@@ -98,23 +109,29 @@ def can_follow_url(user):
return user.reputation >= forum_settings.MIN_REP_TO_DISABLE_URL_NOFOLLOW
def can_accept_answer(user, question, answer):
- return (user.is_authenticated() and
- question.author != answer.author and
- question.author == user) or user.is_superuser
+ if user.is_superuser:
+ return True
+ if user.is_authenticated():
+ if question.author != answer.author and question.author == user:
+ return True
+ return False
# now only support to reopen own question except superuser
def can_reopen_question(user, question):
- return (user.is_authenticated() and
- user.id == question.author_id and
- user.reputation >= forum_settings.MIN_REP_TO_REOPEN_OWN_QUESTIONS) or user.is_superuser
+ if user.is_superuser:
+ return True
+ if user.is_authenticated() and user.id == question.author_id:
+ if user.reputation >= forum_settings.MIN_REP_TO_REOPEN_OWN_QUESTIONS:
+ return True
+ return False
def can_delete_post(user, post):
if user.is_superuser:
return True
elif user.is_authenticated() and user == post.author:
- if isinstance(post,Answer):
+ if isinstance(post, Answer):
return True
- elif isinstance(post,Question):
+ elif isinstance(post, Question):
answers = post.answers.all()
for answer in answers:
if user != answer.author and answer.deleted == False:
@@ -142,9 +159,12 @@ def can_view_user_edit(request_user, target_user):
return (request_user.is_authenticated() and request_user == target_user)
def can_upload_files(request_user):
- return (request_user.is_authenticated() and
- request_user.reputation >= forum_settings.MIN_REP_TO_UPLOAD_FILES) or \
- request_user.is_superuser
+ if request_user.is_superuser:
+ return True
+ if request_user.is_authenticated():
+ if request_user.reputation >= forum_settings.MIN_REP_TO_UPLOAD_FILES:
+ return True
+ return False
###########################################
## actions and reputation changes event
@@ -165,48 +185,64 @@ def onFlaggedItem(item, post, user, timestamp=None):
post.offensive_flag_count = post.offensive_flag_count + 1
post.save()
- post.author.reputation = calculate_reputation(post.author.reputation,
- forum_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE)
+ post.author.reputation = calculate_reputation(
+ post.author.reputation,
+ forum_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE
+ )
post.author.save()
question = post
if isinstance(post, Answer):
question = post.question
- reputation = Repute(user=post.author,
- negative=forum_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE,
- question=question, reputed_at=timestamp,
- reputation_type=-4,
- reputation=post.author.reputation)
+ reputation = Repute(
+ user=post.author,
+ negative=forum_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE,
+ question=question, reputed_at=timestamp,
+ reputation_type=-4,
+ reputation=post.author.reputation
+ )
reputation.save()
#todo: These should be updated to work on same revisions.
if post.offensive_flag_count == forum_settings.MIN_FLAGS_TO_HIDE_POST:
- post.author.reputation = calculate_reputation(post.author.reputation,
- forum_settings.REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION)
+ post.author.reputation = \
+ calculate_reputation(
+ post.author.reputation,
+ forum_settings.REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION
+ )
post.author.save()
- reputation = Repute(user=post.author,
- negative=forum_settings.REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION,
- question=question,
- reputed_at=timestamp,
- reputation_type=-6,
- reputation=post.author.reputation)
+ reputation = Repute(
+ user=post.author,
+ negative=\
+ forum_settings.REP_LOSS_FOR_RECEIVING_THREE_FLAGS_PER_REVISION,
+ question=question,
+ reputed_at=timestamp,
+ reputation_type=-6,
+ reputation=post.author.reputation
+ )
reputation.save()
elif post.offensive_flag_count == forum_settings.MIN_FLAGS_TO_DELETE_POST:
- post.author.reputation = calculate_reputation(post.author.reputation,
- forum_settings.REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION)
+ post.author.reputation = \
+ calculate_reputation(
+ post.author.reputation,
+ forum_settings.REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION
+ )
post.author.save()
- reputation = Repute(user=post.author,
- negative=forum_settings.REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION,
- question=question,
- reputed_at=timestamp,
- reputation_type=-7,
- reputation=post.author.reputation)
+ reputation = Repute(
+ user=post.author,
+ negative=\
+ forum_settings.REP_LOSS_FOR_RECEIVING_FIVE_FLAGS_PER_REVISION,
+ question=question,
+ reputed_at=timestamp,
+ reputation_type=-7,
+ reputation=post.author.reputation
+ )
reputation.save()
post.deleted = True
@@ -231,9 +267,9 @@ def onAnswerAccept(answer, user, timestamp=None):
answer.question.save()
answer.author.reputation = calculate_reputation(
- answer.author.reputation,
- forum_settings.REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE
- )
+ answer.author.reputation,
+ forum_settings.REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE
+ )
answer.author.save()
reputation = Repute(user=answer.author,
positive=forum_settings.REP_GAIN_FOR_RECEIVING_ANSWER_ACCEPTANCE,
@@ -264,15 +300,20 @@ def onAnswerAcceptCanceled(answer, user, timestamp=None):
answer.save()
answer.question.save()
- answer.author.reputation = calculate_reputation(answer.author.reputation,
- forum_settings.REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE)
+ answer.author.reputation = calculate_reputation(
+ answer.author.reputation,
+ forum_settings.REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE
+ )
answer.author.save()
- reputation = Repute(user=answer.author,
- negative=forum_settings.REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE,
- question=answer.question,
- reputed_at=timestamp,
- reputation_type=-2,
- reputation=answer.author.reputation)
+ reputation = Repute(
+ user=answer.author,
+ negative=\
+ forum_settings.REP_LOSS_FOR_RECEIVING_CANCELATION_OF_ANSWER_ACCEPTANCE,
+ question=answer.question,
+ reputed_at=timestamp,
+ reputation_type=-2,
+ reputation=answer.author.reputation
+ )
reputation.save()
user.reputation = calculate_reputation(user.reputation,
@@ -330,20 +371,25 @@ def onUpVotedCanceled(vote, post, user, timestamp=None):
if not post.wiki:
author = post.author
- author.reputation = calculate_reputation(author.reputation,
- forum_settings.REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION)
+ author.reputation = \
+ calculate_reputation(
+ author.reputation,
+ forum_settings.REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION
+ )
author.save()
question = post
if isinstance(post, Answer):
question = post.question
- reputation = Repute(user=author,
- negative=forum_settings.REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION,
- question=question,
- reputed_at=timestamp,
- reputation_type=-8,
- reputation=author.reputation)
+ reputation = Repute(
+ user=author,
+ negative=forum_settings.REP_LOSS_FOR_RECEIVING_UPVOTE_CANCELATION,
+ question=question,
+ reputed_at=timestamp,
+ reputation_type=-8,
+ reputation=author.reputation
+ )
reputation.save()
@transaction.commit_on_success
@@ -358,8 +404,10 @@ def onDownVoted(vote, post, user, timestamp=None):
if not post.wiki:
author = post.author
- author.reputation = calculate_reputation(author.reputation,
- forum_settings.REP_LOSS_FOR_DOWNVOTING)
+ author.reputation = calculate_reputation(
+ author.reputation,
+ forum_settings.REP_LOSS_FOR_DOWNVOTING
+ )
author.save()
question = post
@@ -374,8 +422,10 @@ def onDownVoted(vote, post, user, timestamp=None):
reputation=author.reputation)
reputation.save()
- user.reputation = calculate_reputation(user.reputation,
- forum_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE)
+ user.reputation = calculate_reputation(
+ user.reputation,
+ forum_settings.REP_LOSS_FOR_RECEIVING_DOWNVOTE
+ )
user.save()
reputation = Repute(user=user,
@@ -400,8 +450,10 @@ def onDownVotedCanceled(vote, post, user, timestamp=None):
if not post.wiki:
author = post.author
- author.reputation = calculate_reputation(author.reputation,
- forum_settings.REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION)
+ author.reputation = calculate_reputation(
+ author.reputation,
+ forum_settings.REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION
+ )
author.save()
question = post
@@ -409,11 +461,13 @@ def onDownVotedCanceled(vote, post, user, timestamp=None):
question = post.question
reputation = Repute(user=author,
- positive=forum_settings.REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION,
- question=question,
- reputed_at=timestamp,
- reputation_type=4,
- reputation=author.reputation)
+ positive=\
+ forum_settings.REP_GAIN_FOR_RECEIVING_DOWNVOTE_CANCELATION,
+ question=question,
+ reputed_at=timestamp,
+ reputation_type=4,
+ reputation=author.reputation
+ )
reputation.save()
user.reputation = calculate_reputation(user.reputation,
@@ -435,10 +489,13 @@ def onDeleteCanceled(post, user, timestamp=None):
post.deleted_at = None
post.save()
logging.debug('now restoring something')
- if isinstance(post,Answer):
- logging.debug('updated answer count on undelete, have %d' % post.question.answer_count)
+ if isinstance(post, Answer):
+ logging.debug(
+ 'updated answer count on undelete, have %d' \
+ % post.question.answer_count
+ )
Question.objects.update_answer_count(post.question)
- elif isinstance(post,Question):
+ elif isinstance(post, Question):
for tag in list(post.tags.all()):
if tag.used_count == 1 and tag.deleted:
tag.deleted = False
@@ -467,12 +524,16 @@ def onDeleted(post, user, timestamp=None):
answers = post.answers.all()
if user == post.author:
if len(answers) > 0:
- msg = _('Your question and all of it\'s answers have been deleted')
+ msg = _(
+ 'Your question and all of it\'s answers have been deleted'
+ )
else:
msg = _('Your question has been deleted')
else:
if len(answers) > 0:
- msg = _('The question and all of it\'s answers have been deleted')
+ msg = _(
+ 'The question and all of it\'s answers have been deleted'
+ )
else:
msg = _('The question has been deleted')
user.message_set.create(message=msg)
diff --git a/forum/conf/site_settings.py b/forum/conf/site_settings.py
index 19445bda..05d0c1c8 100644
--- a/forum/conf/site_settings.py
+++ b/forum/conf/site_settings.py
@@ -6,7 +6,6 @@ from forum.conf.settings_wrapper import settings
from livesettings import ConfigurationGroup, StringValue
from django.utils.translation import ugettext as _
from django.utils.html import escape
-from django.conf import settings as django_settings
from forum import const
QA_SITE_SETTINGS = ConfigurationGroup(
diff --git a/forum/conf/skin_general_settings.py b/forum/conf/skin_general_settings.py
index 166cd603..b1674d37 100644
--- a/forum/conf/skin_general_settings.py
+++ b/forum/conf/skin_general_settings.py
@@ -4,7 +4,6 @@ General skin settings
from forum.conf.settings_wrapper import settings
from livesettings import ConfigurationGroup, StringValue, IntegerValue
from django.utils.translation import ugettext as _
-from forum.skins import get_skin_choices
GENERAL_SKIN_SETTINGS = ConfigurationGroup(
'GENERAL_SKIN_SETTINGS',
@@ -16,7 +15,7 @@ settings.register(
GENERAL_SKIN_SETTINGS,
'ASKBOT_DEFAULT_SKIN',
default='default',
- choices=get_skin_choices(),
+ choices=[('default','default')],#todo: get_skin_choices(),
description=_('Select skin'),
)
)
diff --git a/forum/const/__init__.py b/forum/const/__init__.py
index fcba80d1..e83c5a12 100644
--- a/forum/const/__init__.py
+++ b/forum/const/__init__.py
@@ -55,7 +55,7 @@ POST_SCOPE_LIST = (
('favorite', _('favorite')),
)
DEFAULT_POST_SCOPE = 'all'
-PAGE_SIZE_CHOICES = (('10','10',),('30','30',),('50','50',),)
+PAGE_SIZE_CHOICES = (('10', '10',), ('30', '30',), ('50', '50',),)
#todo: remove this duplication
QUESTIONS_PER_PAGE_USER_CHOICES = (
(10, u'10'),
diff --git a/forum/const/message_keys.py b/forum/const/message_keys.py
index c52b9353..f7f8e8e3 100644
--- a/forum/const/message_keys.py
+++ b/forum/const/message_keys.py
@@ -9,7 +9,7 @@ _ = lambda v:v
#NOTE: all strings must be explicitly put into this dictionary,
#because you don't want to import _ from here with import *
-__all__ = ['GREETING_FOR_ANONYMOUS_USER',]
+__all__ = ['GREETING_FOR_ANONYMOUS_USER', ]
#this variable is shown in settings, because
#the url within is configurable, the default is reverse('faq')
diff --git a/forum/feed.py b/forum/feed.py
index 94065120..779049c7 100644
--- a/forum/feed.py
+++ b/forum/feed.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-#encoding:utf-8
+"""
#-------------------------------------------------------------------------------
# Name: Syndication feed class for subscription
# Purpose:
@@ -10,11 +9,16 @@
# Copyright: (c) CNPROG.COM 2009
# Licence: GPL V2
#-------------------------------------------------------------------------------
+"""
+#!/usr/bin/env python
+#encoding:utf-8
from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
from django.utils.translation import ugettext as _
-from models import Question
+from forum.models import Question
from forum.conf import settings as forum_settings
class RssLastestQuestionsFeed(Feed):
+ """rss feed class for the latest questions
+ """
title = forum_settings.APP_TITLE + _(' - ')+ _('latest questions')
link = forum_settings.APP_URL
description = forum_settings.APP_DESCRIPTION
@@ -22,21 +26,37 @@ class RssLastestQuestionsFeed(Feed):
copyright = forum_settings.APP_COPYRIGHT
def item_link(self, item):
+ """get full url to the item
+ """
return self.link + item.get_absolute_url()
def item_author_name(self, item):
+ """get name of author
+ """
return item.author.username
def item_author_link(self, item):
+ """get url of the author's profile
+ """
return item.author.get_profile_url()
def item_pubdate(self, item):
+ """get date of creation for the item
+ """
return item.added_at
def items(self, item):
- return Question.objects.filter(deleted=False).order_by('-last_activity_at')[:30]
+ """get questions for the feed
+ """
+ return Question.objects.filter(
+ deleted=False
+ ).order_by(
+ '-last_activity_at'
+ )[:30]
def main():
+ """main function for use as a script
+ """
pass
if __name__ == '__main__':
diff --git a/forum/forms.py b/forum/forms.py
index d5ca388b..38f8f2fd 100644
--- a/forum/forms.py
+++ b/forum/forms.py
@@ -1,16 +1,13 @@
import re
-from datetime import date
from django import forms
-from models import *
-from const import * #todo: clean out import * thing
+from forum import models
from forum import const
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
-from forum.utils.forms import NextUrlField, UserNameField, SetPasswordForm
+from forum.utils.forms import NextUrlField, UserNameField
from recaptcha_django import ReCaptchaField
-from django.conf import settings
from forum.conf import settings as forum_settings
import logging
@@ -19,7 +16,9 @@ class TitleField(forms.CharField):
def __init__(self, *args, **kwargs):
super(TitleField, self).__init__(*args, **kwargs)
self.required = True
- self.widget = forms.TextInput(attrs={'size' : 70, 'autocomplete' : 'off'})
+ self.widget = forms.TextInput(
+ attrs={'size' : 70, 'autocomplete' : 'off'}
+ )
self.max_length = 255
self.label = _('title')
self.help_text = _('please enter a descriptive title for your question')
@@ -98,7 +97,7 @@ class WikiField(forms.BooleanField):
self.required = False
self.label = _('community wiki')
self.help_text = _('if you choose community wiki option, the question and answer do not generate points and name of author will not be shown')
- def clean(self,value):
+ def clean(self, value):
return value and forum_settings.WIKI_ON
class EmailNotifyField(forms.BooleanField):
@@ -139,7 +138,7 @@ class AdvancedSearchForm(forms.Form):
reset_author = forms.BooleanField(required=False)
reset_query = forms.BooleanField(required=False)
start_over = forms.BooleanField(required=False)
- tags = forms.CharField(max_length=256,required=False)
+ tags = forms.CharField(max_length=256, required=False)
author = forms.IntegerField(required=False)
page_size = forms.ChoiceField(choices=const.PAGE_SIZE_CHOICES, required=False)
page = forms.IntegerField(required=False)
@@ -147,7 +146,7 @@ class AdvancedSearchForm(forms.Form):
def clean_tags(self):
if 'tags' in self.cleaned_data:
tags_input = self.cleaned_data['tags'].strip()
- split_re = re.compile(TAG_SPLIT_REGEX)
+ split_re = re.compile(const.TAG_SPLIT_REGEX)
tag_strings = split_re.split(tags_input)
tagname_re = re.compile(const.TAG_REGEX, re.UNICODE)
out = set()
@@ -232,7 +231,7 @@ class AnswerForm(forms.Form):
email_notify = EmailNotifyField()
def __init__(self, question, user, *args, **kwargs):
super(AnswerForm, self).__init__(*args, **kwargs)
- self.fields['email_notify'].widget.attrs['id'] = 'question-subscribe-updates';
+ self.fields['email_notify'].widget.attrs['id'] = 'question-subscribe-updates'
if question.wiki and forum_settings.WIKI_ON:
self.fields['wiki'].initial = True
if user.is_authenticated():
@@ -243,7 +242,7 @@ class AnswerForm(forms.Form):
class CloseForm(forms.Form):
- reason = forms.ChoiceField(choices=CLOSE_REASONS)
+ reason = forms.ChoiceField(choices=const.CLOSE_REASONS)
class RetagQuestionForm(forms.Form):
tags = TagNamesField()
@@ -327,7 +326,7 @@ class EditUserForm(forms.Form):
if forum_settings.EMAIL_UNIQUE == True:
if 'email' in self.cleaned_data:
try:
- user = User.objects.get(email = self.cleaned_data['email'])
+ User.objects.get(email = self.cleaned_data['email'])
except User.DoesNotExist:
return self.cleaned_data['email']
except User.MultipleObjectsReturned:
@@ -336,7 +335,7 @@ class EditUserForm(forms.Form):
return self.cleaned_data['email']
class TagFilterSelectionForm(forms.ModelForm):
- tag_filter_setting = forms.ChoiceField(choices=TAG_EMAIL_FILTER_CHOICES, #imported from forum/const.py
+ tag_filter_setting = forms.ChoiceField(choices=const.TAG_EMAIL_FILTER_CHOICES,
initial='ignored',
label=_('Choose email tag filter'),
widget=forms.RadioSelect)
@@ -393,10 +392,10 @@ class EditUserEmailFeedsForm(forms.Form):
label=_('Comments and posts mentioning me'),
)
- def set_initial_values(self,user=None):
- KEY_MAP = dict([(v,k) for k,v in self.FORM_TO_MODEL_MAP.iteritems()])
+ def set_initial_values(self, user=None):
+ KEY_MAP = dict([(v, k) for k, v in self.FORM_TO_MODEL_MAP.iteritems()])
if user != None:
- settings = EmailFeedSetting.objects.filter(subscriber=user)
+ settings = models.EmailFeedSetting.objects.filter(subscriber=user)
initial_values = {}
for setting in settings:
feed_type = setting.feed_type
@@ -422,8 +421,10 @@ class EditUserEmailFeedsForm(forms.Form):
"""
changed = False
for form_field, feed_type in self.FORM_TO_MODEL_MAP.items():
- s, created = EmailFeedSetting.objects.get_or_create(subscriber=user,\
- feed_type=feed_type)
+ s, created = models.EmailFeedSetting.objects.get_or_create(
+ subscriber=user,
+ feed_type=feed_type
+ )
if save_unbound:
#just save initial values instead
if form_field in self.initial:
@@ -440,7 +441,7 @@ class EditUserEmailFeedsForm(forms.Form):
if created:
s.save()
if form_field == 'individually_selected':
- feed_type = ContentType.objects.get_for_model(Question)
+ feed_type = ContentType.objects.get_for_model(models.Question)
user.followed_questions.clear()
return changed
@@ -455,11 +456,11 @@ class SimpleEmailSubscribeForm(forms.Form):
choices=SIMPLE_SUBSCRIBE_CHOICES
)
- def save(self,user=None):
+ def save(self, user=None):
EFF = EditUserEmailFeedsForm
if self.cleaned_data['subscribe'] == 'y':
email_settings_form = EFF()
logging.debug('%s wants to subscribe' % user.username)
else:
email_settings_form = EFF(initial=EFF.NO_EMAIL_INITIAL)
- email_settings_form.save(user,save_unbound=True)
+ email_settings_form.save(user, save_unbound=True)
diff --git a/forum/importers/stackexchange/management/commands/load_stackexchange.py b/forum/importers/stackexchange/management/commands/load_stackexchange.py
index 8e5b74a1..5145035e 100644
--- a/forum/importers/stackexchange/management/commands/load_stackexchange.py
+++ b/forum/importers/stackexchange/management/commands/load_stackexchange.py
@@ -11,7 +11,6 @@ import forum.models as askbot
import django_authopenid.models as askbot_openid
import forum.importers.stackexchange.models as se
from forum.forms import EditUserEmailFeedsForm
-from forum.utils.html import sanitize_html
from forum.conf import settings as forum_settings
from django.contrib.auth.models import Message as DjangoMessage
from django.utils.translation import ugettext as _
@@ -797,8 +796,4 @@ class Command(BaseCommand):
form.initial['answered_by_me'] = 'd'
#
form.save(user=u, save_unbound=True)
-
- if 'u_auth' in locals():
- u_auth.user = u
- u_auth.save()
USER[se_u.id] = u
diff --git a/forum/management/commands/base_command.py b/forum/management/commands/base_command.py
index c073bf7a..46a2d7a7 100644
--- a/forum/management/commands/base_command.py
+++ b/forum/management/commands/base_command.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-#encoding:utf-8
+"""
#-------------------------------------------------------------------------------
# Name: Award badges command
# Purpose: This is a command file croning in background process regularly to
@@ -11,15 +10,11 @@
# Copyright: (c) Mike 2009
# Licence: GPL V2
#-------------------------------------------------------------------------------
+"""
+#!/usr/bin/env python
+#encoding:utf-8
-from datetime import datetime, date
from django.core.management.base import NoArgsCommand
-from django.db import connection
-from django.shortcuts import get_object_or_404
-from django.contrib.contenttypes.models import ContentType
-
-from forum.models import *
-from forum.const import *
class BaseCommand(NoArgsCommand):
def update_activities_auditted(self, cursor, activity_ids):
@@ -28,8 +23,3 @@ class BaseCommand(NoArgsCommand):
query = "UPDATE activity SET is_auditted = 1 WHERE id in (%s)"\
% ','.join('%s' % item for item in activity_ids)
cursor.execute(query)
-
-
-
-
-
diff --git a/forum/management/commands/clean_award_badges.py b/forum/management/commands/clean_award_badges.py
index 117e3a5f..2aab8bda 100644
--- a/forum/management/commands/clean_award_badges.py
+++ b/forum/management/commands/clean_award_badges.py
@@ -1,3 +1,4 @@
+"""
#-------------------------------------------------------------------------------
# Name: Award badges command
# Purpose: This is a command file croning in background process regularly to
@@ -9,14 +10,13 @@
# Copyright: (c) Mike 2009
# Licence: GPL V2
#-------------------------------------------------------------------------------
+"""
#!/usr/bin/env python
#encoding:utf-8
from django.core.management.base import NoArgsCommand
from django.db import connection
-from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-
-from forum.models import *
+from forum import models
class Command(NoArgsCommand):
def handle_noargs(self, **options):
@@ -29,18 +29,18 @@ class Command(NoArgsCommand):
connection.close()
def clean_awards(self):
- Award.objects.all().delete()
+ models.Award.objects.all().delete()
- award_type =ContentType.objects.get_for_model(Award)
- Activity.objects.filter(content_type=award_type).delete()
+ award_type =ContentType.objects.get_for_model(models.Award)
+ models.Activity.objects.filter(content_type=award_type).delete()
- for user in User.objects.all():
+ for user in models.User.objects.all():
user.gold = 0
user.silver = 0
user.bronze = 0
user.save()
- for badge in Badge.objects.all():
+ for badge in models.Badge.objects.all():
badge.awarded_count = 0
badge.save()
@@ -56,4 +56,4 @@ def main():
pass
if __name__ == '__main__':
- main() \ No newline at end of file
+ main()
diff --git a/forum/management/commands/multi_award_badges.py b/forum/management/commands/multi_award_badges.py
index 8d8e0065..4361713e 100644
--- a/forum/management/commands/multi_award_badges.py
+++ b/forum/management/commands/multi_award_badges.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-#encoding:utf-8
+"""
#-------------------------------------------------------------------------------
# Name: Award badges command
# Purpose: This is a command file croning in background process regularly to
@@ -11,16 +10,17 @@
# Copyright: (c) Mike 2009
# Licence: GPL V2
#-------------------------------------------------------------------------------
+"""
+#!/usr/bin/env python
+#encoding:utf-8
-from datetime import datetime, date
-from django.core.management.base import NoArgsCommand
from django.db import connection
from django.shortcuts import get_object_or_404
from django.contrib.contenttypes.models import ContentType
-from forum.models import Badge, User, Award, Question, Answer
+from forum.models import Badge, User, Award, Question, Answer, Tag
from forum import const
-from base_command import BaseCommand
+from forum.management.commands.base_command BaseCommand
class Command(BaseCommand):
def handle_noargs(self, **options):
diff --git a/forum/management/commands/once_award_badges.py b/forum/management/commands/once_award_badges.py
index 1d403da5..ea04c11d 100644
--- a/forum/management/commands/once_award_badges.py
+++ b/forum/management/commands/once_award_badges.py
@@ -192,12 +192,12 @@ class Command(BaseCommand):
"""
For user asked question and got first upvote, we award him following badge:
"""
- query = "SELECT act.user_id, q.vote_up_count, act.object_id FROM "
- "activity act, question q WHERE act.activity_type = %s AND "
- "act.object_id = q.id AND "
- "act.user_id NOT IN "
- "(SELECT distinct user_id FROM award WHERE badge_id = %s)"\
- % (const.TYPE_ACTIVITY_ASK_QUESTION, 13)
+ query = ('SELECT act.user_id, q.vote_up_count, act.object_id FROM ' \
+ + 'activity act, question q WHERE act.activity_type = %s AND ' \
+ + 'act.object_id = q.id AND ' \
+ + 'act.user_id NOT IN ' \
+ + '(SELECT distinct user_id FROM award WHERE badge_id = %s)') \
+ % (const.TYPE_ACTIVITY_ASK_QUESTION, 13)
cursor = connection.cursor()
try:
cursor.execute(query)
@@ -224,12 +224,12 @@ class Command(BaseCommand):
(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 0, 0),
"""
- query = "SELECT act.user_id, a.vote_up_count, act.object_id FROM "
- "activity act, answer a WHERE act.activity_type = %s AND "
- "act.object_id = a.id AND "
- "act.user_id NOT IN "
- "(SELECT distinct user_id FROM award WHERE badge_id = %s)"\
- % (const.TYPE_ACTIVITY_ANSWER, 15)
+ query = ("SELECT act.user_id, a.vote_up_count, act.object_id FROM "\
+ + "activity act, answer a WHERE act.activity_type = %s AND "\
+ + "act.object_id = a.id AND "\
+ + "act.user_id NOT IN "\
+ + "(SELECT distinct user_id FROM award WHERE badge_id = %s)") \
+ % (const.TYPE_ACTIVITY_ANSWER, 15)
cursor = connection.cursor()
try:
cursor.execute(query)
@@ -254,13 +254,13 @@ class Command(BaseCommand):
"""
(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 0, 0)
"""
- query = "SELECT act.user_id, act.object_id FROM "
- "activity act, answer a WHERE act.object_id = a.id AND "
- "act.activity_type = %s AND "
- "a.vote_up_count >= 10 AND "
- "act.user_id NOT IN "
- "(SELECT user_id FROM award WHERE badge_id = %s)"\
- % (const.TYPE_ACTIVITY_ANSWER, 32)
+ query = ("SELECT act.user_id, act.object_id FROM " \
+ + "activity act, answer a WHERE act.object_id = a.id AND "\
+ + "act.activity_type = %s AND "\
+ + "a.vote_up_count >= 10 AND "\
+ + "act.user_id NOT IN "\
+ + "(SELECT user_id FROM award WHERE badge_id = %s)") \
+ % (const.TYPE_ACTIVITY_ANSWER, 32)
cursor = connection.cursor()
try:
cursor.execute(query)
@@ -284,16 +284,16 @@ class Command(BaseCommand):
"""
(26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0)
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE "
- "activity_type = %s OR "
- "activity_type = %s AND "
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "
- "GROUP BY user_id HAVING vote_count >= 300"\
- % (
- const.TYPE_ACTIVITY_VOTE_UP,
- const.TYPE_ACTIVITY_VOTE_DOWN,
- 2
- )
+ query = ("SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ + "activity_type = %s OR " \
+ + "activity_type = %s AND " \
+ + "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
+ + "GROUP BY user_id HAVING vote_count >= 300") \
+ % (
+ const.TYPE_ACTIVITY_VOTE_UP,
+ const.TYPE_ACTIVITY_VOTE_DOWN,
+ 2
+ )
self.__award_for_count_num(query, 26)
@@ -301,16 +301,16 @@ class Command(BaseCommand):
"""
(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 0, 0)
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE "
- "activity_type = %s OR "
- "activity_type = %s AND "
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "
- "GROUP BY user_id HAVING vote_count >= 100"\
- % (
- const.TYPE_ACTIVITY_UPDATE_QUESTION,
- const.TYPE_ACTIVITY_UPDATE_ANSWER,
- 27
- )
+ query = ("SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ + "activity_type = %s OR " \
+ + "activity_type = %s AND " \
+ + "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
+ + "GROUP BY user_id HAVING vote_count >= 100" )\
+ % (
+ const.TYPE_ACTIVITY_UPDATE_QUESTION,
+ const.TYPE_ACTIVITY_UPDATE_ANSWER,
+ 27
+ )
self.__award_for_count_num(query, 27)
@@ -318,16 +318,16 @@ class Command(BaseCommand):
"""
(5, '评论家', 3, '评论家', '评论10次以上', 0, 0),
"""
- query = "SELECT count(*) vote_count, user_id FROM activity WHERE "
- "activity_type = %s OR "
- "activity_type = %s AND "
- "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "
- "GROUP BY user_id HAVING vote_count >= 10"\
- % (
- const.TYPE_ACTIVITY_COMMENT_QUESTION,
- const.TYPE_ACTIVITY_COMMENT_ANSWER,
- 5
- )
+ query = ("SELECT count(*) vote_count, user_id FROM activity WHERE " \
+ + "activity_type = %s OR " \
+ + "activity_type = %s AND " \
+ + "user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) " \
+ + "GROUP BY user_id HAVING vote_count >= 10" )\
+ % (
+ const.TYPE_ACTIVITY_COMMENT_QUESTION,
+ const.TYPE_ACTIVITY_COMMENT_ANSWER,
+ 5
+ )
self.__award_for_count_num(query, 5)
def __award_for_count_num(self, query, badge):
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
index ccda1081..cd434a34 100644
--- a/forum/management/commands/send_email_alerts.py
+++ b/forum/management/commands/send_email_alerts.py
@@ -10,7 +10,6 @@ from django.utils.translation import ungettext
import datetime
from django.conf import settings
from forum.conf import settings as forum_settings
-import logging
from django.utils.datastructures import SortedDict
from django.contrib.contenttypes.models import ContentType
from forum import const
@@ -247,11 +246,11 @@ class Command(NoArgsCommand):
q_mentions_id = [q.id for q in mentions.get_all_origin_posts()]
- q_mentions_A = Q_set_A.filter(id__in, q_mentions_id)
+ q_mentions_A = Q_set_A.filter(id__in = q_mentions_id)
q_mentions_A.cutoff_time = cutoff_time
extend_question_list(q_mentions_A, q_list, add_mention=True)
- q_mentions_B = Q_set_B.filter(id__in, q_mentions_id)
+ q_mentions_B = Q_set_B.filter(id__in = q_mentions_id)
q_mentions_B.cutoff_time = cutoff_time
extend_question_list(q_mentions_B, q_list, add_mention=True)
@@ -301,7 +300,7 @@ class Command(NoArgsCommand):
content_object=q,
activity_type=EMAIL_UPDATE_ACTIVITY
)
- emailed_at = datetime.datetime(1970,1,1)#long time ago
+ emailed_at = datetime.datetime(1970, 1, 1)#long time ago
except Activity.MultipleObjectsReturned:
raise Exception(
'server error - multiple question email activities '
@@ -341,8 +340,10 @@ class Command(NoArgsCommand):
new_ans = new_ans.exclude(author=user)
meta_data['new_ans'] = len(new_ans)
- ans_rev = AnswerRevision.objects.filter(answer__question=q,\
- revised_at__gt=emailed_at)
+ ans_rev = AnswerRevision.objects.filter(
+ answer__question=q,
+ revised_at__gt=emailed_at
+ )
ans_rev = ans_rev.exclude(author=user)
meta_data['ans_rev'] = len(ans_rev)
@@ -458,6 +459,11 @@ class Command(NoArgsCommand):
msg.content_subtype = 'html'
msg.send()
else:
- msg2 = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, ['your@email.com'])
+ msg2 = EmailMessage(
+ subject,
+ text,
+ settings.DEFAULT_FROM_EMAIL,
+ ['your@email.com']
+ )
msg2.content_subtype = 'html'
msg2.send()
diff --git a/forum/management/commands/subscribe_everyone.py b/forum/management/commands/subscribe_everyone.py
index c79528f3..fac4168f 100644
--- a/forum/management/commands/subscribe_everyone.py
+++ b/forum/management/commands/subscribe_everyone.py
@@ -1,15 +1,10 @@
from django.core.management.base import NoArgsCommand
from django.db import connection
-from django.db.models import Q, F
-from forum.models import *
+from forum.models import EmailFeedSetting, User
from django.core.mail import EmailMessage
-from django.utils.translation import ugettext as _
-from django.utils.translation import ungettext
-import datetime
-from django.conf import settings
class Command(NoArgsCommand):
- def handle_noargs(self,**options):
+ def handle_noargs(self, **options):
try:
try:
self.subscribe_everyone()
@@ -24,9 +19,15 @@ class Command(NoArgsCommand):
for user in User.objects.all():
for feed_type in feed_type_info:
try:
- feed_setting = EmailFeedSetting.objects.get(subscriber=user,feed_type = feed_type[0])
+ feed_setting = EmailFeedSetting.objects.get(
+ subscriber=user,
+ feed_type = feed_type[0]
+ )
except EmailFeedSetting.DoesNotExist:
- feed_setting = EmailFeedSetting(subscriber=user,feed_type=feed_type[0])
+ feed_setting = EmailFeedSetting(
+ subscriber=user,
+ feed_type=feed_type[0]
+ )
feed_setting.frequency = 'w'
feed_setting.reported_at = None
feed_setting.save()
diff --git a/forum/middleware/anon_user.py b/forum/middleware/anon_user.py
index 51d35fa7..24eff0a2 100644
--- a/forum/middleware/anon_user.py
+++ b/forum/middleware/anon_user.py
@@ -1,17 +1,13 @@
-from django.http import HttpResponseRedirect
-from forum.utils.forms import get_next_url
from django.utils.translation import ugettext as _
from forum.user_messages import create_message, get_and_delete_messages
-from django.core.urlresolvers import reverse
from forum.conf import settings as forum_settings
from forum import const
-import logging
class AnonymousMessageManager(object):
- def __init__(self,request):
+ def __init__(self, request):
self.request = request
- def create(self,message=''):
- create_message(self.request,message)
+ def create(self, message=''):
+ create_message(self.request, message)
def get_and_delete(self):
messages = get_and_delete_messages(self.request)
return messages
@@ -25,12 +21,16 @@ def dummy_deepcopy(*arg):
class ConnectToSessionMessagesMiddleware(object):
def process_request(self, request):
if not request.user.is_authenticated():
- request.user.__deepcopy__ = dummy_deepcopy #plug on deepcopy which may be called by django db "driver"
- request.user.message_set = AnonymousMessageManager(request) #here request is linked to anon user
- request.user.get_and_delete_messages = request.user.message_set.get_and_delete
+ #plug on deepcopy which may be called by django db "driver"
+ request.user.__deepcopy__ = dummy_deepcopy
+ #here request is linked to anon user
+ request.user.message_set = AnonymousMessageManager(request)
+ request.user.get_and_delete_messages = \
+ request.user.message_set.get_and_delete
#also set the first greeting one time per session only
if 'greeting_set' not in request.session:
request.session['greeting_set'] = True
- msg = _(const.GREETING_FOR_ANONYMOUS_USER) % forum_settings.GREETING_URL
+ msg = _(const.GREETING_FOR_ANONYMOUS_USER) \
+ % forum_settings.GREETING_URL
request.user.message_set.create(message=msg)
diff --git a/forum/middleware/pagesize.py b/forum/middleware/pagesize.py
index 39b9d35b..154c112f 100644
--- a/forum/middleware/pagesize.py
+++ b/forum/middleware/pagesize.py
@@ -1,19 +1,23 @@
+import logging
+import traceback
+import sys
# used in questions
QUESTIONS_PAGE_SIZE = 10
class QuestionsPageSizeMiddleware(object):
def process_request(self, request):
- # Set flag to False by default. If it is equal to True, then need to be saved.
+ # Set flag to False by default. If it is True, then need to be saved.
page_size_changed = False
# get page_size from session, if failed then get default value
user_page_size = request.session.get("page_size", QUESTIONS_PAGE_SIZE)
# set page_size equal to logon user specified value in database
- if request.user.is_authenticated() and request.user.questions_per_page > 0:
+ if request.user.is_authenticated() \
+ and request.user.questions_per_page > 0:
user_page_size = request.user.questions_per_page
try:
# get new page_size from UI selection
page_size = int(request.GET.get('page_size', user_page_size))
- if page_size <> user_page_size:
+ if page_size != user_page_size:
page_size_changed = True
except ValueError:
@@ -28,9 +32,6 @@ class QuestionsPageSizeMiddleware(object):
# put page_size into session
request.session["page_size"] = page_size
- def process_exception(self,request,exception):
- import logging
- import traceback
- import sys
+ def process_exception(self, request, exception):
exc_type, exc_value, exc_traceback = sys.exc_info()
logging.debug(''.join(traceback.format_tb(exc_traceback)))
diff --git a/forum/middleware/view_log.py b/forum/middleware/view_log.py
index bf0b9fbb..f6112547 100644
--- a/forum/middleware/view_log.py
+++ b/forum/middleware/view_log.py
@@ -4,7 +4,7 @@ from forum.views.readers import questions as questions_view
from forum.views.commands import vote
from django.views.static import serve
from forum.views.writers import delete_comment, question_comments, answer_comments
-from forum.views.readers import question, question_revisions, answer_revisions
+from forum.views.readers import question_revisions, answer_revisions
#todo: the list is getting bigger and bigger - maybe there is a better way to
#trigger reset of sarch state?
@@ -19,8 +19,6 @@ class ViewLog(object):
def __init__(self):
self.views = []
self.depth = 3 #todo maybe move this to const.py
- def set_current(self, view_name):
- thi
def get_previous(self, num):
if num > self.depth - 1:
diff --git a/forum/models/__init__.py b/forum/models/__init__.py
index 3b4fd8c0..2df44bcc 100644
--- a/forum/models/__init__.py
+++ b/forum/models/__init__.py
@@ -1,11 +1,7 @@
-import signals
-from question import Question ,QuestionRevision, QuestionView, AnonymousQuestion, FavoriteQuestion
-from answer import Answer, AnonymousAnswer, AnswerRevision
-from tag import Tag, MarkedTag
-from meta import Vote, Comment, FlaggedItem
-from user import Activity, ValidationHash, EmailFeedSetting
-#from user import AuthKeyUserAssociation
-from repute import Badge, Award, Repute
+import logging
+import re
+import hashlib
+import datetime
from django.core.urlresolvers import reverse
from django.core.mail import EmailMessage
from forum.search.indexer import create_fulltext_indexes
@@ -17,15 +13,19 @@ from django.template.defaultfilters import slugify
from django.utils.safestring import mark_safe
from django.db import models
from django.conf import settings as django_settings
-from forum import const
-import logging
-import re
-import hashlib
-
-import datetime
from django.contrib.contenttypes.models import ContentType
-
-#todo: must go after signals
+from forum import const
+from forum.models.question import Question, QuestionRevision
+from forum.models.question import QuestionView, AnonymousQuestion
+from forum.models.question import FavoriteQuestion
+from forum.models.answer import Answer, AnonymousAnswer, AnswerRevision
+from forum.models.tag import Tag, MarkedTag
+from forum.models.meta import Vote, Comment, FlaggedItem
+from forum.models.user import Activity, ValidationHash, EmailFeedSetting
+from forum.models import signals
+#from user import AuthKeyUserAssociation
+from forum.models.repute import Badge, Award, Repute
+from forum.conf import settings as forum_settings
from forum import auth
User.add_to_class('is_approved', models.BooleanField(default=False))
@@ -186,7 +186,7 @@ def _process_vote(user, post, timestamp=None, cancel=False, vote_type=None):
if cancel:
auth.onDownVotedCanceled(vote, post, user, timestamp)
else:
- auth.onDonwVoted(vote, post, user, timestamp)
+ auth.onDownVoted(vote, post, user, timestamp)
def upvote(self, post, timestamp=None, cancel=False):
_process_vote(
@@ -210,14 +210,14 @@ def accept_answer(self, answer, timestamp=None, cancel=False):
else:
auth.onAnswerAccept(answer, self, timestamp=timestamp)
-def flag_post(self, post, timestamp=None, cancel=False):
+def flag_post(user, post, timestamp=None, cancel=False):
if cancel:#todo: can't unflag?
return
if post.flagged_items.filter(user=user).count() > 0:
return
else:
flag = FlaggedItem(
- user = self,
+ user = user,
content_object = post,
flagged_at = timestamp,
)
@@ -296,7 +296,7 @@ def send_instant_notifications_about_activity_in_post(
#get details about update
#todo: is there a way to solve this import issue?
- from forum.conf import settings as forum_settings
+ #from forum.conf import settings as forum_settings
base_url = forum_settings.APP_URL
data = {
'receiving_user': u,
@@ -313,7 +313,8 @@ def send_instant_notifications_about_activity_in_post(
}
#send update
subject = _('email update message subject')
- text = format_instant_notification_body(template, data)
+ text = format_instant_notification_body(
+ )
msg = EmailMessage(subject, text, django_settings.DEFAULT_FROM_EMAIL, [u.email])
print 'sending email to %s' % u.email
print 'subject: %s' % subject
@@ -337,29 +338,8 @@ def record_ask_event(instance, created, **kwargs):
)
activity.save()
-#todo: translate this
-record_answer_event_re = re.compile("You have received (a|\d+) .*new response.*")
def record_answer_event(instance, created, **kwargs):
if created:
- q_author = instance.question.author
- found_match = False
- for m in q_author.message_set.all():
- match = record_answer_event_re.search(m.message)
- if match:
- found_match = True
- try:
- cnt = int(match.group(1))
- except:
- cnt = 1
- m.message = u"You have received %d <a href=\"%s?sort=responses\">new responses</a>."\
- % (cnt+1, q_author.get_profile_url())
- m.save()
- break
- if not found_match:
- msg = u"You have received a <a href=\"%s?sort=responses\">new response</a>."\
- % q_author.get_profile_url()
- q_author.message_set.create(message=msg)
-
activity = Activity(
user = instance.author,
active_at = instance.added_at,
@@ -376,15 +356,26 @@ def record_answer_event(instance, created, **kwargs):
#todo: change to more general post_update_activity
-def record_post_update_activity(post, newly_mentioned_users, **kwargs):
+def record_post_update_activity(
+ post,
+ newly_mentioned_users = list(),
+ timestamp = None,
+ created = False,
+ **kwargs
+ ):
+ """called upon signal forum.models.signals.post_updated
+ which is sent at the end of save() method in posts
+ """
#todo: take into account created == True case
- activity_type = post.get_updated_activity_type()
+ activity_type = post.get_updated_activity_type(created)
+
+ assert(timestamp != None)
#fields will depend on post type and maybe activity type
#post has to be saved already, b/c Activity is in generic relation to post
activity = Activity(
user = post.get_last_author(),
- active_at = post.added_at,
+ active_at = timestamp,
content_object = post,
activity_type = activity_type
)
@@ -420,8 +411,6 @@ def record_revision_question_event(instance, created, **kwargs):
instance.question.get_author_list(include_comments = True)
)
- receiving_users.update(
- )
for a in instance.question.answers.all():
receiving_users.update(a.get_author_list())
@@ -562,6 +551,8 @@ def record_cancel_vote(instance, **kwargs):
#todo: same problem - cannot access receiving user here
activity.save()
+#todo: weird that there is no record delete answer or comment
+#is this even necessary to keep track of?
def record_delete_question(instance, delete_by, **kwargs):
"""
when user deleted the question
@@ -634,7 +625,7 @@ def record_user_full_updated(instance, **kwargs):
def post_stored_anonymous_content(sender,user,session_key,signal,*args,**kwargs):
aq_list = AnonymousQuestion.objects.filter(session_key = session_key)
aa_list = AnonymousAnswer.objects.filter(session_key = session_key)
- from forum.conf import settings as forum_settings
+ #from forum.conf import settings as forum_settings
if forum_settings.EMAIL_VALIDATION == True:#add user to the record
for aq in aq_list:
aq.author = user
@@ -652,7 +643,6 @@ def post_stored_anonymous_content(sender,user,session_key,signal,*args,**kwargs)
#signal for User model save changes
django_signals.pre_save.connect(calculate_gravatar_hash, sender=User)
django_signals.post_save.connect(record_ask_event, sender=Question)
-django_signals.post_save.connect(record_answer_event, sender=Answer)
django_signals.post_save.connect(record_revision_question_event, sender=QuestionRevision)
django_signals.post_save.connect(record_revision_answer_event, sender=AnswerRevision)
django_signals.post_save.connect(record_award_event, sender=Award)
@@ -675,6 +665,10 @@ signals.post_updated.connect(
record_post_update_activity,
sender=Comment
)
+signals.post_updated.connect(
+ record_post_update_activity,
+ sender=Answer
+ )
#post_syncdb.connect(create_fulltext_indexes)
#todo: wtf??? what is x=x about?
diff --git a/forum/models/answer.py b/forum/models/answer.py
index 3f52b4ab..4b35fd31 100644
--- a/forum/models/answer.py
+++ b/forum/models/answer.py
@@ -1,18 +1,15 @@
-from base import AnonymousContent, ContentRevision, DeletableContent
-from content import Content
-#todo: take care of copy-paste markdowner stuff maybe make html automatic field?
-from forum import const
-from markdown2 import Markdown
-from django.utils.html import strip_tags
-from forum.utils.html import sanitize_html
+import datetime
from django.db import models
from django.utils.http import urlquote as django_urlquote
from django.template.defaultfilters import slugify
from django.core.urlresolvers import reverse
-import datetime
-markdowner = Markdown(html4tags=True)
+from forum.models.base import AnonymousContent, DeletableContent
+from forum.models.base import ContentRevision
+from forum.models.base import save_post, parse_post_text
+from forum.models import content
+from forum.models.question import Question
+from forum import const
-from question import Question
class AnswerManager(models.Manager):
def create_new(self, question=None, author=None, added_at=None, wiki=False, text='', email_notify=False):
@@ -22,7 +19,7 @@ class AnswerManager(models.Manager):
added_at = added_at,
wiki = wiki,
text = text,
- html = sanitize_html(markdowner.convert(text)),
+ #.html field is denormalized by the save() call
)
if answer.wiki:
answer.last_edited_by = answer.author
@@ -84,16 +81,19 @@ class AnswerManager(models.Manager):
# cursor.execute(self.GET_ANSWERS_FROM_USER_QUESTIONS, [user_id, user_id])
# return cursor.fetchall()
-class Answer(Content, DeletableContent):
+class Answer(content.Content, DeletableContent):
question = models.ForeignKey('Question', related_name='answers')
accepted = models.BooleanField(default=False)
accepted_at = models.DateTimeField(null=True, blank=True)
objects = AnswerManager()
- class Meta(Content.Meta):
+ class Meta(content.Content.Meta):
db_table = u'answer'
+ save = save_post
+ parse = parse_post_text
+
def apply_edit(self, edited_at=None, edited_by=None, text=None, comment=None, wiki=False):
if text is None:
@@ -105,7 +105,7 @@ class Answer(Content, DeletableContent):
self.last_edited_at = edited_at
self.last_edited_by = edited_by
- self.html = sanitize_html(markdowner.convert(text))
+ #self.html is denormalized in save()
self.text = text
#todo: bug wiki has no effect here
self.save()
diff --git a/forum/models/base.py b/forum/models/base.py
index 110c0deb..1b3a4c2a 100644
--- a/forum/models/base.py
+++ b/forum/models/base.py
@@ -1,99 +1,143 @@
import datetime
-import hashlib
-from urllib import quote_plus, urlencode
from django.db import models
-from django.utils.http import urlquote as django_urlquote
from django.utils.html import strip_tags
-from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
-from django.utils.translation import ugettext as _
from django.contrib.sitemaps import ping_google
-import django.dispatch
-from django.conf import settings
+#todo: maybe merge forum.utils.markup and forum.utils.html
from forum.utils import markup
+from forum.utils.html import sanitize_html
from django.utils import html
import logging
+from markdown2 import Markdown
+
+markdowner = Markdown(html4tags=True)
#todo: following methods belong to a future common post class
-def render_post_text_and_get_newly_mentioned_users(post,
- urlize_content = False):
+def parse_post_text(post):
+ """typically post has a field to store raw source text
+ in comment it is called .comment, in Question and Answer it is
+ called .text
+ also there is another field called .html (consistent across models)
+ so the goal of this function is to render raw text into .html
+ and extract any metadata given stored in source (currently
+ this metadata is limited by twitter style @mentions
+ but there may be more in the future
+
+ so really it should be renamed into ..._and_get_meta_data
+ """
text = post.get_text()
- if urlize_content:
+ if post._urlize:
text = html.urlize(text)
- if '@' not in text:
- post.html = text
- return list()
-
- from forum.models.user import Activity
-
- mentioned_by = post.get_last_author()
-
- op = post.get_origin_post()
- anticipated_authors = op.get_author_list( include_comments = True, recursive = True )
-
- extra_name_seeds = markup.extract_mentioned_name_seeds(text)
-
- extra_authors = set()
- for name_seed in extra_name_seeds:
- extra_authors.update(User.objects.filter(username__startswith = name_seed))
+ if post._use_markdown:
+ text = sanitize_html(markdowner.convert(text))
- #it is important to preserve order here so that authors of post get mentioned first
- anticipated_authors += list(extra_authors)
+ #todo, add markdown parser call conditional on
+ #post.use_markdown flag
+ post_html = text
+ mentioned_authors = list()
+ removed_mentions = list()
+ if '@' in text:
+ from forum.models.user import Activity
- mentioned_authors, post.html = markup.mentionize_text(text, anticipated_authors)
+ mentioned_by = post.get_last_author()
- #maybe delete some previous mentions
- if post.id != None:
- #only look for previous mentions if post was already saved before
- prev_mention_qs = Activity.objects.get_mentions(
- mentioned_in = post
+ op = post.get_origin_post()
+ anticipated_authors = op.get_author_list(
+ include_comments = True,
+ recursive = True
)
- new_set = set(mentioned_authors)
- for mention in prev_mention_qs:
- delta_set = set(mention.receiving_users.all()) - new_set
- if not delta_set:
- mention.delete()
- new_set -= delta_set
- mentioned_authors = list(new_set)
+ extra_name_seeds = markup.extract_mentioned_name_seeds(text)
- return mentioned_authors
+ extra_authors = set()
+ for name_seed in extra_name_seeds:
+ extra_authors.update(User.objects.filter(
+ username__startswith = name_seed
+ )
+ )
-def save_content(self, urlize_content = False, **kwargs):
+ #it is important to preserve order here so that authors of post
+ #get mentioned first
+ anticipated_authors += list(extra_authors)
+
+ mentioned_authors, post_html = markup.mentionize_text(
+ text,
+ anticipated_authors
+ )
+
+ #find mentions that were removed and identify any previously
+ #entered mentions so that we can send alerts on only new ones
+ if post.pk is not None:
+ #only look for previous mentions if post was already saved before
+ prev_mention_qs = Activity.objects.get_mentions(
+ mentioned_in = post
+ )
+ new_set = set(mentioned_authors)
+ for prev_mention in prev_mention_qs:
+
+ user = prev_mention.get_mentioned_user()
+ if user in new_set:
+ #don't report mention twice
+ new_set.remove(user)
+ else:
+ removed_mentions.append(prev_mention)
+ mentioned_authors = list(new_set)
+
+ data = {
+ 'html': post_html,
+ 'newly_mentioned_users': mentioned_authors,
+ 'removed_mentions': removed_mentions,
+ }
+ return data
+
+def save_post(post, **kwargs):
"""generic save method to use with posts
"""
- new_mentions = self._render_text_and_get_newly_mentioned_users(
- urlize_content
- )
+ data = post.parse()
- from forum.models.user import Activity
+ post.html = data['html']
+ newly_mentioned_users = data['newly_mentioned_users']
+ removed_mentions = data['removed_mentions']
- #this save must precede saving the mention activity
- super(self.__class__, self).save(**kwargs)
+ #a hack allowing to save denormalized .summary field for questions
+ if hasattr(post, 'summary'):
+ post.summary = strip_tags(post.html)[:120]
+
+ #delete removed mentions
+ for rm in removed_mentions:
+ rm.delete()
- post_author = self.get_last_author()
+ created = post.pk is None
- for u in new_mentions:
+ #this save must precede saving the mention activity
+ #because generic relation needs primary key of the related object
+ super(post.__class__, post).save(**kwargs)
+ last_author = post.get_last_author()
+
+ #create new mentions
+ for u in newly_mentioned_users:
+ from forum.models.user import Activity
Activity.objects.create_new_mention(
mentioned_whom = u,
- mentioned_in = self,
- mentioned_by = post_author
+ mentioned_in = post,
+ mentioned_by = last_author
)
-
#todo: this is handled in signal because models for posts
#are too spread out
from forum.models import signals
signals.post_updated.send(
- post = self,
- newly_mentioned_users = new_mentions,
- sender = self.__class__
+ post = post,
+ newly_mentioned_users = newly_mentioned_users,
+ timestamp = post.get_time_of_last_edit(),
+ created = created,
+ sender = post.__class__
)
try:
diff --git a/forum/models/content.py b/forum/models/content.py
index 95064692..5f144f1e 100644
--- a/forum/models/content.py
+++ b/forum/models/content.py
@@ -1,9 +1,10 @@
+import datetime
+import logging
from django.contrib.auth.models import User
from django.contrib.contenttypes import generic
+from django.contrib.sitemaps import ping_google
from django.db import models
-from meta import Comment, Vote, FlaggedItem
-import datetime
-import logging
+from forum.models.meta import Comment, Vote, FlaggedItem
class Content(models.Model):
"""
@@ -35,6 +36,9 @@ class Content(models.Model):
votes = generic.GenericRelation(Vote)
flagged_items = generic.GenericRelation(FlaggedItem)
+ _use_markdown = True
+ _urlize = False
+
class Meta:
abstract = True
app_label = 'forum'
@@ -80,6 +84,12 @@ class Content(models.Model):
def get_last_author(self):
return self.last_edited_by
+ def get_time_of_last_edit(self):
+ if self.last_edited_at:
+ return self.last_edited_at
+ else:
+ return self.added_at
+
def get_author_list(self, include_comments = False, recursive = False, exclude_list = None):
authors = set()
authors.update([r.author for r in self.revisions.all()])
@@ -108,7 +118,11 @@ class Content(models.Model):
return True
else:
- raise Exception('unexpected User.tag_filter_setting %' % self.tag_filter_setting)
+ raise ValueError(
+ 'unexpected User.tag_filter_setting %s' \
+ % self.tag_filter_setting
+ )
+
def post_get_last_update_info(self):#todo: rename this subroutine
when = self.added_at
who = self.author
diff --git a/forum/models/meta.py b/forum/models/meta.py
index d0530694..5f36d76e 100644
--- a/forum/models/meta.py
+++ b/forum/models/meta.py
@@ -1,9 +1,7 @@
+import datetime
from django.db import models
-from base import MetaContent, UserContent
-from base import render_post_text_and_get_newly_mentioned_users
-from base import save_content
from forum import const
-import datetime
+from forum.models import base
class VoteManager(models.Manager):
def get_up_vote_count_from_user(self, user):
@@ -26,7 +24,7 @@ class VoteManager(models.Manager):
return 0
-class Vote(MetaContent, UserContent):
+class Vote(base.MetaContent, base.UserContent):
VOTE_UP = +1
VOTE_DOWN = -1
VOTE_CHOICES = (
@@ -39,7 +37,7 @@ class Vote(MetaContent, UserContent):
objects = VoteManager()
- class Meta(MetaContent.Meta):
+ class Meta(base.MetaContent.Meta):
unique_together = ('content_type', 'object_id', 'user')
db_table = u'vote'
@@ -65,25 +63,28 @@ class FlaggedItemManager(models.Manager):
else:
return 0
-class FlaggedItem(MetaContent, UserContent):
+class FlaggedItem(base.MetaContent, base.UserContent):
"""A flag on a Question or Answer indicating offensive content."""
flagged_at = models.DateTimeField(default=datetime.datetime.now)
objects = FlaggedItemManager()
- class Meta(MetaContent.Meta):
+ class Meta(base.MetaContent.Meta):
unique_together = ('content_type', 'object_id', 'user')
db_table = u'flagged_item'
def __unicode__(self):
return '[%s] flagged at %s' %(self.user, self.flagged_at)
-class Comment(MetaContent, UserContent):
+class Comment(base.MetaContent, base.UserContent):
comment = models.CharField(max_length = const.COMMENT_HARD_MAX_LENGTH)
added_at = models.DateTimeField(default = datetime.datetime.now)
html = models.CharField(max_length = const.COMMENT_HARD_MAX_LENGTH, default='')
- class Meta(MetaContent.Meta):
+ _urlize = True
+ _use_markdown = False
+
+ class Meta(base.MetaContent.Meta):
ordering = ('-added_at',)
db_table = u'comment'
@@ -97,15 +98,13 @@ class Comment(MetaContent, UserContent):
def set_text(self, text):
self.comment = text
- _render_text_and_get_newly_mentioned_users = \
- render_post_text_and_get_newly_mentioned_users
-
- _save = save_content
+ def parse(self):
+ return base.parse_post_text(self)
def save(self,**kwargs):
- self._save(urlize_content = True)
+ base.save_post(self)
- def get_updated_activity_type(self):
+ def get_updated_activity_type(self, created = False):
if self.content_object.__class__.__name__ == 'Question':
return const.TYPE_ACTIVITY_COMMENT_QUESTION
elif self.content_object.__class__.__name__ == 'Answer':
@@ -123,6 +122,9 @@ class Comment(MetaContent, UserContent):
users -= set([self.user])#remove activity user
return list(users)
+ def get_time_of_last_edit(self):
+ return self.added_at
+
def delete(self, **kwargs):
#todo: not very good import in models of other models
#todo: potentially a circular import
diff --git a/forum/models/question.py b/forum/models/question.py
index 6a36e0aa..0d63426d 100644
--- a/forum/models/question.py
+++ b/forum/models/question.py
@@ -1,23 +1,20 @@
-from base import DeletableContent, AnonymousContent, ContentRevision
-from content import Content
-from forum.models import signals
-from tag import Tag
-from forum import const
-from forum.utils.html import sanitize_html
-from markdown2 import Markdown
-from django.utils.html import strip_tags
+import logging
import datetime
from django.conf import settings
from django.utils.datastructures import SortedDict
-from forum.models.tag import MarkedTag
from django.db import models
from django.contrib.auth.models import User
-from django.utils.http import urlquote as django_urlquote
+from django.utils.http import urlquote as django_urlquote
from django.template.defaultfilters import slugify
from django.core.urlresolvers import reverse
-
-markdowner = Markdown(html4tags=True)
-
+from django.contrib.sitemaps import ping_google
+from django.utils.translation import ugettext as _
+from forum.models.tag import Tag, MarkedTag
+from forum.models import signals
+from forum.models.base import AnonymousContent, DeletableContent, ContentRevision
+from forum.models.base import save_post, parse_post_text
+from forum.models import content
+from forum import const
from forum.utils.lists import LazyList
#todo: too bad keys are duplicated see const sort methods
@@ -35,8 +32,7 @@ QUESTION_ORDER_BY_MAP = {
class QuestionManager(models.Manager):
def create_new(self, title=None,author=None,added_at=None, wiki=False,tagnames=None, text=None):
- html = sanitize_html(markdowner.convert(text))
- summary = strip_tags(html)[:120]
+
question = Question(
title = title,
author = author,
@@ -45,11 +41,15 @@ class QuestionManager(models.Manager):
last_activity_by = author,
wiki = wiki,
tagnames = tagnames,
- html = html,
+ #html field is denormalized in .save() call
text = text,
- summary = summary
+ #summary field is denormalized in .save() call
)
if question.wiki:
+ #todo: this is confusing - last_edited_at field
+ #is used as an indicator whether question has been edited
+ #in template forum/skins/default/templates/post_contributor_info.html
+ #but in principle, post creation should count as edit as well
question.last_edited_by = question.author
question.last_edited_at = added_at
question.wikified_at = added_at
@@ -233,7 +233,7 @@ class QuestionManager(models.Manager):
return False
- #todo: why not make this into a method of class Question?
+ #todo: why not make this into a method of Question class?
# also it is actually strange - why do we need the answer_count
# field if the count depends on who is requesting this?
def update_answer_count(self, question):
@@ -244,7 +244,7 @@ class QuestionManager(models.Manager):
# for some reasons, this Answer class failed to be imported,
# although we have imported all classes from models on top.
- from answer import Answer
+ from forum.models.answer import Answer
self.filter(id=question.id).update(
answer_count=Answer.objects.get_answers_from_question(question).filter(deleted=False).count())
@@ -285,7 +285,7 @@ class QuestionManager(models.Manager):
return LazyList(get_data)
-class Question(Content, DeletableContent):
+class Question(content.Content, DeletableContent):
title = models.CharField(max_length=300)
tags = models.ManyToManyField('Tag', related_name='questions')
answer_accepted = models.BooleanField(default=False)
@@ -312,9 +312,11 @@ class Question(Content, DeletableContent):
objects = QuestionManager()
- class Meta(Content.Meta):
+ class Meta(content.Content.Meta):
db_table = u'question'
+ parse = parse_post_text
+
def delete(self):
super(Question, self).delete()
try:
@@ -335,8 +337,8 @@ class Question(Content, DeletableContent):
# Update the Question's tag associations
signals.tags_updated = self.objects.update_tags(
self,
- form.cleaned_data['tags'],
- request.user
+ tagnames,
+ retagged_by
)
# Create a new revision
@@ -351,7 +353,7 @@ class Question(Content, DeletableContent):
text = latest_revision.text
)
# send tags updated singal
- signals.tags_updated.send(sender=question.__class__, question=self)
+ signals.tags_updated.send(sender=Question, question=self)
def get_origin_post(self):
return self
@@ -374,10 +376,6 @@ class Question(Content, DeletableContent):
if edited_at is None:
edited_at = datetime.datetime.now()
- #todo: have this copy-paste in few places
- html = sanitize_html(markdowner.convert(text))
- question_summary = strip_tags(html)[:120]
-
# Update the Question itself
self.title = title
self.last_edited_at = edited_at
@@ -385,8 +383,6 @@ class Question(Content, DeletableContent):
self.last_edited_by = edited_by
self.last_activity_by = edited_by
self.tagnames = tags
- self.summary = question_summary
- self.html = html
self.text = text
#wiki is an eternal trap whence there is no exit
@@ -436,13 +432,15 @@ class Question(Content, DeletableContent):
This is required as we're using ``tagnames`` as the sole means of
adding and editing tags.
"""
- initial_addition = (self.id is None)
-
- super(Question, self).save(**kwargs)
+ initial_addition = (self.pk is None)
+
+ save_post(self, **kwargs)
if initial_addition:
- tags = Tag.objects.get_or_create_multiple(self.tagname_list(),
- self.author)
+ tags = Tag.objects.get_or_create_multiple(
+ self.tagname_list(),
+ self.author
+ )
self.tags.add(*tags)
Tag.objects.update_use_counts(tags)
@@ -454,7 +452,10 @@ class Question(Content, DeletableContent):
return u','.join([unicode(tag) for tag in self.tagname_list()])
def get_absolute_url(self):
- return '%s%s' % (reverse('question', args=[self.id]), django_urlquote(slugify(self.title)))
+ return '%s%s' % (
+ reverse('question', args=[self.id]),
+ django_urlquote(slugify(self.title))
+ )
def has_favorite_by_user(self, user):
if not user.is_authenticated():
@@ -463,7 +464,7 @@ class Question(Content, DeletableContent):
return FavoriteQuestion.objects.filter(question=self, user=user).count() > 0
def get_answer_count_by_user(self, user_id):
- from answer import Answer
+ from forum.models.answer import Answer
query_set = Answer.objects.filter(author__id=user_id)
return query_set.filter(question=self).count()
@@ -523,6 +524,7 @@ class Question(Content, DeletableContent):
answer_comments.append(comment)
#create the report
+ from forum.conf import settings as forum_settings
if edited or new_answers or modified_answers or answer_comments:
out = []
if edited:
@@ -618,5 +620,3 @@ class AnonymousQuestion(AnonymousContent):
text=self.text,
)
self.delete()
-
-from answer import Answer, AnswerManager
diff --git a/forum/models/tag.py b/forum/models/tag.py
index 0e585547..89f706f5 100644
--- a/forum/models/tag.py
+++ b/forum/models/tag.py
@@ -1,9 +1,9 @@
-from base import DeletableContent
from django.db import models
from django.db import connection, transaction
from django.contrib.auth.models import User
-
from django.utils.translation import ugettext as _
+from forum.models.base import DeletableContent
+
class TagManager(models.Manager):
UPDATE_USED_COUNTS_QUERY = (
diff --git a/forum/models/user.py b/forum/models/user.py
index c05d911b..083aca79 100644
--- a/forum/models/user.py
+++ b/forum/models/user.py
@@ -1,18 +1,17 @@
-#todo: remove this with Django 1.2
+from hashlib import md5
+import string
+from random import Random
+import datetime
+import logging
from django.db import models
+from django.db.backends.dummy.base import IntegrityError
from django.contrib.contenttypes.models import ContentType
-from forum.models import signals
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
-from hashlib import md5
-import string
-from random import Random
+from django.utils.translation import ugettext as _
from forum import const
from forum.utils import functions
-import datetime
-import logging
-from django.utils.translation import ugettext as _
class ActivityManager(models.Manager):
def get_all_origin_posts(self):
@@ -80,8 +79,12 @@ class ActivityManager(models.Manager):
mentioned_whom = None,
mentioned_at = None,
mentioned_in = None,
- reported = None
+ reported = None,
+ mentioned_at__gt = None,
):
+ """extract mention-type activity objects
+ todo: implement better rich field lookups
+ """
kwargs = dict()
@@ -90,6 +93,8 @@ class ActivityManager(models.Manager):
if mentioned_at:
#todo: handle cases with rich lookups here like __lt
kwargs['active_at'] = mentioned_at
+ elif mentioned_at__gt:
+ kwargs['active_at__gt'] = mentioned_at__gt
if mentioned_by:
kwargs['user'] = mentioned_by
@@ -139,6 +144,12 @@ class Activity(models.Model):
app_label = 'forum'
db_table = u'activity'
+ def get_mentioned_user(self):
+ assert(self.activity_type == const.TYPE_ACTIVITY_MENTION)
+ user_qs = self.receiving_users.all()
+ assert(len(user_qs) == 1)
+ return user_qs[0]
+
class EmailFeedSettingManager(models.Manager):
def exists_match_to_post_and_subscriber(
diff --git a/forum/search/state_manager.py b/forum/search/state_manager.py
index 86cc5662..fda4bcb9 100644
--- a/forum/search/state_manager.py
+++ b/forum/search/state_manager.py
@@ -20,7 +20,7 @@ def some_in(what, where):
class SearchState(object):
def __init__(self):
- self.scope= const.DEFAULT_POST_SCOPE
+ self.scope = const.DEFAULT_POST_SCOPE
self.query = None
self.tags = None
self.author = None
@@ -64,76 +64,76 @@ class SearchState(object):
setattr(self, key, new_value)
self.reset_page()
- def relax_stickiness(self, input, view_log):
+ def relax_stickiness(self, input_dict, view_log):
if view_log.get_previous(1) == 'questions':
- if not some_in(ACTIVE_COMMANDS, input):
+ if not some_in(ACTIVE_COMMANDS, input_dict):
self.reset()
#todo also relax if 'all' scope was clicked twice
- def update_from_user_input(self,input,raw_input = {}):
+ def update_from_user_input(self, input_dict, unprocessed_input = {}):
#todo: this function will probably not
#fit the case of multiple parameters entered at the same tiem
- if 'start_over' in input:
+ if 'start_over' in input_dict:
self.reset()
- if 'page' in input:
- self.page = input['page']
+ if 'page' in input_dict:
+ self.page = input_dict['page']
#special case - on page flip no other input is accepted
return
- if 'page_size' in input:
- self.update_value('page_size',input)
+ if 'page_size' in input_dict:
+ self.update_value('page_size', input_dict)
self.reset_page()#todo may be smarter here - start with ~same q
#same as with page - return right away
return
- if 'scope' in input:
- if input['scope'] == 'favorite' and self.logged_in == False:
+ if 'scope' in input_dict:
+ if input_dict['scope'] == 'favorite' and self.logged_in == False:
self.reset_scope()
else:
- self.update_value('scope',input)
+ self.update_value('scope', input_dict)
- if 'tags' in input:
+ if 'tags' in input_dict:
if self.tags:
old_tags = self.tags.copy()
- self.tags = self.tags.union(input['tags'])
+ self.tags = self.tags.union(input_dict['tags'])
if self.tags != old_tags:
self.reset_page()
else:
- self.tags = input['tags']
+ self.tags = input_dict['tags']
#all resets just return
- if 'reset_tags' in input:
+ if 'reset_tags' in input_dict:
if self.tags:
self.tags = None
self.reset_page()
return
#todo: handle case of deleting tags one-by-one
- if 'reset_author' in input:
+ if 'reset_author' in input_dict:
if self.author:
self.author = None
self.reset_page()
return
- if 'reset_query' in input:
+ if 'reset_query' in input_dict:
self.reset_query()
return
- self.update_value('author',input)
+ self.update_value('author', input_dict)
- if 'query' in input:
- self.update_value('query',input)
+ if 'query' in input_dict:
+ self.update_value('query', input_dict)
self.sort = 'relevant'
- elif 'search' in raw_input:#a case of use nulling search query by hand
+ elif 'search' in unprocessed_input:#a case of use nulling search query by hand
self.reset_query()
return
- if 'sort' in input:
- if input['sort'] == 'relevant' and self.query is None:
+ if 'sort' in input_dict:
+ if input_dict['sort'] == 'relevant' and self.query is None:
self.reset_sort()
else:
- self.update_value('sort',input)
+ self.update_value('sort', input_dict)
#todo: plug - mysql has no relevance sort
if self.sort == 'relevant':
diff --git a/forum/skins/__init__.py b/forum/skins/__init__.py
index 8e5265e8..b7b222a2 100644
--- a/forum/skins/__init__.py
+++ b/forum/skins/__init__.py
@@ -1,9 +1,10 @@
from django.template import loader
from django.template.loaders import filesystem
-from django.http import HttpResponse
import os.path
import os
import logging
+from forum.conf import settings as forum_settings
+from forum.skins import utils
#module for skinning askbot
#via ASKBOT_DEFAULT_SKIN configureation variable (not django setting)
@@ -13,28 +14,21 @@ import logging
#here it is ignored because it is assumed that we won't use unicode paths
def load_template_source(name, dirs=None):
+ print 'want template %s' % name
try:
#todo: move this to top after splitting out get_skin_dirs()
- from forum.conf import settings as forum_settings
+ print 'trying to import forum_settings'
+ print 'imported!'
tname = os.path.join(forum_settings.ASKBOT_DEFAULT_SKIN,'templates',name)
+ print tname
+ print 'success'
return filesystem.load_template_source(tname,dirs)
except:
+ print 'failed'
tname = os.path.join('default','templates',name)
return filesystem.load_template_source(tname,dirs)
load_template_source.is_usable = True
-#todo: move this to skins/utils.py
-#then move import forum.conf.settings to top
-def get_skin_dirs():
- #todo: handle case of multiple skin directories
- d = os.path.dirname
- n = os.path.normpath
- j = os.path.join
- f = os.path.isfile
- skin_dirs = []
- skin_dirs.append( n(j(d(d(__file__)), 'skins')) )
- return skin_dirs
-
def find_media_source(url):
"""returns url prefixed with the skin name
of the first skin that contains the file
@@ -43,20 +37,23 @@ def find_media_source(url):
if file is not found - returns None
and logs an error message
"""
+ print 'trying to get source dammit'
while url[0] == '/': url = url[1:]
d = os.path.dirname
n = os.path.normpath
j = os.path.join
f = os.path.isfile
#todo: handles case of multiple skin directories
- skins = get_skin_dirs()[0]
+ skins = utils.get_skin_dirs()[0]
try:
#todo: move this to top after splitting out get_skin_dirs()
- from forum.conf import settings as forum_settings
+ print 'looking for the media path'
media = os.path.join(skins, forum_settings.ASKBOT_DEFAULT_SKIN, url)
+ print 'out of dadata'
assert(f(media))
use_skin = forum_settings.ASKBOT_DEFAULT_SKIN
except:
+ print 'failed'
try:
media = j(skins, 'default', url)
assert(f(media))
@@ -71,20 +68,3 @@ def find_media_source(url):
use_skin = ''
return None
return use_skin + '/' + url
-
-def get_skin_choices():
- #todo: expand this to handle custom skin directories
- dirs = get_skin_dirs()
- default_dir = dirs[0]
- items = os.listdir(default_dir)
- skin_list = ['default']
- for i in items:
- item_path = os.path.join(default_dir,i)
- if not os.path.isdir(item_path):
- continue
- if i == 'common':
- continue
- if i not in skin_list:
- skin_list.append(i)
-
- return [(i,i) for i in skin_list]
diff --git a/forum/skins/utils.py b/forum/skins/utils.py
new file mode 100644
index 00000000..e3f2ddc5
--- /dev/null
+++ b/forum/skins/utils.py
@@ -0,0 +1,29 @@
+import os
+
+def get_skin_dirs():
+ #todo: handle case of multiple skin directories
+ d = os.path.dirname
+ n = os.path.normpath
+ j = os.path.join
+ f = os.path.isfile
+ skin_dirs = []
+ skin_dirs.append( n(j(d(d(__file__)), 'skins')) )
+ return skin_dirs
+
+def get_skin_choices():
+ #todo: expand this to handle custom skin directories
+ dirs = get_skin_dirs()
+ default_dir = dirs[0]
+ items = os.listdir(default_dir)
+ skin_list = ['default']
+ for i in items:
+ item_path = os.path.join(default_dir,i)
+ if not os.path.isdir(item_path):
+ continue
+ if i == 'common':
+ continue
+ if i not in skin_list:
+ skin_list.append(i)
+
+ return [(i,i) for i in skin_list]
+
diff --git a/forum/templatetags/extra_tags.py b/forum/templatetags/extra_tags.py
index 39a1ded7..972e8c9e 100644
--- a/forum/templatetags/extra_tags.py
+++ b/forum/templatetags/extra_tags.py
@@ -1,6 +1,5 @@
import time
import os
-import posixpath
import datetime
import math
import re
@@ -294,7 +293,7 @@ def media(url):
url = skins.find_media_source(url)
if url:
url = '///' + settings.FORUM_SCRIPT_ALIAS + '/m/' + url
- return posixpath.normpath(url) + '?v=%d' \
+ return os.path.normpath(url) + '?v=%d' \
% forum_settings.MEDIA_RESOURCE_REVISION
else:
return '' #todo: raise exception here?
@@ -377,7 +376,7 @@ class BlockMediaUrlNode(template.Node):
url = skins.find_media_source(url)
url = prefix + url
- out = posixpath.normpath(url) + '?v=%d' % forum_settings.MEDIA_RESOURCE_REVISION
+ out = os.path.normpath(url) + '?v=%d' % forum_settings.MEDIA_RESOURCE_REVISION
return out.replace(' ','')
@register.tag(name='blockmedia')
@@ -426,41 +425,41 @@ def question_counter_widget(question):
#background and foreground colors for each item
(views_fg, views_bg) = colors.get_counter_colors(
- view_count,
- max = forum_settings.VIEW_COUNTER_EXPECTED_MAXIMUM,
- zero_bg = forum_settings.COLORS_VIEW_COUNTER_EMPTY_BG,
- zero_fg = forum_settings.COLORS_VIEW_COUNTER_EMPTY_FG,
- min_bg = forum_settings.COLORS_VIEW_COUNTER_MIN_BG,
- min_fg = forum_settings.COLORS_VIEW_COUNTER_MIN_FG,
- max_bg = forum_settings.COLORS_VIEW_COUNTER_MAX_BG,
- max_fg = forum_settings.COLORS_VIEW_COUNTER_MAX_FG,
- )
+ view_count,
+ counter_max = forum_settings.VIEW_COUNTER_EXPECTED_MAXIMUM,
+ zero_bg = forum_settings.COLORS_VIEW_COUNTER_EMPTY_BG,
+ zero_fg = forum_settings.COLORS_VIEW_COUNTER_EMPTY_FG,
+ min_bg = forum_settings.COLORS_VIEW_COUNTER_MIN_BG,
+ min_fg = forum_settings.COLORS_VIEW_COUNTER_MIN_FG,
+ max_bg = forum_settings.COLORS_VIEW_COUNTER_MAX_BG,
+ max_fg = forum_settings.COLORS_VIEW_COUNTER_MAX_FG,
+ )
(answers_fg, answers_bg) = colors.get_counter_colors(
- answer_count,
- max = forum_settings.ANSWER_COUNTER_EXPECTED_MAXIMUM,
- zero_bg = forum_settings.COLORS_ANSWER_COUNTER_EMPTY_BG,
- zero_fg = forum_settings.COLORS_ANSWER_COUNTER_EMPTY_FG,
- min_bg = forum_settings.COLORS_ANSWER_COUNTER_MIN_BG,
- min_fg = forum_settings.COLORS_ANSWER_COUNTER_MIN_FG,
- max_bg = forum_settings.COLORS_ANSWER_COUNTER_MAX_BG,
- max_fg = forum_settings.COLORS_ANSWER_COUNTER_MAX_FG,
- )
+ answer_count,
+ counter_max = forum_settings.ANSWER_COUNTER_EXPECTED_MAXIMUM,
+ zero_bg = forum_settings.COLORS_ANSWER_COUNTER_EMPTY_BG,
+ zero_fg = forum_settings.COLORS_ANSWER_COUNTER_EMPTY_FG,
+ min_bg = forum_settings.COLORS_ANSWER_COUNTER_MIN_BG,
+ min_fg = forum_settings.COLORS_ANSWER_COUNTER_MIN_FG,
+ max_bg = forum_settings.COLORS_ANSWER_COUNTER_MAX_BG,
+ max_fg = forum_settings.COLORS_ANSWER_COUNTER_MAX_FG,
+ )
if answer_accepted:
#todo: maybe recalculate the foreground color too
answers_bg = forum_settings.COLORS_ANSWER_COUNTER_ACCEPTED_BG
answers_fg = forum_settings.COLORS_ANSWER_COUNTER_ACCEPTED_FG
(votes_fg, votes_bg) = colors.get_counter_colors(
- vote_count,
- max = forum_settings.VOTE_COUNTER_EXPECTED_MAXIMUM,
- zero_bg = forum_settings.COLORS_VOTE_COUNTER_EMPTY_BG,
- zero_fg = forum_settings.COLORS_VOTE_COUNTER_EMPTY_FG,
- min_bg = forum_settings.COLORS_VOTE_COUNTER_MIN_BG,
- min_fg = forum_settings.COLORS_VOTE_COUNTER_MIN_FG,
- max_bg = forum_settings.COLORS_VOTE_COUNTER_MAX_BG,
- max_fg = forum_settings.COLORS_VOTE_COUNTER_MAX_FG,
- )
+ vote_count,
+ counter_max = forum_settings.VOTE_COUNTER_EXPECTED_MAXIMUM,
+ zero_bg = forum_settings.COLORS_VOTE_COUNTER_EMPTY_BG,
+ zero_fg = forum_settings.COLORS_VOTE_COUNTER_EMPTY_FG,
+ min_bg = forum_settings.COLORS_VOTE_COUNTER_MIN_BG,
+ min_fg = forum_settings.COLORS_VOTE_COUNTER_MIN_FG,
+ max_bg = forum_settings.COLORS_VOTE_COUNTER_MAX_BG,
+ max_fg = forum_settings.COLORS_VOTE_COUNTER_MAX_FG,
+ )
#returns a dictionary with keys like 'votes_bg', etc
return locals()
@@ -506,5 +505,4 @@ def ifmany(parser,token):
else:
false_nodelist = template.NodeList()
-
return IsManyNode(test_items, true_nodelist, false_nodelist)
diff --git a/forum/tests.py b/forum/tests.py
index dca9cfad..2096386b 100644
--- a/forum/tests.py
+++ b/forum/tests.py
@@ -1,14 +1,12 @@
-from django.test import Client, TestCase
+from django.test import TestCase
from django.contrib.auth.models import User
-from forum import models
-import datetime
from django.template import defaultfilters
from django.core.urlresolvers import reverse
class AnonymousVisitorTests(TestCase):
- fixtures = ['forum/fixtures/full_dump.json',]
+ fixtures = ['forum/fixtures/full_dump.json', ]
def test_index(self):
#todo: merge this with all reader url tests
@@ -35,7 +33,7 @@ class AnonymousVisitorTests(TestCase):
url = reverse(url_name, kwargs = kwargs)
url_info = 'getting url %s' % url
if data:
- url_info += '?' + '&'.join(['%s=%s' % (k,v) for k,v in data.iteritems()])
+ url_info += '?' + '&'.join(['%s=%s' % (k, v) for k, v in data.iteritems()])
print url_info
r = self.client.get(url, data=data, follow=follow)
@@ -215,8 +213,8 @@ class AnonymousVisitorTests(TestCase):
status_code=200,
follow=True,
)
- u = User.objects.get(id=2)
- name_slug = defaultfilters.slugify(u.username)
+ user = User.objects.get(id=2)
+ name_slug = defaultfilters.slugify(user.username)
try_url(
'user_profile',
kwargs={'id': 2, 'slug': name_slug},
diff --git a/forum/urls.py b/forum/urls.py
index 944732e5..1864c608 100644
--- a/forum/urls.py
+++ b/forum/urls.py
@@ -1,11 +1,14 @@
+"""
+askbot forum url configuraion file
+"""
import os.path
-from django.conf.urls.defaults import *
+from django.conf.urls.defaults import url, patterns, include
+from django.conf.urls.defaults import handler500, handler404
from django.contrib import admin
from forum import views as app
from forum.feed import RssLastestQuestionsFeed
from forum.sitemap import QuestionsSitemap
from django.utils.translation import ugettext as _
-import logging
admin.autodiscover()
feeds = {
@@ -18,83 +21,183 @@ sitemaps = {
APP_PATH = os.path.dirname(__file__)
urlpatterns = patterns('',
url(r'^$', app.readers.index, name='index'),
- url(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}, name='sitemap'),
- #(r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/media/images/favicon.ico'}),
- #(r'^favicon\.gif$', 'django.views.generic.simple.redirect_to', {'url': '/media/images/favicon.gif'}),
- url(r'^m/(?P<path>.*)$', 'django.views.static.serve',
+ url(
+ r'^sitemap.xml$',
+ 'django.contrib.sitemaps.views.sitemap',
+ {'sitemaps': sitemaps},
+ name='sitemap'
+ ),
+ url(
+ r'^m/(?P<path>.*)$',
+ 'django.views.static.serve',
{'document_root': os.path.join(APP_PATH,'skins').replace('\\','/')},
name='askbot_media',
),
- url(r'^%s(?P<path>.*)$' % _('upfiles/'), 'django.views.static.serve',
+ url(
+ r'^%s(?P<path>.*)$' % _('upfiles/'),
+ 'django.views.static.serve',
{'document_root': os.path.join(APP_PATH,'upfiles').replace('\\','/')},
name='uploaded_file',
),
- #url(r'^%s/$' % _('signin/'), 'django_authopenid.views.signin', name='signin'),
url(r'^%s$' % _('about/'), app.meta.about, name='about'),
url(r'^%s$' % _('faq/'), app.meta.faq, name='faq'),
url(r'^%s$' % _('privacy/'), app.meta.privacy, name='privacy'),
url(r'^%s$' % _('logout/'), app.meta.logout, name='logout'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('comments/')), app.writers.answer_comments, name='answer_comments'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('edit/')), app.writers.edit_answer, name='edit_answer'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('revisions/')), app.readers.answer_revisions, name='answer_revisions'),
- url(r'^%s$' % _('questions/'), app.readers.questions, name='questions'),
- url(r'^%s%s$' % (_('questions/'), _('ask/')), app.writers.ask, name='ask'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('edit/')), app.writers.edit_question, name='edit_question'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')), app.commands.close, name='close'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')), app.commands.reopen, name='reopen'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')), app.writers.answer, name='answer'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('vote/')), app.commands.vote, name='vote'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')), app.readers.question_revisions, name='question_revisions'),
- url(r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('comments/')), app.writers.question_comments, name='question_comments'),
- url(r'^%s$' % _('command/'), app.commands.ajax_command, name='call_ajax'),
-
- url(r'^%s(?P<object_id>\d+)/%s(?P<comment_id>\d+)/%s$' % (_('questions/'), _('comments/'),_('delete/')), \
- app.writers.delete_comment, kwargs={'commented_object_type':'question'},\
- name='delete_question_comment'),
-
- url(r'^%s(?P<object_id>\d+)/%s(?P<comment_id>\d+)/%s$' % (_('answers/'), _('comments/'),_('delete/')), \
- app.writers.delete_comment, kwargs={'commented_object_type':'answer'}, \
- name='delete_answer_comment'), \
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('comments/')),
+ app.writers.answer_comments,
+ name='answer_comments'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('edit/')),
+ app.writers.edit_answer,
+ name='edit_answer'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('revisions/')),
+ app.readers.answer_revisions,
+ name='answer_revisions'
+ ),
+ url(
+ r'^%s$' % _('questions/'),
+ app.readers.questions,
+ name='questions'
+ ),
+ url(
+ r'^%s%s$' % (_('questions/'), _('ask/')),
+ app.writers.ask,
+ name='ask'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('edit/')),
+ app.writers.edit_question,
+ name='edit_question'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')),
+ app.commands.close,
+ name='close'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')),
+ app.commands.reopen,
+ name='reopen'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')),
+ app.writers.answer,
+ name='answer'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('vote/')),
+ app.commands.vote,
+ name='vote'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')),
+ app.readers.question_revisions,
+ name='question_revisions'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('comments/')),
+ app.writers.question_comments,
+ name='question_comments'
+ ),
+ url(
+ r'^%s$' % _('command/'),
+ app.commands.ajax_command,
+ name='call_ajax'
+ ),
+ url(
+ r'^%s(?P<object_id>\d+)/%s(?P<comment_id>\d+)/%s$'\
+ % (_('questions/'), _('comments/'),_('delete/')),
+ app.writers.delete_comment,
+ kwargs={'commented_object_type':'question'},
+ name='delete_question_comment'
+ ),
+ url(
+ r'^%s(?P<object_id>\d+)/%s(?P<comment_id>\d+)/%s$'\
+ % (_('answers/'), _('comments/'),_('delete/')),
+ app.writers.delete_comment,
+ kwargs={'commented_object_type':'answer'},
+ name='delete_answer_comment'
+ ),
#place general question item in the end of other operations
- url(r'^%s(?P<id>\d+)/' % _('question/'), app.readers.question, name='question'),
- url(r'^%s$' % _('tags/'), app.readers.tags, name='tags'),
-
- url(r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('interesting/')), app.commands.mark_tag, \
- kwargs={'reason':'good','action':'add'}, \
- name='mark_interesting_tag'),
-
- url(r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('ignored/')), app.commands.mark_tag, \
- kwargs={'reason':'bad','action':'add'}, \
- name='mark_ignored_tag'),
-
- url(r'^%s(?P<tag>[^/]+)/$' % _('unmark-tag/'), app.commands.mark_tag, \
- kwargs={'action':'remove'}, \
- name='mark_ignored_tag'),
-
- url(r'^%s$' % _('users/'),app.users.users, name='users'),
- url(r'^%s(?P<id>\d+)/$' % _('moderate-user/'), app.users.moderate_user, name='moderate_user'),
+ url(
+ r'^%s(?P<id>\d+)/' % _('question/'),
+ app.readers.question,
+ name='question'
+ ),
+ url(
+ r'^%s$' % _('tags/'),
+ app.readers.tags,
+ name='tags'
+ ),
+ url(
+ r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('interesting/')),
+ app.commands.mark_tag,
+ kwargs={'reason':'good','action':'add'},
+ name='mark_interesting_tag'
+ ),
+ url(
+ r'^%s%s(?P<tag>[^/]+)/$' % (_('mark-tag/'),_('ignored/')),
+ app.commands.mark_tag,
+ kwargs={'reason':'bad','action':'add'},
+ name='mark_ignored_tag'
+ ),
+ url(
+ r'^%s(?P<tag>[^/]+)/$' % _('unmark-tag/'),
+ app.commands.mark_tag,
+ kwargs={'action':'remove'},
+ name='mark_ignored_tag'
+ ),
+ url(
+ r'^%s$' % _('users/'),
+ app.users.users,
+ name='users'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/$' % _('moderate-user/'),
+ app.users.moderate_user,
+ name='moderate_user'
+ ),
#todo: rename as user_edit, b/c that's how template is named
- url(r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('edit/')), app.users.edit_user, name='edit_user'),
- url(r'^%s(?P<id>\d+)/(?P<slug>.+)/$' % _('users/'), app.users.user, name='user_profile'),
- url(r'^%s$' % _('badges/'),app.meta.badges, name='badges'),
- url(r'^%s(?P<id>\d+)//*' % _('badges/'), app.meta.badge, name='badge'),
- url(r'^%s%s$' % (_('messages/'), _('markread/')),app.commands.read_message, name='read_message'),
- # (r'^admin/doc/' % _('admin/doc'), include('django.contrib.admindocs.urls')),
- url(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}, name='feeds'),
- url(r'^%s$' % _('upload/'), app.writers.upload, name='upload'),
+ url(
+ r'^%s(?P<id>\d+)/%s$' % (_('users/'), _('edit/')),
+ app.users.edit_user,
+ name='edit_user'
+ ),
+ url(
+ r'^%s(?P<id>\d+)/(?P<slug>.+)/$' % _('users/'),
+ app.users.user,
+ name='user_profile'
+ ),
+ url(
+ r'^%s$' % _('badges/'),
+ app.meta.badges,
+ name='badges'
+ ),
+ url(
+ r'^%s(?P<id>\d+)//*' % _('badges/'),
+ app.meta.badge,
+ name='badge'
+ ),
+ url(
+ r'^%s%s$' % (_('messages/'), _('markread/')),
+ app.commands.read_message,
+ name='read_message'
+ ),
+ #(r'^admin/doc/' % _('admin/doc'),include('django.contrib.admindocs.urls')),
+ url(
+ r'^feeds/(?P<url>.*)/$',
+ 'django.contrib.syndication.views.feed',
+ {'feed_dict': feeds},
+ name='feeds'
+ ),
+ url( r'^%s$' % _('upload/'), app.writers.upload, name='upload'),
url(r'^%s$' % _('search/'), app.readers.search, name='search'),
url(r'^%s$' % _('feedback/'), app.meta.feedback, name='feedback'),
(r'^%s' % _('account/'), include('django_authopenid.urls')),
(r'^i18n/', include('django.conf.urls.i18n')),
-
url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"),
)
-
-#todo: modules
-#from forum.modules import get_modules_script
-#module_patterns = get_modules_script('urls')
-#for pattern_file in module_patterns:
-# pattern = getattr(pattern_file, 'urlpatterns', None)
-# if pattern:
-# urlpatterns += pattern
-
diff --git a/forum/user_messages/context_processors.py b/forum/user_messages/context_processors.py
index 5f7b857c..dec6198d 100644
--- a/forum/user_messages/context_processors.py
+++ b/forum/user_messages/context_processors.py
@@ -52,4 +52,3 @@ class LazyMessages (StrAndUnicode):
self._messages = get_and_delete_messages(self.request)
return self._messages
messages = property(_get_messages)
-
diff --git a/forum/utils/colors.py b/forum/utils/colors.py
index 8ab092d7..8ef6f342 100644
--- a/forum/utils/colors.py
+++ b/forum/utils/colors.py
@@ -1,7 +1,7 @@
from forum_modules.grapefruit import Color
import math
-def get_counter_colors(count, max=10, empty_bg='white', empty_fg='black',
+def get_counter_colors(count, counter_max=10, empty_bg='white', empty_fg='black',
zero_bg='white', zero_fg='black',
min_bg='white', min_fg='black',
max_bg='white', max_fg='black'
@@ -9,7 +9,7 @@ def get_counter_colors(count, max=10, empty_bg='white', empty_fg='black',
if count == 0:
return zero_fg, zero_bg
- if count > max:
+ if count > counter_max:
blend_factor = 0
else:
#todo deal with negative counts properly
diff --git a/forum/utils/email.py b/forum/utils/email.py
index dc712572..8f719e82 100644
--- a/forum/utils/email.py
+++ b/forum/utils/email.py
@@ -1,4 +1,4 @@
-from django.core.mail import send_mail, EmailMultiAlternatives
+from django.core.mail import EmailMultiAlternatives
from django.conf import settings
from django.template import loader, Context
from django.utils.html import strip_tags
diff --git a/forum/utils/forms.py b/forum/utils/forms.py
index aeb8ec4d..05bf9f85 100644
--- a/forum/utils/forms.py
+++ b/forum/utils/forms.py
@@ -48,6 +48,7 @@ class UserNameField(StrippedNonEmptyCharField):
self.skip_clean = skip_clean
self.db_model = db_model
self.db_field = db_field
+ self.user_instance = None
error_messages={'required':_('user name is required'),
'taken':_('sorry, this name is taken, please choose another'),
'forbidden':_('sorry, this name is not allowed, please choose another'),
@@ -70,10 +71,15 @@ class UserNameField(StrippedNonEmptyCharField):
if self.skip_clean == True:
logging.debug('username accepted with no validation')
return username
- if hasattr(self, 'user_instance') and isinstance(self.user_instance, User):
+ if self.user_instance is None:
+ pass
+ elif isinstance(self.user_instance, User):
if username == self.user_instance.username:
logging.debug('username valid')
return username
+ else:
+ raise TypeError('user instance must be of type User')
+
try:
username = super(UserNameField, self).clean(username)
except forms.ValidationError:
diff --git a/forum/utils/markup.py b/forum/utils/markup.py
index 941e978b..914eb508 100644
--- a/forum/utils/markup.py
+++ b/forum/utils/markup.py
@@ -76,10 +76,11 @@ def mentionize_text(text, anticipated_authors):
#if there is a termination character before @mention
#indeed try to find a matching person
text = text[pos+1:]
- mentioned_author, text = extract_first_matching_mentioned_author(
- text,
- anticipated_authors
- )
+ mentioned_author, text = \
+ extract_first_matching_mentioned_author(
+ text,
+ anticipated_authors
+ )
if mentioned_author:
mentioned_authors.append(mentioned_author)
output += format_mention_in_html(mentioned_author)
@@ -93,7 +94,11 @@ def mentionize_text(text, anticipated_authors):
else:
#do this if @ is the first character
text = text[1:]
- mentioned_author, text = extract_first_matching_mentioned_name(text, authors)
+ mentioned_author, text = \
+ extract_first_matching_mentioned_author(
+ text,
+ anticipated_authors
+ )
if mentioned_author:
mentioned_authors.append(mentioned_author)
output += format_mention_in_html(mentioned_author)
diff --git a/forum/views/__init__.py b/forum/views/__init__.py
index 291fee2a..dd390da7 100644
--- a/forum/views/__init__.py
+++ b/forum/views/__init__.py
@@ -1,5 +1,8 @@
-import readers
-import writers
-import commands
-import users
-import meta
+"""
+Forum views module
+"""
+from forum.views import readers
+from forum.views import writers
+from forum.views import commands
+from forum.views import users
+from forum.views import meta
diff --git a/forum/views/commands.py b/forum/views/commands.py
index 4746f71d..5de693b5 100644
--- a/forum/views/commands.py
+++ b/forum/views/commands.py
@@ -4,6 +4,7 @@ from django.conf import settings
from forum.conf import settings as forum_settings
from django.utils import simplejson
from django.http import HttpResponse, HttpResponseRedirect
+from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, render_to_response
from django.utils.translation import ugettext as _
from django.template import RequestContext
@@ -276,7 +277,9 @@ def ajax_toggle_ignored_questions(request):#ajax tagging and tag-filtering syste
request.user.save()
@ajax_method
-def ajax_command(request):#refactor? view processing ajax commands - note "vote" and view others do it too
+def ajax_command(request):
+ """view processing ajax commands - note "vote" and view others do it too
+ """
if 'command' not in request.POST:
return HttpResponseForbidden(mimetype="application/json")
if request.POST['command'] == 'toggle-ignored-questions':
diff --git a/forum/views/readers.py b/forum/views/readers.py
index f75f62a4..041f44bd 100644
--- a/forum/views/readers.py
+++ b/forum/views/readers.py
@@ -63,13 +63,10 @@ def index(request):#generates front page - shows listing of questions sorted in
"""
return HttpResponseRedirect(reverse('questions'))
-#todo: eliminate this from urls
-def unanswered(request):#generates listing of unanswered questions
- return questions(request, unanswered=True)
-
-def questions(request):#a view generating listing of questions, used by 'unanswered' too
+def questions(request):
"""
List of Questions, Tagged questions, and Unanswered questions.
+ matching search query or user selection
"""
#don't allow to post to this view
@@ -182,11 +179,6 @@ def search(request): #generates listing of questions matching a search query - i
else:
raise Http404
-#todo: eliminate this - need to go through templates to make sure
-#that there are no urls pointing here
-def tag(request, tag):#stub generates listing of questions tagged with a single tag
- return questions(request, tagname=tag)
-
def tags(request):#view showing a listing of available tags - plain list
stag = ""
is_paginated = True
diff --git a/forum/views/users.py b/forum/views/users.py
index d2c003bc..cb530af1 100644
--- a/forum/views/users.py
+++ b/forum/views/users.py
@@ -7,19 +7,17 @@ from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
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 django.utils import simplejson
from forum.utils.html import sanitize_html
from forum import auth
from forum import forms
import calendar
-from django.contrib.contenttypes.models import ContentType
from forum import const
-from django.conf import settings
from forum.conf import settings as forum_settings
from forum import models
from forum.models import signals
+import logging
question_type = ContentType.objects.get_for_model(models.Question)
answer_type = ContentType.objects.get_for_model(models.Answer)
@@ -71,13 +69,13 @@ def users(request):
base_url = reverse('users') + '?name=%s&sort=%s&' % (suser, sortby)
try:
- users = objects_list.page(page)
+ users_page = objects_list.page(page)
except (EmptyPage, InvalidPage):
- users = objects_list.page(objects_list.num_pages)
+ users_page = objects_list.page(objects_list.num_pages)
return render_to_response('users.html', {
'active_tab': 'users',
- 'users' : users,
+ 'users' : users_page,
'suser' : suser,
'keywords' : suser,
'tab_id' : sortby,
@@ -85,10 +83,10 @@ def users(request):
'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(),
+ 'has_previous': users_page.has_previous(),
+ 'has_next': users_page.has_next(),
+ 'previous': users_page.previous_page_number(),
+ 'next': users_page.next_page_number(),
'base_url' : base_url
}
@@ -607,7 +605,7 @@ def user_responses(request, user_id, user_view):
if len(answers) > 0:
answer_responses = []
for a in answers:
- r = Response(
+ resp = Response(
const.TYPE_RESPONSE['QUESTION_ANSWERED'],
a['title'],
a['question_id'],
@@ -617,6 +615,7 @@ def user_responses(request, user_id, user_view):
a['user_id'],
a['html']
)
+ answer_responses.append(resp)
responses.extend(answer_responses)
# question comments
@@ -991,10 +990,14 @@ USER_TEMPLATE_VIEWS = (
)
)
+#todo: rename this function - variable named user is everywhere
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
+ user_view = dict(
+ (v.id, v) for v in USER_TEMPLATE_VIEWS
+ ).get(
+ sort, USER_TEMPLATE_VIEWS[0]
+ )
func = user_view.view_func
return func(request, id, user_view)
diff --git a/forum/views/writers.py b/forum/views/writers.py
index b6895bc7..fe2238a7 100644
--- a/forum/views/writers.py
+++ b/forum/views/writers.py
@@ -1,24 +1,22 @@
# encoding:utf-8
import os.path
import time, datetime, random
-import logging
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, HttpResponseForbidden, Http404
from django.template import RequestContext
-from django.utils.html import * #todo: remove import * in favor of explicit imports
from django.utils import simplejson
+from django.utils.html import strip_tags
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
+from django.conf import settings
-from forum.forms import *
-from forum.models import *
-from forum.const import *
from forum import auth
-from forum.utils.forms import get_next_url
from forum.views.readers import _get_tags_cache_json
+from forum import forms
+from forum import models
# used in index page
INDEX_PAGE_SIZE = 20
@@ -85,7 +83,7 @@ def ask(request):#view used to ask a new question
must login/register in order for the question go be shown
"""
if request.method == "POST":
- form = AskForm(request.POST)
+ form = forms.AskForm(request.POST)
if form.is_valid():
added_at = datetime.datetime.now()
@@ -103,7 +101,7 @@ def ask(request):#view used to ask a new question
if request.user.is_authenticated():
author = request.user
- question = Question.objects.create_new(
+ question = models.Question.objects.create_new(
title = title,
author = author,
added_at = added_at,
@@ -117,7 +115,7 @@ def ask(request):#view used to ask a new question
request.session.flush()
session_key = request.session.session_key
summary = strip_tags(text)[:120]
- question = AnonymousQuestion(
+ question = models.AnonymousQuestion(
session_key = session_key,
title = title,
tagnames = tagnames,
@@ -131,7 +129,7 @@ def ask(request):#view used to ask a new question
return HttpResponseRedirect(reverse('user_signin_new_question'))
else:
#this branch is for the initial load of ask form
- form = AskForm()
+ form = forms.AskForm()
if 'title' in request.GET:
#normally this title is inherited from search query
#but it is possible to ask with a parameter title in the url query
@@ -155,7 +153,7 @@ def ask(request):#view used to ask a new question
def edit_question(request, id):#edit or retag a question
"""view to edit question
"""
- question = get_object_or_404(Question, id=id)
+ question = get_object_or_404(models.Question, id=id)
if question.deleted and not auth.can_view_deleted_post(request.user, question):
raise Http404
if auth.can_edit_post(request.user, question):
@@ -170,7 +168,7 @@ def _retag_question(request, question):#non-url subview of edit question - just
view "edit_question"
"""
if request.method == 'POST':
- form = RetagQuestionForm(question, request.POST)
+ form = forms.RetagQuestionForm(question, request.POST)
if form.is_valid():
if form.has_changed():
question.retag(
@@ -180,7 +178,7 @@ def _retag_question(request, question):#non-url subview of edit question - just
)
return HttpResponseRedirect(question.get_absolute_url())
else:
- form = RetagQuestionForm(question)
+ form = forms.RetagQuestionForm(question)
return render_to_response('question_retag.html', {
'active_tab': 'questions',
'question': question,
@@ -194,17 +192,17 @@ def _edit_question(request, question):#non-url subview of edit_question - just e
if request.method == 'POST':
if 'select_revision' in request.POST:#revert-type edit
# user has changed revistion number
- revision_form = RevisionForm(question, latest_revision, request.POST)
+ revision_form = forms.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,
+ form = forms.EditQuestionForm(question,
+ models.QuestionRevision.objects.get(question=question,
revision=revision_form.cleaned_data['revision']))
else:
- form = EditQuestionForm(question, latest_revision, request.POST)
+ form = forms.EditQuestionForm(question, latest_revision, request.POST)
else:#new content edit
# Always check modifications against the latest revision
- form = EditQuestionForm(question, latest_revision, request.POST)
+ form = forms.EditQuestionForm(question, latest_revision, request.POST)
if form.is_valid():
if form.has_changed():
edited_at = datetime.datetime.now()
@@ -222,8 +220,8 @@ def _edit_question(request, question):#non-url subview of edit_question - just e
return HttpResponseRedirect(question.get_absolute_url())
else:
- revision_form = RevisionForm(question, latest_revision)
- form = EditQuestionForm(question, latest_revision)
+ revision_form = forms.RevisionForm(question, latest_revision)
+ form = forms.EditQuestionForm(question, latest_revision)
return render_to_response('question_edit.html', {
'active_tab': 'questions',
'question': question,
@@ -234,7 +232,7 @@ def _edit_question(request, question):#non-url subview of edit_question - just e
@login_required
def edit_answer(request, id):
- answer = get_object_or_404(Answer, id=id)
+ answer = get_object_or_404(models.Answer, id=id)
if answer.deleted and not auth.can_view_deleted_post(request.user, answer):
raise Http404
elif not auth.can_edit_post(request.user, answer):
@@ -244,16 +242,16 @@ def edit_answer(request, id):
if request.method == "POST":
if 'select_revision' in request.POST:
# user has changed revistion number
- revision_form = RevisionForm(answer, latest_revision, request.POST)
+ revision_form = forms.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,
+ form = forms.EditAnswerForm(answer,
+ models.AnswerRevision.objects.get(answer=answer,
revision=revision_form.cleaned_data['revision']))
else:
- form = EditAnswerForm(answer, latest_revision, request.POST)
+ form = forms.EditAnswerForm(answer, latest_revision, request.POST)
else:
- form = EditAnswerForm(answer, latest_revision, request.POST)
+ form = forms.EditAnswerForm(answer, latest_revision, request.POST)
if form.is_valid():
if form.has_changed():
edited_at = datetime.datetime.now()
@@ -266,8 +264,8 @@ def edit_answer(request, id):
)
return HttpResponseRedirect(answer.get_absolute_url())
else:
- revision_form = RevisionForm(answer, latest_revision)
- form = EditAnswerForm(answer, latest_revision)
+ revision_form = forms.RevisionForm(answer, latest_revision)
+ form = forms.EditAnswerForm(answer, latest_revision)
return render_to_response('answer_edit.html', {
'active_tab': 'questions',
'answer': answer,
@@ -275,17 +273,18 @@ def edit_answer(request, id):
'form': form,
}, context_instance=RequestContext(request))
+#todo: rename this function to post_new_answer
def answer(request, id):#process a new answer
- question = get_object_or_404(Question, id=id)
+ question = get_object_or_404(models.Question, id=id)
if request.method == "POST":
- form = AnswerForm(question, request.user, request.POST)
+ form = forms.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():
- Answer.objects.create_new(
+ models.Answer.objects.create_new(
question=question,
author=request.user,
added_at=update_time,
@@ -295,7 +294,7 @@ def answer(request, id):#process a new answer
)
else:
request.session.flush()
- anon = AnonymousAnswer(
+ anon = models.AnonymousAnswer(
question=question,
wiki=wiki,
text=text,
@@ -308,7 +307,9 @@ def answer(request, id):#process a new answer
return HttpResponseRedirect(question.get_absolute_url())
-def __generate_comments_json(obj, type, user):#non-view generates json data for the post comments
+def __generate_comments_json(obj, comment_type, user):
+ """non-view generates json data for the post comments
+ """
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 = []
@@ -319,7 +320,8 @@ def __generate_comments_json(obj, type, user):#non-view generates json data for
if user != None and auth.can_delete_comment(user, comment):
#/posts/392845/comments/219852/delete
#todo translate this url
- delete_url = reverse('index') + type + "s/%s/comments/%s/delete/" % (obj.id, comment.id)
+ delete_url = reverse('index') + comment_type + \
+ "s/%s/comments/%s/delete/" % (obj.id, comment.id)
json_comments.append({"id" : comment.id,
"object_id" : obj.id,
"comment_age" : diff_date(comment.added_at),
@@ -333,42 +335,39 @@ def __generate_comments_json(obj, type, user):#non-view generates json data for
return HttpResponse(data, mimetype="application/json")
def question_comments(request, id):#ajax handler for loading comments to question
- question = get_object_or_404(Question, id=id)
- user = request.user
+ question = get_object_or_404(models.Question, id=id)
return __comments(request, question, 'question')
def answer_comments(request, id):#ajax handler for loading comments on answer
- answer = get_object_or_404(Answer, id=id)
- user = request.user
+ answer = get_object_or_404(models.Answer, id=id)
return __comments(request, answer, 'answer')
-def __comments(request, obj, type):#non-view generic ajax handler to load comments to an object
+def __comments(request, obj, comment_type):#non-view generic ajax handler to load comments to an object
# only support get post comments by ajax now
user = request.user
if request.is_ajax():
if request.method == "GET":
- response = __generate_comments_json(obj, type, user)
+ response = __generate_comments_json(obj, comment_type, user)
elif request.method == "POST":
- if auth.can_add_comments(user,obj):
+ if auth.can_add_comments(user, obj):
obj.add_comment(
comment = request.POST.get('comment'),
user = request.user,
)
- response = __generate_comments_json(obj, type, user)
+ response = __generate_comments_json(obj, comment_type, user)
else:
response = HttpResponseForbidden(mimetype="application/json")
return response
def delete_comment(request, object_id='', comment_id='', commented_object_type=None):#ajax handler to delete comment
- response = None
commented_object = None
if commented_object_type == 'question':
- commented_object = Question
+ commented_object = models.Question
elif commented_object_type == 'answer':
- commented_object = Answer
+ commented_object = models.Answer
if request.is_ajax():
- comment = get_object_or_404(Comment, id=comment_id)
+ comment = get_object_or_404(models.Comment, id=comment_id)
if auth.can_delete_comment(request.user, comment):
obj = get_object_or_404(commented_object, id=object_id)
obj.comments.remove(comment)
diff --git a/settings.py b/settings.py
index 98555997..1f78d0e6 100644
--- a/settings.py
+++ b/settings.py
@@ -13,7 +13,6 @@ TEMPLATE_LOADERS = (
'django.template.loaders.app_directories.load_template_source',
#below is forum stuff for this tuple
- 'forum.modules.module_templates_loader',#todo: remove this
'forum.skins.load_template_source',#forum stuff
# 'django.template.loaders.eggs.load_template_source',
)
@@ -59,10 +58,6 @@ FILE_UPLOAD_TEMP_DIR = os.path.join(os.path.dirname(__file__), 'tmp').replace('\
FILE_UPLOAD_HANDLERS = ("django.core.files.uploadhandler.MemoryFileUploadHandler",
"django.core.files.uploadhandler.TemporaryFileUploadHandler",)
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
-# for user upload
-ALLOW_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
-# unit byte
-ALLOW_MAX_FILE_SIZE = 1024 * 1024
# User settings
from settings_local import *
@@ -80,7 +75,6 @@ INSTALLED_APPS = (
'debug_toolbar',
'forum',
'django_authopenid',
- 'debug_toolbar' ,
#'forum.importers.stackexchange', #se loader
'south',
'livesettings',
diff --git a/settings_local.py.dist b/settings_local.py.dist
index 6294a28c..fc6815da 100755
--- a/settings_local.py.dist
+++ b/settings_local.py.dist
@@ -37,6 +37,11 @@ CACHE_BACKEND = 'dummy://'
#If you use memcache you may want to uncomment the following line to enable memcached based sessions
#SESSION_ENGINE = 'django.contrib.sessions.backends.cache_db'
+# for user upload
+
+ALLOW_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
+# unit byte
+ALLOW_MAX_FILE_SIZE = 1024 * 1024
#email server settings
SERVER_EMAIL = ''