diff options
author | Adolfo Fitoria <fitoria@fitoria-laptop.(none)> | 2009-08-08 09:57:47 -0600 |
---|---|---|
committer | Adolfo Fitoria <fitoria@fitoria-laptop.(none)> | 2009-08-08 09:57:47 -0600 |
commit | 07b43ed86df2c9332b35beb632ab7961cc80540e (patch) | |
tree | 62acfad802745c029b36aec7b33ae37f4710f270 | |
parent | e05464c270af74e301e839d0c5180e7b2c94205b (diff) | |
parent | 84c4766d7ce0ae7a6a93dbe996099a60b30fc9e5 (diff) | |
download | askbot-07b43ed86df2c9332b35beb632ab7961cc80540e.tar.gz askbot-07b43ed86df2c9332b35beb632ab7961cc80540e.tar.bz2 askbot-07b43ed86df2c9332b35beb632ab7961cc80540e.zip |
Merge branch 'evgenyfadeev/master' into experimental
Conflicts:
forum/models.py
forum/views.py
locale/es/LC_MESSAGES/django.po
-rw-r--r-- | forum/auth.py | 449 | ||||
-rw-r--r-- | forum/models.py | 981 | ||||
-rw-r--r-- | forum/views.py | 1965 | ||||
-rw-r--r-- | locale/en/LC_MESSAGES/django.mo | bin | 15885 -> 13992 bytes | |||
-rw-r--r-- | locale/en/LC_MESSAGES/django.po | 27 | ||||
-rw-r--r-- | locale/es/LC_MESSAGES/django.mo | bin | 39157 -> 42843 bytes | |||
-rw-r--r-- | locale/es/LC_MESSAGES/django.po | 135 | ||||
-rw-r--r-- | templates/reopen.html | 5 |
8 files changed, 223 insertions, 3339 deletions
diff --git a/forum/auth.py b/forum/auth.py index 65ad6dad..36ca54d3 100644 --- a/forum/auth.py +++ b/forum/auth.py @@ -1,451 +1,4 @@ -"""
-Authorisation related functions.
-
-The actions a User is authorised to perform are dependent on their reputation
-and superuser status.
-"""
-import datetime
-from django.contrib.contenttypes.models import ContentType
-from django.db import transaction
-from models import Repute
-from models import Question
-from models import Answer
-from const import TYPE_REPUTATION
-question_type = ContentType.objects.get_for_model(Question)
-answer_type = ContentType.objects.get_for_model(Answer)
-
-VOTE_UP = 15
-FLAG_OFFENSIVE = 15
-POST_IMAGES = 15
-LEAVE_COMMENTS = 50
-UPLOAD_FILES = 60
-VOTE_DOWN = 100
-CLOSE_OWN_QUESTIONS = 250
-RETAG_OTHER_QUESTIONS = 500
-REOPEN_OWN_QUESTIONS = 500
-EDIT_COMMUNITY_WIKI_POSTS = 750
-EDIT_OTHER_POSTS = 2000
-DELETE_COMMENTS = 2000
-VIEW_OFFENSIVE_FLAGS = 2000
-DISABLE_URL_NOFOLLOW = 2000
-CLOSE_OTHER_QUESTIONS = 3000
-LOCK_POSTS = 4000
-
-VOTE_RULES = {
- 'scope_votes_per_user_per_day' : 30, # how many votes of one user has everyday
- 'scope_flags_per_user_per_day' : 5, # how many times user can flag posts everyday
- 'scope_warn_votes_left' : 10, # start when to warn user how many votes left
- 'scope_deny_unvote_days' : 1, # if 1 days passed, user can't cancel votes.
- 'scope_flags_invisible_main_page' : 3, # post doesn't show on main page if has more than 3 offensive flags
- 'scope_flags_delete_post' : 5, # post will be deleted if it has more than 5 offensive flags
-}
-
-REPUTATION_RULES = {
- 'initial_score' : 1,
- 'scope_per_day_by_upvotes' : 200,
- 'gain_by_upvoted' : 10,
- 'gain_by_answer_accepted' : 15,
- 'gain_by_accepting_answer' : 2,
- 'gain_by_downvote_canceled' : 2,
- 'gain_by_canceling_downvote' : 1,
- 'lose_by_canceling_accepted_answer' : -2,
- 'lose_by_accepted_answer_cancled' : -15,
- 'lose_by_downvoted' : -2,
- 'lose_by_flagged' : -2,
- 'lose_by_downvoting' : -1,
- 'lose_by_flagged_lastrevision_3_times': -30,
- 'lose_by_flagged_lastrevision_5_times': -100,
- 'lose_by_upvote_canceled' : -10,
-}
-
-def can_vote_up(user):
- """Determines if a User can vote Questions and Answers up."""
- return user.is_authenticated() and (
- user.reputation >= VOTE_UP or
- user.is_superuser)
-
-def can_flag_offensive(user):
- """Determines if a User can flag Questions and Answers as offensive."""
- return user.is_authenticated() and (
- user.reputation >= FLAG_OFFENSIVE or
- user.is_superuser)
-
-def can_add_comments(user):
- """Determines if a User can add comments to Questions and Answers."""
- return user.is_authenticated() and (
- user.reputation >= LEAVE_COMMENTS or
- user.is_superuser)
-
-def can_vote_down(user):
- """Determines if a User can vote Questions and Answers down."""
- return user.is_authenticated() and (
- user.reputation >= VOTE_DOWN or
- user.is_superuser)
-
-def can_retag_questions(user):
- """Determines if a User can retag Questions."""
- return user.is_authenticated() and (
- RETAG_OTHER_QUESTIONS <= user.reputation < EDIT_OTHER_POSTS or
- user.is_superuser)
-
-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 >= EDIT_COMMUNITY_WIKI_POSTS) or
- user.reputation >= EDIT_OTHER_POSTS or
- user.is_superuser)
-
-def can_delete_comment(user, comment):
- """Determines if a User can delete the given Comment."""
- return user.is_authenticated() and (
- user.id == comment.user_id or
- user.reputation >= DELETE_COMMENTS or
- user.is_superuser)
-
-def can_view_offensive_flags(user):
- """Determines if a User can view offensive flag counts."""
- return user.is_authenticated() and (
- user.reputation >= VIEW_OFFENSIVE_FLAGS or
- user.is_superuser)
-
-def can_close_question(user, question):
- """Determines if a User can close the given Question."""
- return user.is_authenticated() and (
- (user.id == question.author_id and
- user.reputation >= CLOSE_OWN_QUESTIONS) or
- user.reputation >= CLOSE_OTHER_QUESTIONS or
- user.is_superuser)
-
-def can_lock_posts(user):
- """Determines if a User can lock Questions or Answers."""
- return user.is_authenticated() and (
- user.reputation >= LOCK_POSTS or
- user.is_superuser)
-
-def can_follow_url(user):
- """Determines if the URL link can be followed by Google search engine."""
- return user.reputation >= 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
-
-# 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 >= REOPEN_OWN_QUESTIONS) or user.is_superuser
-
-def can_delete_post(user, post):
- return (user.is_authenticated() and
- user.id == post.author_id) or user.is_superuser
-
-def can_view_deleted_post(user, post):
- return user.is_superuser
-
-# user preferences view permissions
-def is_user_self(request_user, target_user):
- return (request_user.is_authenticated() and request_user == target_user)
-
-def can_view_user_votes(request_user, target_user):
- return (request_user.is_authenticated() and request_user == target_user)
-
-def can_view_user_preferences(request_user, target_user):
- return (request_user.is_authenticated() and request_user == target_user)
-
-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 >= UPLOAD_FILES) or \
- request_user.is_superuser
-
-###########################################
-## actions and reputation changes event
-###########################################
-def calculate_reputation(origin, offset):
- result = int(origin) + int(offset)
- if (result > 0):
- return result
- else:
- return 1
-
-@transaction.commit_on_success
-def onFlaggedItem(item, post, user):
-
- item.save()
- post.offensive_flag_count = post.offensive_flag_count + 1
- post.save()
-
- post.author.reputation = calculate_reputation(post.author.reputation,
- int(REPUTATION_RULES['lose_by_flagged']))
- post.author.save()
-
- question = post
- if ContentType.objects.get_for_model(post) == answer_type:
- question = post.question
-
- reputation = Repute(user=post.author,
- negative=int(REPUTATION_RULES['lose_by_flagged']),
- question=question, reputed_at=datetime.datetime.now(),
- reputation_type=-4,
- reputation=post.author.reputation)
- reputation.save()
-
- #todo: These should be updated to work on same revisions.
- if post.offensive_flag_count == VOTE_RULES['scope_flags_invisible_main_page'] :
- post.author.reputation = calculate_reputation(post.author.reputation,
- int(REPUTATION_RULES['lose_by_flagged_lastrevision_3_times']))
- post.author.save()
-
- reputation = Repute(user=post.author,
- negative=int(REPUTATION_RULES['lose_by_flagged_lastrevision_3_times']),
- question=question,
- reputed_at=datetime.datetime.now(),
- reputation_type=-6,
- reputation=post.author.reputation)
- reputation.save()
-
- elif post.offensive_flag_count == VOTE_RULES['scope_flags_delete_post']:
- post.author.reputation = calculate_reputation(post.author.reputation,
- int(REPUTATION_RULES['lose_by_flagged_lastrevision_5_times']))
- post.author.save()
-
- reputation = Repute(user=post.author,
- negative=int(REPUTATION_RULES['lose_by_flagged_lastrevision_5_times']),
- question=question,
- reputed_at=datetime.datetime.now(),
- reputation_type=-7,
- reputation=post.author.reputation)
- reputation.save()
-
- post.deleted = True
- #post.deleted_at = datetime.datetime.now()
- #post.deleted_by = Admin
- post.save()
-
-
-@transaction.commit_on_success
-def onAnswerAccept(answer, user):
- answer.accepted = True
- answer.accepted_at = datetime.datetime.now()
- answer.question.answer_accepted = True
- answer.save()
- answer.question.save()
-
- answer.author.reputation = calculate_reputation(answer.author.reputation,
- int(REPUTATION_RULES['gain_by_answer_accepted']))
- answer.author.save()
- reputation = Repute(user=answer.author,
- positive=int(REPUTATION_RULES['gain_by_answer_accepted']),
- question=answer.question,
- reputed_at=datetime.datetime.now(),
- reputation_type=2,
- reputation=answer.author.reputation)
- reputation.save()
-
- user.reputation = calculate_reputation(user.reputation,
- int(REPUTATION_RULES['gain_by_accepting_answer']))
- user.save()
- reputation = Repute(user=user,
- positive=int(REPUTATION_RULES['gain_by_accepting_answer']),
- question=answer.question,
- reputed_at=datetime.datetime.now(),
- reputation_type=3,
- reputation=user.reputation)
- reputation.save()
-
-@transaction.commit_on_success
-def onAnswerAcceptCanceled(answer, user):
- answer.accepted = False
- answer.accepted_at = None
- answer.question.answer_accepted = False
- answer.save()
- answer.question.save()
-
- answer.author.reputation = calculate_reputation(answer.author.reputation,
- int(REPUTATION_RULES['lose_by_accepted_answer_cancled']))
- answer.author.save()
- reputation = Repute(user=answer.author,
- negative=int(REPUTATION_RULES['lose_by_accepted_answer_cancled']),
- question=answer.question,
- reputed_at=datetime.datetime.now(),
- reputation_type=-2,
- reputation=answer.author.reputation)
- reputation.save()
-
- user.reputation = calculate_reputation(user.reputation,
- int(REPUTATION_RULES['lose_by_canceling_accepted_answer']))
- user.save()
- reputation = Repute(user=user,
- negative=int(REPUTATION_RULES['lose_by_canceling_accepted_answer']),
- question=answer.question,
- reputed_at=datetime.datetime.now(),
- reputation_type=-1,
- reputation=user.reputation)
- reputation.save()
-
-@transaction.commit_on_success
-def onUpVoted(vote, post, user):
- vote.save()
-
- post.vote_up_count = int(post.vote_up_count) + 1
- post.score = int(post.score) + 1
- post.save()
-
- if not post.wiki:
- author = post.author
- if Repute.objects.get_reputation_by_upvoted_today(author) < int(REPUTATION_RULES['scope_per_day_by_upvotes']):
- author.reputation = calculate_reputation(author.reputation,
- int(REPUTATION_RULES['gain_by_upvoted']))
- author.save()
-
- question = post
- if ContentType.objects.get_for_model(post) == answer_type:
- question = post.question
-
- reputation = Repute(user=author,
- positive=int(REPUTATION_RULES['gain_by_upvoted']),
- question=question,
- reputed_at=datetime.datetime.now(),
- reputation_type=1,
- reputation=author.reputation)
- reputation.save()
-
-@transaction.commit_on_success
-def onUpVotedCanceled(vote, post, user):
- vote.delete()
-
- post.vote_up_count = int(post.vote_up_count) - 1
- if post.vote_up_count < 0:
- post.vote_up_count = 0
- post.score = int(post.score) - 1
- post.save()
-
- if not post.wiki:
- author = post.author
- author.reputation = calculate_reputation(author.reputation,
- int(REPUTATION_RULES['lose_by_upvote_canceled']))
- author.save()
-
- question = post
- if ContentType.objects.get_for_model(post) == answer_type:
- question = post.question
-
- reputation = Repute(user=author,
- negative=int(REPUTATION_RULES['lose_by_upvote_canceled']),
- question=question,
- reputed_at=datetime.datetime.now(),
- reputation_type=-8,
- reputation=author.reputation)
- reputation.save()
-
-@transaction.commit_on_success
-def onDownVoted(vote, post, user):
- vote.save()
-
- post.vote_down_count = int(post.vote_down_count) + 1
- post.score = int(post.score) - 1
- post.save()
-
- if not post.wiki:
- author = post.author
- author.reputation = calculate_reputation(author.reputation,
- int(REPUTATION_RULES['lose_by_downvoted']))
- author.save()
-
- question = post
- if ContentType.objects.get_for_model(post) == answer_type:
- question = post.question
-
- reputation = Repute(user=author,
- negative=int(REPUTATION_RULES['lose_by_downvoted']),
- question=question,
- reputed_at=datetime.datetime.now(),
- reputation_type=-3,
- reputation=author.reputation)
- reputation.save()
-
- user.reputation = calculate_reputation(user.reputation,
- int(REPUTATION_RULES['lose_by_downvoting']))
- user.save()
-
- reputation = Repute(user=user,
- negative=int(REPUTATION_RULES['lose_by_downvoting']),
- question=question,
- reputed_at=datetime.datetime.now(),
- reputation_type=-5,
- reputation=user.reputation)
- reputation.save()
-
-@transaction.commit_on_success
-def onDownVotedCanceled(vote, post, user):
- vote.delete()
-
- post.vote_down_count = int(post.vote_down_count) - 1
- if post.vote_down_count < 0:
- post.vote_down_count = 0
- post.score = post.score + 1
- post.save()
-
- if not post.wiki:
- author = post.author
- author.reputation = calculate_reputation(author.reputation,
- int(REPUTATION_RULES['gain_by_downvote_canceled']))
- author.save()
-
- question = post
- if ContentType.objects.get_for_model(post) == answer_type:
- question = post.question
-
- reputation = Repute(user=author,
- positive=int(REPUTATION_RULES['gain_by_downvote_canceled']),
- question=question,
- reputed_at=datetime.datetime.now(),
- reputation_type=4,
- reputation=author.reputation)
- reputation.save()
-
- user.reputation = calculate_reputation(user.reputation,
- int(REPUTATION_RULES['gain_by_canceling_downvote']))
- user.save()
-
- reputation = Repute(user=user,
- positive=int(REPUTATION_RULES['gain_by_canceling_downvote']),
- question=question,
- reputed_at=datetime.datetime.now(),
- reputation_type=5,
- reputation=user.reputation)
- reputation.save()
-
-def onDeleteCanceled(post, user):
- post.deleted = False
- post.deleted_by = None
- post.deleted_at = None
- post.save()
- for tag in list(post.tags.all()):
- if tag.used_count == 1 and tag.deleted:
- tag.deleted = False
- tag.deleted_by = None
- tag.deleted_at = None
- tag.save()
-
-def onDeleted(post, user):
- post.deleted = True
- post.deleted_by = user
- post.deleted_at = datetime.datetime.now()
- post.save()
-
- for tag in list(post.tags.all()):
- if tag.used_count == 1:
- tag.deleted = True
- tag.deleted_by = user
- tag.deleted_at = datetime.datetime.now()
- tag.save()
-======= -""" +""" Authorisation related functions. The actions a User is authorised to perform are dependent on their reputation diff --git a/forum/models.py b/forum/models.py index c3ed9c9d..b607bec3 100644 --- a/forum/models.py +++ b/forum/models.py @@ -1,4 +1,4 @@ -# encoding:utf-8
+# encoding:utf-8
import datetime
import hashlib
from urllib import quote_plus, urlencode
@@ -12,16 +12,40 @@ from django.template.defaultfilters import slugify from django.db.models.signals import post_delete, post_save, pre_save
from django.utils.translation import ugettext as _
import django.dispatch
+import settings
from forum.managers import *
from const import *
+class EmailFeed(models.Model):
+ #subscription key for unsubscribe by visiting emailed link
+ key = models.CharField(max_length=32)
+ #generic relation with feed content (i.e. question or tags)
+ feed_content_type = models.ForeignKey(ContentType,related_name='content_emailfeed')
+ feed_id = models.PositiveIntegerField()
+ content = generic.GenericForeignKey('feed_content_type','feed_id')
+ #generic relation with owner - either nameless email or User
+ subscriber_content_type = models.ForeignKey(ContentType,related_name='subscriber_emailfeed')
+ subscriber_id = models.PositiveIntegerField()
+ subscriber = generic.GenericForeignKey('subscriber_content_type','subscriber_id')
+ added_at = models.DateTimeField(default=datetime.datetime.now)
+ reported_at = models.DateTimeField(default=datetime.datetime.now)
+
+ #getter functions rely on implementations of similar functions in content
+ #of subscriber objects
+ def get_update_summary(self):
+ return self.content.get_update_summary(last_reported_at = self.reported_at,recipient_email = self.get_email())
+
+ def get_email(self):
+ return self.subscriber.email
+
class Tag(models.Model):
name = models.CharField(max_length=255, unique=True)
created_by = models.ForeignKey(User, related_name='created_tags')
deleted = models.BooleanField(default=False)
deleted_at = models.DateTimeField(null=True, blank=True)
deleted_by = models.ForeignKey(User, null=True, blank=True, related_name='deleted_tags')
+ email_feeds = generic.GenericRelation(EmailFeed)
# Denormalised data
used_count = models.PositiveIntegerField(default=0)
@@ -131,6 +155,7 @@ class Question(models.Model): comments = generic.GenericRelation(Comment)
votes = generic.GenericRelation(Vote)
flagged_items = generic.GenericRelation(FlaggedItem)
+ email_feeds = generic.GenericRelation(EmailFeed)
objects = QuestionManager()
@@ -173,15 +198,10 @@ class Question(models.Model): attr = CONST['deleted']
else:
attr = None
-
- if (attr is not None):
- return u'%s %s' % (self.title, attr)
+ if attr is not None:
+ return u'%s %s' % (self.title, attr)
else:
-<<<<<<< HEAD:forum/models.py return self.title
-======= - return self.title
->>>>>>> evgenyfadeev/master:forum/models.py def get_revision_url(self):
return reverse('question_revisions', args=[self.id])
@@ -189,6 +209,62 @@ class Question(models.Model): def get_latest_revision(self):
return self.revisions.all()[0]
+ def get_update_summary(self,last_reported_at=None,recipient_email=''):
+ edited = False
+ if self.last_edited_at and self.last_edited_at > last_reported_at:
+ if self.last_edited_by.email != recipient_email:
+ edited = True
+ comments = []
+ for comment in self.comments.all():
+ if comment.added_at > last_reported_at and comment.user.email != recipient_email:
+ comments.append(comment)
+ new_answers = []
+ answer_comments = []
+ modified_answers = []
+ commented_answers = []
+ import sets
+ commented_answers = sets.Set([])
+ for answer in self.answers.all():
+ if (answer.added_at > last_reported_at and answer.author.email != recipient_email):
+ new_answers.append(answer)
+ if (answer.last_edited_at
+ and answer.last_edited_at > last_reported_at
+ and answer.last_edited_by.email != recipient_email):
+ modified_answers.append(answer)
+ for comment in answer.comments.all():
+ if comment.added_at > last_reported_at and comment.user.email != recipient_email:
+ commented_answers.add(answer)
+ answer_comments.append(comment)
+
+ #create the report
+ if edited or comments or new_answers or modified_answers or answer_comments:
+ out = []
+ if edited:
+ out.append(_('%(author)s modified the question') % {'author':self.last_edited_by.username})
+ if new_answers:
+ names = sets.Set(map(lambda x: x.author.username,new_answers))
+ people = ', '.join(names)
+ out.append(_('%(people)s posted %(new_answer_count)s new answers') \
+ % {'new_answer_count':len(new_answers),'people':people})
+ if comments:
+ names = sets.Set(map(lambda x: x.user.username,comments))
+ people = ', '.join(names)
+ out.append(_('%(people)s commented the question') % {'people':people})
+ if answer_comments:
+ names = sets.Set(map(lambda x: x.user.username,answer_comments))
+ people = ', '.join(names)
+ if len(commented_answers) > 1:
+ out.append(_('%(people)s commented answers') % {'people':people})
+ else:
+ out.append(_('%(people)s commented an answer') % {'people':people})
+ url = settings.APP_URL + self.get_absolute_url()
+ retval = '<a href="%s">%s</a>:<br>\n' % (url,self.title)
+ out = map(lambda x: '<li>' + x + '</li>',out)
+ retval += '<ul>' + '\n'.join(out) + '</ul><br>\n'
+ return retval
+ else:
+ return None
+
def __unicode__(self):
return self.title
@@ -227,6 +303,44 @@ class QuestionRevision(models.Model): def __unicode__(self):
return u'revision %s of %s' % (self.revision, self.title)
+class AnonymousAnswer(models.Model):
+ question = models.ForeignKey(Question, related_name='anonymous_answers')
+ session_key = models.CharField(max_length=40) #session id for anonymous questions
+ wiki = models.BooleanField(default=False)
+ added_at = models.DateTimeField(default=datetime.datetime.now)
+ ip_addr = models.IPAddressField(max_length=21) #allow high port numbers
+ author = models.ForeignKey(User,null=True)
+ text = models.TextField()
+ summary = models.CharField(max_length=180)
+
+ def publish(self,user):
+ from forum.views import create_new_answer
+ added_at = datetime.datetime.now()
+ print user.id
+ create_new_answer(question=self.question,wiki=self.wiki,
+ added_at=added_at,text=self.text,
+ author=user)
+ self.delete()
+
+class AnonymousQuestion(models.Model):
+ title = models.CharField(max_length=300)
+ session_key = models.CharField(max_length=40) #session id for anonymous questions
+ text = models.TextField()
+ summary = models.CharField(max_length=180)
+ tagnames = models.CharField(max_length=125)
+ wiki = models.BooleanField(default=False)
+ added_at = models.DateTimeField(default=datetime.datetime.now)
+ ip_addr = models.IPAddressField(max_length=21) #allow high port numbers
+ author = models.ForeignKey(User,null=True)
+
+ def publish(self,user):
+ from forum.views import create_new_question
+ added_at = datetime.datetime.now()
+ create_new_question(title=self.title, author=user, added_at=added_at,
+ wiki=self.wiki, tagnames=self.tagnames,
+ summary=self.summary, text=self.text)
+ self.delete()
+
class Answer(models.Model):
question = models.ForeignKey(Question, related_name='answers')
author = models.ForeignKey(User, related_name='answers')
@@ -455,6 +569,13 @@ class BookAuthorRss(models.Model): class Meta:
db_table = u'book_author_rss'
+class AnonymousEmail(models.Model):
+ #validation key, if used
+ key = models.CharField(max_length=32)
+ email = models.EmailField(null=False,unique=True)
+ isvalid = models.BooleanField(default=False)
+ feeds = generic.GenericRelation(EmailFeed)
+
# User extend properties
QUESTIONS_PER_PAGE_CHOICES = (
(10, u'10'),
@@ -462,8 +583,11 @@ QUESTIONS_PER_PAGE_CHOICES = ( (50, u'50'),
)
+User.add_to_class('email_isvalid', models.BooleanField(default=False))
+User.add_to_class('email_key', models.CharField(max_length=16, null=True))
User.add_to_class('reputation', models.PositiveIntegerField(default=1))
User.add_to_class('gravatar', models.CharField(max_length=32))
+User.add_to_class('email_feeds', generic.GenericRelation(EmailFeed))
User.add_to_class('favorite_questions',
models.ManyToManyField(Question, through=FavoriteQuestion,
related_name='favorited_by'))
@@ -488,11 +612,14 @@ edit_question_or_answer = django.dispatch.Signal(providing_args=["instance", "mo delete_post_or_answer = django.dispatch.Signal(providing_args=["instance", "deleted_by"])
mark_offensive = django.dispatch.Signal(providing_args=["instance", "mark_by"])
user_updated = django.dispatch.Signal(providing_args=["instance", "updated_by"])
+user_logged_in = django.dispatch.Signal(providing_args=["session"])
+
+
def get_messages(self):
- messages = []
- for m in self.message_set.all():
- messages.append(m.message)
- return messages
+ messages = []
+ for m in self.message_set.all():
+ messages.append(m.message)
+ return messages
def delete_messages(self):
self.message_set.all().delete()
@@ -525,12 +652,7 @@ def record_comment_event(instance, created, **kwargs): from django.contrib.contenttypes.models import ContentType
question_type = ContentType.objects.get_for_model(Question)
question_type_id = question_type.id
- #python 2.4 issues - Adolfo Fitoria
- #type = TYPE_ACTIVITY_COMMENT_QUESTION if instance.content_type_id == question_type_id else TYPE_ACTIVITY_COMMENT_ANSWER
- if (instance.content_type_id == question_type_id):
- type = TYPE_ACTIVITY_COMMENT_QUESTION
- else:
- type = TYPE_ACTIVITY_COMMENT_ANSWER
+ type = TYPE_ACTIVITY_COMMENT_QUESTION if instance.content_type_id == question_type_id else TYPE_ACTIVITY_COMMENT_ANSWER
activity = Activity(user=instance.user, active_at=instance.added_at, content_object=instance, activity_type=type)
activity.save()
@@ -645,6 +767,24 @@ def record_user_full_updated(instance, **kwargs): activity = Activity(user=instance, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_USER_FULL_UPDATED)
activity.save()
+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)
+ import settings
+ if settings.EMAIL_VALIDATION == 'on':#add user to the record
+ for aq in aq_list:
+ aq.author = user
+ aq.save()
+ for aa in aa_list:
+ aa.author = user
+ aa.save()
+ #maybe add pending posts message?
+ else: #just publish the questions
+ for aq in aq_list:
+ aq.publish(user)
+ for aa in aa_list:
+ aa.publish(user)
+
#signal for User modle save changes
pre_save.connect(calculate_gravatar_hash, sender=User)
post_save.connect(record_ask_event, sender=Question)
@@ -665,807 +805,4 @@ mark_offensive.connect(record_mark_offensive, sender=Answer) tags_updated.connect(record_update_tags, sender=Question)
post_save.connect(record_favorite_question, sender=FavoriteQuestion)
user_updated.connect(record_user_full_updated, sender=User)
-======= -# encoding:utf-8 -import datetime -import hashlib -from urllib import quote_plus, urlencode -from django.db import models -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.template.defaultfilters import slugify -from django.db.models.signals import post_delete, post_save, pre_save -from django.utils.translation import ugettext as _ -import django.dispatch -import settings - -from forum.managers import * -from const import * - -class EmailFeed(models.Model): - #subscription key for unsubscribe by visiting emailed link - key = models.CharField(max_length=32) - #generic relation with feed content (i.e. question or tags) - feed_content_type = models.ForeignKey(ContentType,related_name='content_emailfeed') - feed_id = models.PositiveIntegerField() - content = generic.GenericForeignKey('feed_content_type','feed_id') - #generic relation with owner - either nameless email or User - subscriber_content_type = models.ForeignKey(ContentType,related_name='subscriber_emailfeed') - subscriber_id = models.PositiveIntegerField() - subscriber = generic.GenericForeignKey('subscriber_content_type','subscriber_id') - added_at = models.DateTimeField(default=datetime.datetime.now) - reported_at = models.DateTimeField(default=datetime.datetime.now) - - #getter functions rely on implementations of similar functions in content - #of subscriber objects - def get_update_summary(self): - return self.content.get_update_summary(last_reported_at = self.reported_at,recipient_email = self.get_email()) - - def get_email(self): - return self.subscriber.email - -class Tag(models.Model): - name = models.CharField(max_length=255, unique=True) - created_by = models.ForeignKey(User, related_name='created_tags') - deleted = models.BooleanField(default=False) - deleted_at = models.DateTimeField(null=True, blank=True) - deleted_by = models.ForeignKey(User, null=True, blank=True, related_name='deleted_tags') - email_feeds = generic.GenericRelation(EmailFeed) - # Denormalised data - used_count = models.PositiveIntegerField(default=0) - - objects = TagManager() - - class Meta: - db_table = u'tag' - ordering = ('-used_count', 'name') - - def __unicode__(self): - return self.name - -class Comment(models.Model): - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') - user = models.ForeignKey(User, related_name='comments') - comment = models.CharField(max_length=300) - added_at = models.DateTimeField(default=datetime.datetime.now) - - class Meta: - ordering = ('-added_at',) - db_table = u'comment' - def __unicode__(self): - return self.comment - -class Vote(models.Model): - VOTE_UP = +1 - VOTE_DOWN = -1 - VOTE_CHOICES = ( - (VOTE_UP, u'Up'), - (VOTE_DOWN, u'Down'), - ) - - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') - user = models.ForeignKey(User, related_name='votes') - vote = models.SmallIntegerField(choices=VOTE_CHOICES) - voted_at = models.DateTimeField(default=datetime.datetime.now) - - objects = VoteManager() - - class Meta: - unique_together = ('content_type', 'object_id', 'user') - db_table = u'vote' - def __unicode__(self): - return '[%s] voted at %s: %s' %(self.user, self.voted_at, self.vote) - - def is_upvote(self): - return self.vote == self.VOTE_UP - - def is_downvote(self): - return self.vote == self.VOTE_DOWN - -class FlaggedItem(models.Model): - """A flag on a Question or Answer indicating offensive content.""" - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') - user = models.ForeignKey(User, related_name='flagged_items') - flagged_at = models.DateTimeField(default=datetime.datetime.now) - - objects = FlaggedItemManager() - - class 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 Question(models.Model): - title = models.CharField(max_length=300) - author = models.ForeignKey(User, related_name='questions') - added_at = models.DateTimeField(default=datetime.datetime.now) - tags = models.ManyToManyField(Tag, related_name='questions') - # Status - wiki = models.BooleanField(default=False) - wikified_at = models.DateTimeField(null=True, blank=True) - answer_accepted = models.BooleanField(default=False) - closed = models.BooleanField(default=False) - closed_by = models.ForeignKey(User, null=True, blank=True, related_name='closed_questions') - closed_at = models.DateTimeField(null=True, blank=True) - close_reason = models.SmallIntegerField(choices=CLOSE_REASONS, null=True, blank=True) - deleted = models.BooleanField(default=False) - deleted_at = models.DateTimeField(null=True, blank=True) - deleted_by = models.ForeignKey(User, null=True, blank=True, related_name='deleted_questions') - locked = models.BooleanField(default=False) - locked_by = models.ForeignKey(User, null=True, blank=True, related_name='locked_questions') - locked_at = models.DateTimeField(null=True, blank=True) - # Denormalised data - score = models.IntegerField(default=0) - vote_up_count = models.IntegerField(default=0) - vote_down_count = models.IntegerField(default=0) - answer_count = models.PositiveIntegerField(default=0) - comment_count = models.PositiveIntegerField(default=0) - view_count = models.PositiveIntegerField(default=0) - offensive_flag_count = models.SmallIntegerField(default=0) - favourite_count = models.PositiveIntegerField(default=0) - last_edited_at = models.DateTimeField(null=True, blank=True) - last_edited_by = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_questions') - last_activity_at = models.DateTimeField(default=datetime.datetime.now) - last_activity_by = models.ForeignKey(User, related_name='last_active_in_questions') - tagnames = models.CharField(max_length=125) - summary = models.CharField(max_length=180) - html = models.TextField() - comments = generic.GenericRelation(Comment) - votes = generic.GenericRelation(Vote) - flagged_items = generic.GenericRelation(FlaggedItem) - email_feeds = generic.GenericRelation(EmailFeed) - - objects = QuestionManager() - - def save(self, **kwargs): - """ - Overridden to manually manage addition of tags when the object - is first saved. - - 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) - if initial_addition: - tags = Tag.objects.get_or_create_multiple(self.tagname_list(), - self.author) - self.tags.add(*tags) - Tag.objects.update_use_counts(tags) - - def tagname_list(self): - """Creates a list of Tag names from the ``tagnames`` attribute.""" - return [name for name in self.tagnames.split(u' ')] - - def get_absolute_url(self): - return '%s%s' % (reverse('question', args=[self.id]), self.title.replace(' ', '-')) - - def has_favorite_by_user(self, user): - if not user.is_authenticated(): - return False - return FavoriteQuestion.objects.filter(question=self, user=user).count() > 0 - - def get_answer_count_by_user(self, user_id): - query_set = Answer.objects.filter(author__id=user_id) - return query_set.filter(question=self).count() - - def get_question_title(self): - if self.closed: - attr = CONST['closed'] - elif self.deleted: - attr = CONST['deleted'] - else: - attr = None - if attr is not None: - return u'%s %s' % (self.title, attr) - else: - return self.title - - def get_revision_url(self): - return reverse('question_revisions', args=[self.id]) - - def get_latest_revision(self): - return self.revisions.all()[0] - - def get_update_summary(self,last_reported_at=None,recipient_email=''): - edited = False - if self.last_edited_at and self.last_edited_at > last_reported_at: - if self.last_edited_by.email != recipient_email: - edited = True - comments = [] - for comment in self.comments.all(): - if comment.added_at > last_reported_at and comment.user.email != recipient_email: - comments.append(comment) - new_answers = [] - answer_comments = [] - modified_answers = [] - for answer in self.answers.all(): - if (answer.added_at > last_reported_at): - new_answers.append(answer) - if (answer.last_edited_at - and answer.last_edited_at > last_reported_at - and answer.last_edited_by.email != recipient_email): - modified_answers.append(answer) - for comment in answer.comments.all(): - if comment.added_at > last_reported_at and comment.user.email != recipient_email: - answer_comments.append(comment) - if edited or comments or new_answers or modified_answers or answer_comments: - import sets - out = [] - if edited: - out.append(_('%(author)s modified the question') % {'author':self.last_edited_by.username}) - if new_answers: - names = sets.Set(map(lambda x: x.author.username,new_answers)) - people = ', '.join(names) - out.append(_('%(people)s posted %(new_answer_count)s new answers') \ - % {'new_answer_count':len(new_answers),'people':people}) - if comments: - names = sets.Set(map(lambda x: x.user.username,comments)) - people = ', '.join(names) - out.append(_('%(people)s commented the question') % {'people':people}) - if answer_comments: - names = sets.Set(map(lambda x: x.user.username,answer_comments)) - people = ', '.join(names) - if len(answer_comments) > 1: - out.append(_('%(people)s commented answers') % {'people':people}) - else: - out.append(_('%(people)s commented the answer') % {'people':people}) - url = settings.APP_URL + self.get_absolute_url() - retval = '<a href="%s">%s</a>:<br>\n' % (url,self.title) - out = map(lambda x: '<li>' + x + '</li>',out) - retval += '<ul>' + '\n'.join(out) + '</ul><br>\n' - return retval - else: - return None - - def __unicode__(self): - return self.title - - class Meta: - db_table = u'question' - -class QuestionRevision(models.Model): - """A revision of a Question.""" - question = models.ForeignKey(Question, related_name='revisions') - revision = models.PositiveIntegerField(blank=True) - title = models.CharField(max_length=300) - author = models.ForeignKey(User, related_name='question_revisions') - revised_at = models.DateTimeField() - tagnames = models.CharField(max_length=125) - summary = models.CharField(max_length=300, blank=True) - text = models.TextField() - - class Meta: - db_table = u'question_revision' - ordering = ('-revision',) - - def get_question_title(self): - return self.question.title - - def get_absolute_url(self): - return '/questions/%s/revisions' % (self.question.id) - - def save(self, **kwargs): - """Looks up the next available revision number.""" - if not self.revision: - self.revision = QuestionRevision.objects.filter( - question=self.question).values_list('revision', - flat=True)[0] + 1 - super(QuestionRevision, self).save(**kwargs) - - def __unicode__(self): - return u'revision %s of %s' % (self.revision, self.title) - -class AnonymousAnswer(models.Model): - question = models.ForeignKey(Question, related_name='anonymous_answers') - session_key = models.CharField(max_length=40) #session id for anonymous questions - wiki = models.BooleanField(default=False) - added_at = models.DateTimeField(default=datetime.datetime.now) - ip_addr = models.IPAddressField(max_length=21) #allow high port numbers - author = models.ForeignKey(User,null=True) - text = models.TextField() - summary = models.CharField(max_length=180) - - def publish(self,user): - from forum.views import create_new_answer - added_at = datetime.datetime.now() - print user.id - create_new_answer(question=self.question,wiki=self.wiki, - added_at=added_at,text=self.text, - author=user) - self.delete() - -class AnonymousQuestion(models.Model): - title = models.CharField(max_length=300) - session_key = models.CharField(max_length=40) #session id for anonymous questions - text = models.TextField() - summary = models.CharField(max_length=180) - tagnames = models.CharField(max_length=125) - wiki = models.BooleanField(default=False) - added_at = models.DateTimeField(default=datetime.datetime.now) - ip_addr = models.IPAddressField(max_length=21) #allow high port numbers - author = models.ForeignKey(User,null=True) - - def publish(self,user): - from forum.views import create_new_question - added_at = datetime.datetime.now() - create_new_question(title=self.title, author=user, added_at=added_at, - wiki=self.wiki, tagnames=self.tagnames, - summary=self.summary, text=self.text) - self.delete() - -class Answer(models.Model): - question = models.ForeignKey(Question, related_name='answers') - author = models.ForeignKey(User, related_name='answers') - added_at = models.DateTimeField(default=datetime.datetime.now) - # Status - wiki = models.BooleanField(default=False) - wikified_at = models.DateTimeField(null=True, blank=True) - accepted = models.BooleanField(default=False) - accepted_at = models.DateTimeField(null=True, blank=True) - deleted = models.BooleanField(default=False) - deleted_by = models.ForeignKey(User, null=True, blank=True, related_name='deleted_answers') - locked = models.BooleanField(default=False) - locked_by = models.ForeignKey(User, null=True, blank=True, related_name='locked_answers') - locked_at = models.DateTimeField(null=True, blank=True) - # Denormalised data - score = models.IntegerField(default=0) - vote_up_count = models.IntegerField(default=0) - vote_down_count = models.IntegerField(default=0) - comment_count = models.PositiveIntegerField(default=0) - offensive_flag_count = models.SmallIntegerField(default=0) - last_edited_at = models.DateTimeField(null=True, blank=True) - last_edited_by = models.ForeignKey(User, null=True, blank=True, related_name='last_edited_answers') - html = models.TextField() - comments = generic.GenericRelation(Comment) - votes = generic.GenericRelation(Vote) - flagged_items = generic.GenericRelation(FlaggedItem) - - objects = AnswerManager() - - def get_user_vote(self, user): - votes = self.votes.filter(user=user) - if votes.count() > 0: - return votes[0] - else: - return None - - def get_latest_revision(self): - return self.revisions.all()[0] - - def get_question_title(self): - return self.question.title - - def get_absolute_url(self): - return '%s%s#%s' % (reverse('question', args=[self.question.id]), self.question.title, self.id) - - class Meta: - db_table = u'answer' - - def __unicode__(self): - return self.html - -class AnswerRevision(models.Model): - """A revision of an Answer.""" - answer = models.ForeignKey(Answer, related_name='revisions') - revision = models.PositiveIntegerField() - author = models.ForeignKey(User, related_name='answer_revisions') - revised_at = models.DateTimeField() - summary = models.CharField(max_length=300, blank=True) - text = models.TextField() - - def get_absolute_url(self): - return '/answers/%s/revisions' % (self.answer.id) - - def get_question_title(self): - return self.answer.question.title - - class Meta: - db_table = u'answer_revision' - ordering = ('-revision',) - - def save(self, **kwargs): - """Looks up the next available revision number if not set.""" - if not self.revision: - self.revision = AnswerRevision.objects.filter( - answer=self.answer).values_list('revision', - flat=True)[0] + 1 - super(AnswerRevision, self).save(**kwargs) - -class FavoriteQuestion(models.Model): - """A favorite Question of a User.""" - question = models.ForeignKey(Question) - user = models.ForeignKey(User, related_name='user_favorite_questions') - added_at = models.DateTimeField(default=datetime.datetime.now) - class Meta: - db_table = u'favorite_question' - def __unicode__(self): - return '[%s] favorited at %s' %(self.user, self.added_at) - -class Badge(models.Model): - """Awarded for notable actions performed on the site by Users.""" - GOLD = 1 - SILVER = 2 - BRONZE = 3 - TYPE_CHOICES = ( - (GOLD, _('gold')), - (SILVER, _('silver')), - (BRONZE, _('bronze')), - ) - - name = models.CharField(max_length=50) - type = models.SmallIntegerField(choices=TYPE_CHOICES) - slug = models.SlugField(max_length=50, blank=True) - description = models.CharField(max_length=300) - multiple = models.BooleanField(default=False) - # Denormalised data - awarded_count = models.PositiveIntegerField(default=0) - - class Meta: - db_table = u'badge' - ordering = ('name',) - unique_together = ('name', 'type') - - def __unicode__(self): - return u'%s: %s' % (self.get_type_display(), self.name) - - def save(self, **kwargs): - if not self.slug: - self.slug = self.name#slugify(self.name) - super(Badge, self).save(**kwargs) - - def get_absolute_url(self): - return '%s%s/' % (reverse('badge', args=[self.id]), self.slug) - -class Award(models.Model): - """The awarding of a Badge to a User.""" - user = models.ForeignKey(User, related_name='award_user') - badge = models.ForeignKey(Badge, related_name='award_badge') - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') - awarded_at = models.DateTimeField(default=datetime.datetime.now) - notified = models.BooleanField(default=False) - objects = AwardManager() - - def __unicode__(self): - return u'[%s] is awarded a badge [%s] at %s' % (self.user.username, self.badge.name, self.awarded_at) - - class Meta: - db_table = u'award' - -class Repute(models.Model): - """The reputation histories for user""" - user = models.ForeignKey(User) - positive = models.SmallIntegerField(default=0) - negative = models.SmallIntegerField(default=0) - question = models.ForeignKey(Question) - reputed_at = models.DateTimeField(default=datetime.datetime.now) - reputation_type = models.SmallIntegerField(choices=TYPE_REPUTATION) - reputation = models.IntegerField(default=1) - objects = ReputeManager() - - def __unicode__(self): - return u'[%s]\' reputation changed at %s' % (self.user.username, self.reputed_at) - - class Meta: - db_table = u'repute' - -class Activity(models.Model): - """ - We keep some history data for user activities - """ - user = models.ForeignKey(User) - activity_type = models.SmallIntegerField(choices=TYPE_ACTIVITY) - active_at = models.DateTimeField(default=datetime.datetime.now) - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') - is_auditted = models.BooleanField(default=False) - - def __unicode__(self): - return u'[%s] was active at %s' % (self.user.username, self.active_at) - - class Meta: - db_table = u'activity' - -class Book(models.Model): - """ - Model for book info - """ - user = models.ForeignKey(User) - title = models.CharField(max_length=255) - short_name = models.CharField(max_length=255) - author = models.CharField(max_length=255) - price = models.DecimalField(max_digits=6, decimal_places=2) - pages = models.SmallIntegerField() - published_at = models.DateTimeField() - publication = models.CharField(max_length=255) - cover_img = models.CharField(max_length=255) - tagnames = models.CharField(max_length=125) - added_at = models.DateTimeField() - last_edited_at = models.DateTimeField() - questions = models.ManyToManyField(Question, related_name='book', db_table='book_question') - - def get_absolute_url(self): - return '%s' % reverse('book', args=[self.short_name]) - - def __unicode__(self): - return self.title - class Meta: - db_table = u'book' - -class BookAuthorInfo(models.Model): - """ - Model for book author info - """ - user = models.ForeignKey(User) - book = models.ForeignKey(Book) - blog_url = models.CharField(max_length=255) - added_at = models.DateTimeField() - last_edited_at = models.DateTimeField() - - class Meta: - db_table = u'book_author_info' - -class BookAuthorRss(models.Model): - """ - Model for book author blog rss - """ - user = models.ForeignKey(User) - book = models.ForeignKey(Book) - title = models.CharField(max_length=255) - url = models.CharField(max_length=255) - rss_created_at = models.DateTimeField() - added_at = models.DateTimeField() - - class Meta: - db_table = u'book_author_rss' - -class AnonymousEmail(models.Model): - #validation key, if used - key = models.CharField(max_length=32) - email = models.EmailField(null=False,unique=True) - isvalid = models.BooleanField(default=False) - feeds = generic.GenericRelation(EmailFeed) - -# User extend properties -QUESTIONS_PER_PAGE_CHOICES = ( - (10, u'10'), - (30, u'30'), - (50, u'50'), -) - -User.add_to_class('email_isvalid', models.BooleanField(default=False)) -User.add_to_class('email_key', models.CharField(max_length=16, null=True)) -User.add_to_class('reputation', models.PositiveIntegerField(default=1)) -User.add_to_class('gravatar', models.CharField(max_length=32)) -User.add_to_class('email_feeds', generic.GenericRelation(EmailFeed)) -User.add_to_class('favorite_questions', - models.ManyToManyField(Question, through=FavoriteQuestion, - related_name='favorited_by')) -User.add_to_class('badges', models.ManyToManyField(Badge, through=Award, - related_name='awarded_to')) -User.add_to_class('gold', models.SmallIntegerField(default=0)) -User.add_to_class('silver', models.SmallIntegerField(default=0)) -User.add_to_class('bronze', models.SmallIntegerField(default=0)) -User.add_to_class('questions_per_page', - models.SmallIntegerField(choices=QUESTIONS_PER_PAGE_CHOICES, default=10)) -User.add_to_class('last_seen', - models.DateTimeField(default=datetime.datetime.now)) -User.add_to_class('real_name', models.CharField(max_length=100, blank=True)) -User.add_to_class('website', models.URLField(max_length=200, blank=True)) -User.add_to_class('location', models.CharField(max_length=100, blank=True)) -User.add_to_class('date_of_birth', models.DateField(null=True, blank=True)) -User.add_to_class('about', models.TextField(blank=True)) - -# custom signal -tags_updated = django.dispatch.Signal(providing_args=["question"]) -edit_question_or_answer = django.dispatch.Signal(providing_args=["instance", "modified_by"]) -delete_post_or_answer = django.dispatch.Signal(providing_args=["instance", "deleted_by"]) -mark_offensive = django.dispatch.Signal(providing_args=["instance", "mark_by"]) -user_updated = django.dispatch.Signal(providing_args=["instance", "updated_by"]) -user_logged_in = django.dispatch.Signal(providing_args=["session"]) - - -def get_messages(self): - messages = [] - for m in self.message_set.all(): - messages.append(m.message) - return messages - -def delete_messages(self): - self.message_set.all().delete() - -def get_profile_url(self): - """Returns the URL for this User's profile.""" - return '%s%s/' % (reverse('user', args=[self.id]), self.username) -User.add_to_class('get_profile_url', get_profile_url) -User.add_to_class('get_messages', get_messages) -User.add_to_class('delete_messages', delete_messages) - -def calculate_gravatar_hash(instance, **kwargs): - """Calculates a User's gravatar hash from their email address.""" - if kwargs.get('raw', False): - return - instance.gravatar = hashlib.md5(instance.email).hexdigest() - -def record_ask_event(instance, created, **kwargs): - if created: - activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ASK_QUESTION) - activity.save() - -def record_answer_event(instance, created, **kwargs): - if created: - activity = Activity(user=instance.author, active_at=instance.added_at, content_object=instance, activity_type=TYPE_ACTIVITY_ANSWER) - activity.save() - -def record_comment_event(instance, created, **kwargs): - if created: - from django.contrib.contenttypes.models import ContentType - question_type = ContentType.objects.get_for_model(Question) - question_type_id = question_type.id - type = TYPE_ACTIVITY_COMMENT_QUESTION if instance.content_type_id == question_type_id else TYPE_ACTIVITY_COMMENT_ANSWER - activity = Activity(user=instance.user, active_at=instance.added_at, content_object=instance, activity_type=type) - activity.save() - -def record_revision_question_event(instance, created, **kwargs): - if created and instance.revision <> 1: - activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_QUESTION) - activity.save() - -def record_revision_answer_event(instance, created, **kwargs): - if created and instance.revision <> 1: - activity = Activity(user=instance.author, active_at=instance.revised_at, content_object=instance, activity_type=TYPE_ACTIVITY_UPDATE_ANSWER) - activity.save() - -def record_award_event(instance, created, **kwargs): - """ - After we awarded a badge to user, we need to record this activity and notify user. - We also recaculate awarded_count of this badge and user information. - """ - if created: - activity = Activity(user=instance.user, active_at=instance.awarded_at, content_object=instance, - activity_type=TYPE_ACTIVITY_PRIZE) - activity.save() - - instance.badge.awarded_count += 1 - instance.badge.save() - - if instance.badge.type == Badge.GOLD: - instance.user.gold += 1 - if instance.badge.type == Badge.SILVER: - instance.user.silver += 1 - if instance.badge.type == Badge.BRONZE: - instance.user.bronze += 1 - instance.user.save() - -def notify_award_message(instance, created, **kwargs): - """ - Notify users when they have been awarded badges by using Django message. - """ - if created: - user = instance.user - user.message_set.create(message=u"%s" % instance.badge.name) - -def record_answer_accepted(instance, created, **kwargs): - """ - when answer is accepted, we record this for question author - who accepted it. - """ - if not created and instance.accepted: - activity = Activity(user=instance.question.author, active_at=datetime.datetime.now(), \ - content_object=instance, activity_type=TYPE_ACTIVITY_MARK_ANSWER) - activity.save() - -def update_last_seen(instance, created, **kwargs): - """ - when user has activities, we update 'last_seen' time stamp for him - """ - user = instance.user - user.last_seen = datetime.datetime.now() - user.save() - -def record_vote(instance, created, **kwargs): - """ - when user have voted - """ - if created: - if instance.vote == 1: - vote_type = TYPE_ACTIVITY_VOTE_UP - else: - vote_type = TYPE_ACTIVITY_VOTE_DOWN - - activity = Activity(user=instance.user, active_at=instance.voted_at, content_object=instance, activity_type=vote_type) - activity.save() - -def record_cancel_vote(instance, **kwargs): - """ - when user canceled vote, the vote will be deleted. - """ - activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_CANCEL_VOTE) - activity.save() - -def record_delete_question(instance, delete_by, **kwargs): - """ - when user deleted the question - """ - if instance.__class__ == "Question": - activity_type = TYPE_ACTIVITY_DELETE_QUESTION - else: - activity_type = TYPE_ACTIVITY_DELETE_ANSWER - - activity = Activity(user=delete_by, active_at=datetime.datetime.now(), content_object=instance, activity_type=activity_type) - activity.save() - -def record_mark_offensive(instance, mark_by, **kwargs): - activity = Activity(user=mark_by, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_MARK_OFFENSIVE) - activity.save() - -def record_update_tags(question, **kwargs): - """ - when user updated tags of the question - """ - activity = Activity(user=question.author, active_at=datetime.datetime.now(), content_object=question, activity_type=TYPE_ACTIVITY_UPDATE_TAGS) - activity.save() - -def record_favorite_question(instance, created, **kwargs): - """ - when user add the question in him favorite questions list. - """ - if created: - activity = Activity(user=instance.user, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_FAVORITE) - activity.save() - -def record_user_full_updated(instance, **kwargs): - activity = Activity(user=instance, active_at=datetime.datetime.now(), content_object=instance, activity_type=TYPE_ACTIVITY_USER_FULL_UPDATED) - activity.save() - -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) - import settings - if settings.EMAIL_VALIDATION == 'on':#add user to the record - for aq in aq_list: - aq.author = user - aq.save() - for aa in aa_list: - aa.author = user - aa.save() - #maybe add pending posts message? - else: #just publish the questions - for aq in aq_list: - aq.publish(user) - for aa in aa_list: - aa.publish(user) - -#signal for User modle save changes -pre_save.connect(calculate_gravatar_hash, sender=User) -post_save.connect(record_ask_event, sender=Question) -post_save.connect(record_answer_event, sender=Answer) -post_save.connect(record_comment_event, sender=Comment) -post_save.connect(record_revision_question_event, sender=QuestionRevision) -post_save.connect(record_revision_answer_event, sender=AnswerRevision) -post_save.connect(record_award_event, sender=Award) -post_save.connect(notify_award_message, sender=Award) -post_save.connect(record_answer_accepted, sender=Answer) -post_save.connect(update_last_seen, sender=Activity) -post_save.connect(record_vote, sender=Vote) -post_delete.connect(record_cancel_vote, sender=Vote) -delete_post_or_answer.connect(record_delete_question, sender=Question) -delete_post_or_answer.connect(record_delete_question, sender=Answer) -mark_offensive.connect(record_mark_offensive, sender=Question) -mark_offensive.connect(record_mark_offensive, sender=Answer) -tags_updated.connect(record_update_tags, sender=Question) -post_save.connect(record_favorite_question, sender=FavoriteQuestion) -user_updated.connect(record_user_full_updated, sender=User) -user_logged_in.connect(post_stored_anonymous_content) +user_logged_in.connect(post_stored_anonymous_content)
diff --git a/forum/views.py b/forum/views.py index 5a6499eb..6ef7bd6d 100644 --- a/forum/views.py +++ b/forum/views.py @@ -1,1968 +1,3 @@ -# encoding:utf-8
-import os.path
-import time, datetime, calendar, random
-import logging
-from urllib import quote, unquote
-from django.conf import settings
-from django.core.files.storage import default_storage
-from django.shortcuts import render_to_response, get_object_or_404
-from django.contrib.auth.decorators import login_required
-from django.http import HttpResponseRedirect, HttpResponse,Http404
-from django.core.paginator import Paginator, EmptyPage, InvalidPage
-from django.template import RequestContext
-from django.utils.html import *
-from django.utils import simplejson
-from django.core import serializers
-from django.db import transaction
-from django.contrib.contenttypes.models import ContentType
-from django.utils.translation import ugettext as _
-
-from utils.html import sanitize_html
-from markdown2 import Markdown
-#from lxml.html.diff import htmldiff
-from forum.diff import textDiff as htmldiff
-from forum.forms import *
-from forum.models import *
-from forum.auth import *
-from forum.const import *
-from forum.user import *
-from forum import auth
-
-# used in index page
-INDEX_PAGE_SIZE = 20
-INDEX_AWARD_SIZE = 15
-INDEX_TAGS_SIZE = 100
-# used in tags list
-DEFAULT_PAGE_SIZE = 60
-# used in questions
-QUESTIONS_PAGE_SIZE = 10
-# used in users
-USERS_PAGE_SIZE = 35
-# used in answers
-ANSWERS_PAGE_SIZE = 10
-markdowner = Markdown(html4tags=True)
-question_type = ContentType.objects.get_for_model(Question)
-answer_type = ContentType.objects.get_for_model(Answer)
-comment_type = ContentType.objects.get_for_model(Comment)
-question_revision_type = ContentType.objects.get_for_model(QuestionRevision)
-answer_revision_type = ContentType.objects.get_for_model(AnswerRevision)
-repute_type =ContentType.objects.get_for_model(Repute)
-question_type_id = question_type.id
-answer_type_id = answer_type.id
-comment_type_id = comment_type.id
-question_revision_type_id = question_revision_type.id
-answer_revision_type_id = answer_revision_type.id
-repute_type_id = repute_type.id
-def _get_tags_cache_json():
- tags = Tag.objects.filter(deleted=False).all()
- tags_list = []
- for tag in tags:
- dic = {'n': tag.name, 'c': tag.used_count }
- tags_list.append(dic)
- tags = simplejson.dumps(tags_list)
- return tags
-
-def index(request):
- view_id = request.GET.get('sort', None)
- view_dic = {
- "latest":"-last_activity_at",
- "hottest":"-answer_count",
- "mostvoted":"-score",
- "trans": "-last_activity_at"
- }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-last_activity_at"
- # group questions by author_id of 28,29
- if view_id == 'trans':
- questions = Question.objects.get_translation_questions(orderby, INDEX_PAGE_SIZE)
- else:
- questions = Question.objects.get_questions_by_pagesize(orderby, INDEX_PAGE_SIZE)
- # RISK - inner join queries
- questions = questions.select_related()
- tags = Tag.objects.get_valid_tags(INDEX_TAGS_SIZE)
-
- awards = Award.objects.get_recent_awards()
-
- return render_to_response('index.html', {
- "questions" : questions,
- "tab_id" : view_id,
- "tags" : tags,
- "awards" : awards[:INDEX_AWARD_SIZE],
- }, context_instance=RequestContext(request))
-
-def about(request):
- return render_to_response('about.html', context_instance=RequestContext(request))
-
-def faq(request):
- return render_to_response('faq.html', context_instance=RequestContext(request))
-
-def privacy(request):
- return render_to_response('privacy.html', context_instance=RequestContext(request))
-
-def unanswered(request):
- return questions(request, unanswered=True)
-
-def questions(request, tagname=None, unanswered=False):
- """
- List of Questions, Tagged questions, and Unanswered questions.
- """
- # template file
- # "questions.html" or "unanswered.html"
- template_file = "questions.html"
- # Set flag to False by default. If it is equal to True, then need to be saved.
- pagesize_changed = False
- # get pagesize from session, if failed then get default value
- pagesize = request.session.get("pagesize")
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- view_id = request.GET.get('sort', None)
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-added_at"
-
- # check if request is from tagged questions
- if tagname is not None:
- objects = Question.objects.get_questions_by_tag(tagname, orderby)
- elif unanswered:
- #check if request is from unanswered questions
- template_file = "unanswered.html"
- objects = Question.objects.get_unanswered_questions(orderby)
- else:
- objects = Question.objects.get_questions(orderby)
-
- # RISK - inner join queries
- objects = objects.select_related(depth=1);
- objects_list = Paginator(objects, pagesize)
- questions = objects_list.page(page)
-
- # Get related tags from this page objects
- if questions.object_list.count() > 0:
- related_tags = Tag.objects.get_tags_by_questions(questions.object_list)
- else:
- related_tags = None
- return render_to_response(template_file, {
- "questions" : questions,
- "tab_id" : view_id,
- "questions_count" : objects_list.count,
- "tags" : related_tags,
- "searchtag" : tagname,
- "is_unanswered" : unanswered,
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': questions.has_previous(),
- 'has_next': questions.has_next(),
- 'previous': questions.previous_page_number(),
- 'next': questions.next_page_number(),
- 'base_url' : request.path + '?sort=%s&' % view_id,
- 'pagesize' : pagesize
- }}, context_instance=RequestContext(request))
-
-#TODO: allow anynomus user to ask question by providing email and username.
-@login_required
-def ask(request):
- if request.method == "POST":
- form = AskForm(request.POST)
- if form.is_valid():
- added_at = datetime.datetime.now()
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- question = Question(
- title = strip_tags(form.cleaned_data['title']),
- author = request.user,
- added_at = added_at,
- last_activity_at = added_at,
- last_activity_by = request.user,
- wiki = form.cleaned_data['wiki'],
- tagnames = form.cleaned_data['tags'].strip(),
- html = html,
- summary = strip_tags(html)[:120]
- )
- if question.wiki:
- question.last_edited_by = question.author
- question.last_edited_at = added_at
- question.wikified_at = added_at
-
- question.save()
-
- # create the first revision
- QuestionRevision.objects.create(
- question = question,
- revision = 1,
- title = question.title,
- author = request.user,
- revised_at = added_at,
- tagnames = question.tagnames,
- summary = CONST['default_version'],
- text = form.cleaned_data['text']
- )
-
- return HttpResponseRedirect(question.get_absolute_url())
-
- else:
- form = AskForm()
-
- tags = _get_tags_cache_json()
- return render_to_response('ask.html', {
- 'form' : form,
- 'tags' : tags,
- }, context_instance=RequestContext(request))
-
-def question(request, id):
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
- view_id = request.GET.get('sort', 'votes')
- view_dic = {"latest":"-added_at", "oldest":"added_at", "votes":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "votes"
- orderby = "-score"
-
- question = get_object_or_404(Question, id=id)
- if question.deleted and not can_view_deleted_post(request.user, question):
- raise Http404
- answer_form = AnswerForm(question)
- answers = Answer.objects.get_answers_from_question(question, request.user)
- answers = answers.select_related(depth=1)
-
- favorited = question.has_favorite_by_user(request.user)
- question_vote = question.votes.select_related().filter(user=request.user)
- if question_vote is not None and question_vote.count() > 0:
- question_vote = question_vote[0]
-
- user_answer_votes = {}
- for answer in answers:
- vote = answer.get_user_vote(request.user)
- if vote is not None and not user_answer_votes.has_key(answer.id):
- vote_value = -1
- if vote.is_upvote():
- vote_value = 1
- user_answer_votes[answer.id] = vote_value
-
-
- if answers is not None:
- answers = answers.order_by("-accepted", orderby)
- objects_list = Paginator(answers, ANSWERS_PAGE_SIZE)
- page_objects = objects_list.page(page)
- # update view count
- Question.objects.update_view_count(question)
- return render_to_response('question.html', {
- "question" : question,
- "question_vote" : question_vote,
- "question_comment_count":question.comments.count(),
- "answer" : answer_form,
- "answers" : page_objects.object_list,
- "user_answer_votes": user_answer_votes,
- "tags" : question.tags.all(),
- "tab_id" : view_id,
- "favorited" : favorited,
- "similar_questions" : Question.objects.get_similar_questions(question),
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': page_objects.has_previous(),
- 'has_next': page_objects.has_next(),
- 'previous': page_objects.previous_page_number(),
- 'next': page_objects.next_page_number(),
- 'base_url' : request.path + '?sort=%s&' % view_id,
- 'extend_url' : "#sort-top"
- }
- }, context_instance=RequestContext(request))
-
-@login_required
-def close(request, id):
- question = get_object_or_404(Question, id=id)
- if not can_close_question(request.user, question):
- return HttpResponse('Permission denied.')
- if request.method == 'POST':
- form = CloseForm(request.POST)
- if form.is_valid():
- reason = form.cleaned_data['reason']
- question.closed = True
- question.closed_by = request.user
- question.closed_at = datetime.datetime.now()
- question.close_reason = reason
- question.save()
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = CloseForm()
- return render_to_response('close.html', {
- 'form' : form,
- 'question' : question,
- }, context_instance=RequestContext(request))
-
-@login_required
-def reopen(request, id):
- question = get_object_or_404(Question, id=id)
- # open question
- if not can_reopen_question(request.user, question):
- return HttpResponse('Permission denied.')
- if request.method == 'POST' :
- Question.objects.filter(id=question.id).update(closed=False,
- closed_by=None, closed_at=None, close_reason=None)
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- return render_to_response('reopen.html', {
- 'question' : question,
- }, context_instance=RequestContext(request))
-
-@login_required
-def edit_question(request, id):
- question = get_object_or_404(Question, id=id)
- if question.deleted and not can_view_deleted_post(request.user, question):
- raise Http404
- if can_edit_post(request.user, question):
- return _edit_question(request, question)
- elif can_retag_questions(request.user):
- return _retag_question(request, question)
- else:
- raise Http404
-
-def _retag_question(request, question):
- if request.method == 'POST':
- form = RetagQuestionForm(question, request.POST)
- if form.is_valid():
- if form.has_changed():
- latest_revision = question.get_latest_revision()
- retagged_at = datetime.datetime.now()
- # Update the Question itself
- Question.objects.filter(id=question.id).update(
- tagnames = form.cleaned_data['tags'],
- last_edited_at = retagged_at,
- last_edited_by = request.user,
- last_activity_at = retagged_at,
- last_activity_by = request.user
- )
- # Update the Question's tag associations
- tags_updated = Question.objects.update_tags(question,
- form.cleaned_data['tags'], request.user)
- # Create a new revision
- QuestionRevision.objects.create(
- question = question,
- title = latest_revision.title,
- author = request.user,
- revised_at = retagged_at,
- tagnames = form.cleaned_data['tags'],
- summary = CONST['retagged'],
- text = latest_revision.text
- )
- # send tags updated singal
- tags_updated.send(sender=question.__class__, question=question)
-
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = RetagQuestionForm(question)
- return render_to_response('question_retag.html', {
- 'question': question,
- 'form' : form,
- 'tags' : _get_tags_cache_json(),
- }, context_instance=RequestContext(request))
-
-
-def _edit_question(request, question):
- latest_revision = question.get_latest_revision()
- revision_form = None
- if request.method == 'POST':
- if 'select_revision' in request.POST:
- # user has changed revistion number
- revision_form = RevisionForm(question, latest_revision, request.POST)
- if revision_form.is_valid():
- # Replace with those from the selected revision
- form = EditQuestionForm(question,
- QuestionRevision.objects.get(question=question,
- revision=revision_form.cleaned_data['revision']))
- else:
- form = EditQuestionForm(question, latest_revision, request.POST)
- else:
- # Always check modifications against the latest revision
- form = EditQuestionForm(question, latest_revision, request.POST)
- if form.is_valid():
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- if form.has_changed():
- edited_at = datetime.datetime.now()
- tags_changed = (latest_revision.tagnames !=
- form.cleaned_data['tags'])
- tags_updated = False
- # Update the Question itself
- updated_fields = {
- 'title': form.cleaned_data['title'],
- 'last_edited_at': edited_at,
- 'last_edited_by': request.user,
- 'last_activity_at': edited_at,
- 'last_activity_by': request.user,
- 'tagnames': form.cleaned_data['tags'],
- 'summary': strip_tags(html)[:120],
- 'html': html,
- }
-
- # only save when it's checked
- # because wiki doesn't allow to be edited if last version has been enabled already
- # and we make sure this in forms.
- if ('wiki' in form.cleaned_data and
- form.cleaned_data['wiki']):
- updated_fields['wiki'] = True
- updated_fields['wikified_at'] = edited_at
-
- Question.objects.filter(
- id=question.id).update(**updated_fields)
- # Update the Question's tag associations
- if tags_changed:
- tags_updated = Question.objects.update_tags(
- question, form.cleaned_data['tags'], request.user)
- # Create a new revision
- revision = QuestionRevision(
- question = question,
- title = form.cleaned_data['title'],
- author = request.user,
- revised_at = edited_at,
- tagnames = form.cleaned_data['tags'],
- text = form.cleaned_data['text'],
- )
- if form.cleaned_data['summary']:
- revision.summary = form.cleaned_data['summary']
- else:
- revision.summary = 'No.%s Revision' % latest_revision.revision
- revision.save()
-
- return HttpResponseRedirect(question.get_absolute_url())
- else:
-
- revision_form = RevisionForm(question, latest_revision)
- form = EditQuestionForm(question, latest_revision)
- return render_to_response('question_edit.html', {
- 'question': question,
- 'revision_form': revision_form,
- 'form' : form,
- 'tags' : _get_tags_cache_json()
- }, context_instance=RequestContext(request))
-
-
-@login_required
-def edit_answer(request, id):
- answer = get_object_or_404(Answer, id=id)
- if answer.deleted and not can_view_deleted_post(request.user, answer):
- raise Http404
- elif not can_edit_post(request.user, answer):
- raise Http404
- else:
- latest_revision = answer.get_latest_revision()
- if request.method == "POST":
- if 'select_revision' in request.POST:
- # user has changed revistion number
- revision_form = RevisionForm(answer, latest_revision, request.POST)
- if revision_form.is_valid():
- # Replace with those from the selected revision
- form = EditAnswerForm(answer,
- AnswerRevision.objects.get(answer=answer,
- revision=revision_form.cleaned_data['revision']))
- else:
- form = EditAnswerForm(answer, latest_revision, request.POST)
- else:
- form = EditAnswerForm(answer, latest_revision, request.POST)
- if form.is_valid():
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- if form.has_changed():
- edited_at = datetime.datetime.now()
- updated_fields = {
- 'last_edited_at': edited_at,
- 'last_edited_by': request.user,
- 'html': html,
- }
- Answer.objects.filter(id=answer.id).update(**updated_fields)
-
- revision = AnswerRevision(
- answer = answer,
- author = request.user,
- revised_at = edited_at,
- text = form.cleaned_data['text']
- )
-
- if form.cleaned_data['summary']:
- revision.summary = form.cleaned_data['summary']
- else:
- revision.summary = 'No.%s Revision' % latest_revision.revision
- revision.save()
-
- answer.question.last_activity_at = edited_at
- answer.question.last_activity_by = request.user
- answer.question.save()
-
- return HttpResponseRedirect(answer.get_absolute_url())
- else:
- revision_form = RevisionForm(answer, latest_revision)
- form = EditAnswerForm(answer, latest_revision)
- return render_to_response('answer_edit.html', {
- 'answer': answer,
- 'revision_form': revision_form,
- 'form' : form,
- }, context_instance=RequestContext(request))
-
-QUESTION_REVISION_TEMPLATE = ('<h1>%(title)s</h1>\n'
- '<div class="text">%(html)s</div>\n'
- '<div class="tags">%(tags)s</div>')
-def question_revisions(request, id):
- post = get_object_or_404(Question, id=id)
- revisions = list(post.revisions.all())
- for i, revision in enumerate(revisions):
- revision.html = QUESTION_REVISION_TEMPLATE % {
- 'title': revision.title,
- 'html': sanitize_html(markdowner.convert(revision.text)),
- 'tags': ' '.join(['<a class="post-tag">%s</a>' % tag
- for tag in revision.tagnames.split(' ')]),
- }
- if i > 0:
- revisions[i - 1].diff = htmldiff(revision.html,
- revisions[i - 1].html)
- else:
- revisions[i - 1].diff = QUESTION_REVISION_TEMPLATE % {
- 'title': revisions[0].title,
- 'html': sanitize_html(markdowner.convert(revisions[0].text)),
- 'tags': ' '.join(['<a class="post-tag">%s</a>' % tag
- for tag in revisions[0].tagnames.split(' ')]),
- }
- revisions[i - 1].summary = None
- return render_to_response('revisions_question.html', {
- 'post': post,
- 'revisions': revisions,
- }, context_instance=RequestContext(request))
-
-ANSWER_REVISION_TEMPLATE = ('<div class="text">%(html)s</div>')
-def answer_revisions(request, id):
- post = get_object_or_404(Answer, id=id)
- revisions = list(post.revisions.all())
- for i, revision in enumerate(revisions):
- revision.html = ANSWER_REVISION_TEMPLATE % {
- 'html': sanitize_html(markdowner.convert(revision.text))
- }
- if i > 0:
- revisions[i - 1].diff = htmldiff(revision.html,
- revisions[i - 1].html)
- else:
- revisions[i - 1].diff = revisions[i-1].text
- revisions[i - 1].summary = None
- return render_to_response('revisions_answer.html', {
- 'post': post,
- 'revisions': revisions,
- }, context_instance=RequestContext(request))
-
-#TODO: allow anynomus
-@login_required
-def answer(request, id):
- question = get_object_or_404(Question, id=id)
- if request.method == "POST":
- form = AnswerForm(question, request.POST)
- if form.is_valid():
- update_time = datetime.datetime.now()
- answer = Answer(
- question = question,
- author = request.user,
- added_at = update_time,
- wiki = form.cleaned_data['wiki'],
- html = sanitize_html(markdowner.convert(form.cleaned_data['text'])),
- )
- if answer.wiki:
- answer.last_edited_by = answer.author
- answer.last_edited_at = update_time
- answer.wikified_at = update_time
-
- answer.save()
- Question.objects.update_answer_count(question)
-
- question = get_object_or_404(Question, id=id)
- question.last_activity_at = update_time
- question.last_activity_by = request.user
- question.save()
-
- AnswerRevision.objects.create(
- answer = answer,
- revision = 1,
- author = request.user,
- revised_at = update_time,
- summary = CONST['default_version'],
- text = form.cleaned_data['text']
- )
-
- return HttpResponseRedirect(question.get_absolute_url())
-
-def tags(request):
- stag = ""
- is_paginated = True
- sortby = request.GET.get('sort', 'used')
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- if request.method == "GET":
- stag = request.GET.get("q", "").strip()
- if stag is not None:
- objects_list = Paginator(Tag.objects.filter(deleted=False).exclude(used_count=0).extra(where=['name like %s'], params=['%' + stag + '%']), DEFAULT_PAGE_SIZE)
- else:
- if sortby == "name":
- objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("name"), DEFAULT_PAGE_SIZE)
- else:
- objects_list = Paginator(Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("-used_count"), DEFAULT_PAGE_SIZE)
-
- try:
- tags = objects_list.page(page)
- except (EmptyPage, InvalidPage):
- tags = objects_list.page(objects_list.num_pages)
-
- return render_to_response('tags.html', {
- "tags" : tags,
- "stag" : stag,
- "tab_id" : sortby,
- "keywords" : stag,
- "context" : {
- 'is_paginated' : is_paginated,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': tags.has_previous(),
- 'has_next': tags.has_next(),
- 'previous': tags.previous_page_number(),
- 'next': tags.next_page_number(),
- 'base_url' : '/tags/?sort=%s&' % sortby
- }
-
- }, context_instance=RequestContext(request))
-
-def tag(request, tag):
- return questions(request, tagname=tag)
-
-def vote(request, id):
- """
- vote_type:
- acceptAnswer : 0,
- questionUpVote : 1,
- questionDownVote : 2,
- favorite : 4,
- answerUpVote: 5,
- answerDownVote:6,
- offensiveQuestion : 7,
- offensiveAnswer:8,
- removeQuestion: 9,
- removeAnswer:10
-
- accept answer code:
- response_data['allowed'] = -1, Accept his own answer 0, no allowed - Anonymous 1, Allowed - by default
- response_data['success'] = 0, failed 1, Success - by default
- response_data['status'] = 0, By default 1, Answer has been accepted already(Cancel)
-
- vote code:
- allowed = -3, Don't have enough votes left
- -2, Don't have enough reputation score
- -1, Vote his own post
- 0, no allowed - Anonymous
- 1, Allowed - by default
- status = 0, By default
- 1, Cancel
- 2, Vote is too old to be canceled
-
- offensive code:
- allowed = -3, Don't have enough flags left
- -2, Don't have enough reputation score to do this
- 0, not allowed
- 1, allowed
- status = 0, by default
- 1, can't do it again
- """
- response_data = {
- "allowed": 1,
- "success": 1,
- "status" : 0,
- "count" : 0,
- "message" : ''
- }
-
- def can_vote(vote_score, user):
- if vote_score == 1:
- return can_vote_up(request.user)
- else:
- return can_vote_down(request.user)
-
- try:
- if not request.user.is_authenticated():
- response_data['allowed'] = 0
- response_data['success'] = 0
-
- elif request.is_ajax():
- question = get_object_or_404(Question, id=id)
- vote_type = request.POST.get('type')
-
- #accept answer
- if vote_type == '0':
- answer_id = request.POST.get('postId')
- answer = get_object_or_404(Answer, id=answer_id)
- # make sure question author is current user
- if question.author == request.user:
- # answer user who is also question author is not allow to accept answer
- if answer.author == question.author:
- response_data['success'] = 0
- response_data['allowed'] = -1
- # check if answer has been accepted already
- elif answer.accepted:
- onAnswerAcceptCanceled(answer, request.user)
- response_data['status'] = 1
- else:
- # set other answers in this question not accepted first
- for answer_of_question in Answer.objects.get_answers_from_question(question, request.user):
- if answer_of_question != answer and answer_of_question.accepted:
- onAnswerAcceptCanceled(answer_of_question, request.user)
-
- #make sure retrieve data again after above author changes, they may have related data
- answer = get_object_or_404(Answer, id=answer_id)
- onAnswerAccept(answer, request.user)
- else:
- response_data['allowed'] = 0
- response_data['success'] = 0
- # favorite
- elif vote_type == '4':
- has_favorited = False
- fav_questions = FavoriteQuestion.objects.filter(question=question)
- # if the same question has been favorited before, then delete it
- if fav_questions is not None:
- for item in fav_questions:
- if item.user == request.user:
- item.delete()
- response_data['status'] = 1
- response_data['count'] = len(fav_questions) - 1
- if response_data['count'] < 0:
- response_data['count'] = 0
- has_favorited = True
- # if above deletion has not been executed, just insert a new favorite question
- if not has_favorited:
- new_item = FavoriteQuestion(question=question, user=request.user)
- new_item.save()
- response_data['count'] = FavoriteQuestion.objects.filter(question=question).count()
- Question.objects.update_favorite_count(question)
-
- elif vote_type in ['1', '2', '5', '6']:
- post_id = id
- post = question
- vote_score = 1
- if vote_type in ['5', '6']:
- answer_id = request.POST.get('postId')
- answer = get_object_or_404(Answer, id=answer_id)
- post_id = answer_id
- post = answer
- if vote_type in ['2', '6']:
- vote_score = -1
-
- if post.author == request.user:
- response_data['allowed'] = -1
- elif not can_vote(vote_score, request.user):
- response_data['allowed'] = -2
- elif post.votes.filter(user=request.user).count() > 0:
- vote = post.votes.filter(user=request.user)[0]
- # unvote should be less than certain time
- if (datetime.datetime.now().day - vote.voted_at.day) >= VOTE_RULES['scope_deny_unvote_days']:
- response_data['status'] = 2
- else:
- voted = vote.vote
- if voted > 0:
- # cancel upvote
- onUpVotedCanceled(vote, post, request.user)
-
- else:
- # cancel downvote
- onDownVotedCanceled(vote, post, request.user)
-
- response_data['status'] = 1
- response_data['count'] = post.score
- elif Vote.objects.get_votes_count_today_from_user(request.user) >= VOTE_RULES['scope_votes_per_user_per_day']:
- response_data['allowed'] = -3
- else:
- vote = Vote(user=request.user, content_object=post, vote=vote_score, voted_at=datetime.datetime.now())
- if vote_score > 0:
- # upvote
- onUpVoted(vote, post, request.user)
- else:
- # downvote
- onDownVoted(vote, post, request.user)
-
- votes_left = VOTE_RULES['scope_votes_per_user_per_day'] - Vote.objects.get_votes_count_today_from_user(request.user)
- if votes_left <= VOTE_RULES['scope_warn_votes_left']:
- response_data['message'] = u'%s votes left' % votes_left
- response_data['count'] = post.score
- elif vote_type in ['7', '8']:
- post = question
- post_id = id
- if vote_type == '8':
- post_id = request.POST.get('postId')
- post = get_object_or_404(Answer, id=post_id)
-
- if FlaggedItem.objects.get_flagged_items_count_today(request.user) >= VOTE_RULES['scope_flags_per_user_per_day']:
- response_data['allowed'] = -3
- elif not can_flag_offensive(request.user):
- response_data['allowed'] = -2
- elif post.flagged_items.filter(user=request.user).count() > 0:
- response_data['status'] = 1
- else:
- item = FlaggedItem(user=request.user, content_object=post, flagged_at=datetime.datetime.now())
- onFlaggedItem(item, post, request.user)
- response_data['count'] = post.offensive_flag_count
- # send signal when question or answer be marked offensive
- mark_offensive.send(sender=post.__class__, instance=post, mark_by=request.user)
- elif vote_type in ['9', '10']:
- post = question
- post_id = id
- if vote_type == '10':
- post_id = request.POST.get('postId')
- post = get_object_or_404(Answer, id=post_id)
-
- if not can_delete_post(request.user, post):
- response_data['allowed'] = -2
- elif post.deleted:
- onDeleteCanceled(post, request.user)
- response_data['status'] = 1
- else:
- onDeleted(post, request.user)
- delete_post_or_answer.send(sender=post.__class__, instance=post, delete_by=request.user)
- else:
- response_data['success'] = 0
- response_data['message'] = u'Request mode is not supported. Please try again.'
-
- data = simplejson.dumps(response_data)
-
- except Exception, e:
- response_data['message'] = str(e)
- data = simplejson.dumps(response_data)
- return HttpResponse(data, mimetype="application/json")
-
-def users(request):
- is_paginated = True
- sortby = request.GET.get('sort', 'reputation')
- suser = request.REQUEST.get('q', "")
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- if suser == "":
- if sortby == "newest":
- objects_list = Paginator(User.objects.all().order_by('-date_joined'), USERS_PAGE_SIZE)
- elif sortby == "last":
- objects_list = Paginator(User.objects.all().order_by('date_joined'), USERS_PAGE_SIZE)
- elif sortby == "user":
- objects_list = Paginator(User.objects.all().order_by('username'), USERS_PAGE_SIZE)
- # default
- else:
- objects_list = Paginator(User.objects.all().order_by('-reputation'), USERS_PAGE_SIZE)
- base_url = '/users/?sort=%s&' % sortby
- else:
- sortby = "reputation"
- objects_list = Paginator(User.objects.extra(where=['username like %s'], params=['%' + suser + '%']).order_by('-reputation'), USERS_PAGE_SIZE)
- base_url = '/users/?name=%s&sort=%s&' % (suser, sortby)
-
- try:
- users = objects_list.page(page)
- except (EmptyPage, InvalidPage):
- users = objects_list.page(objects_list.num_pages)
-
- return render_to_response('users.html', {
- "users" : users,
- "suser" : suser,
- "keywords" : suser,
- "tab_id" : sortby,
- "context" : {
- 'is_paginated' : is_paginated,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': users.has_previous(),
- 'has_next': users.has_next(),
- 'previous': users.previous_page_number(),
- 'next': users.next_page_number(),
- 'base_url' : base_url
- }
-
- }, context_instance=RequestContext(request))
-
-def user(request, id):
- sort = request.GET.get('sort', 'stats')
- user_view = dict((v.id, v) for v in USER_TEMPLATE_VIEWS).get(sort, USER_TEMPLATE_VIEWS[0])
- from forum import views
- func = getattr(views, user_view.view_name)
- return func(request, id, user_view)
-
-@login_required
-def edit_user(request, id):
- user = get_object_or_404(User, id=id)
- if request.user != user:
- raise Http404
- if request.method == "POST":
- form = EditUserForm(user, request.POST)
- if form.is_valid():
- user.email = sanitize_html(form.cleaned_data['email'])
- user.real_name = sanitize_html(form.cleaned_data['realname'])
- user.website = sanitize_html(form.cleaned_data['website'])
- user.location = sanitize_html(form.cleaned_data['city'])
- user.date_of_birth = sanitize_html(form.cleaned_data['birthday'])
- if len(user.date_of_birth) == 0:
- user.date_of_birth = '1900-01-01'
- user.about = sanitize_html(form.cleaned_data['about'])
-
- user.save()
- # send user updated singal if full fields have been updated
- if user.email and user.real_name and user.website and user.location and \
- user.date_of_birth and user.about:
- user_updated.send(sender=user.__class__, instance=user, updated_by=user)
- return HttpResponseRedirect(user.get_profile_url())
- else:
- form = EditUserForm(user)
- return render_to_response('user_edit.html', {
- 'form' : form,
- }, context_instance=RequestContext(request))
-
-def user_stats(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- questions = Question.objects.extra(
- select={
- 'vote_count' : 'question.score',
- 'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s AND f.question_id = question.id',
- 'la_user_id' : 'auth_user.id',
- 'la_username' : 'auth_user.username',
- 'la_user_gold' : 'auth_user.gold',
- 'la_user_silver' : 'auth_user.silver',
- 'la_user_bronze' : 'auth_user.bronze',
- 'la_user_reputation' : 'auth_user.reputation'
- },
- select_params=[user_id],
- tables=['question', 'auth_user'],
- where=['question.deleted = 0 AND question.author_id=%s AND question.last_activity_by_id = auth_user.id'],
- params=[user_id],
- order_by=['-vote_count', '-last_activity_at']
- ).values('vote_count',
- 'favorited_myself',
- 'id',
- 'title',
- 'author_id',
- 'added_at',
- 'answer_accepted',
- 'answer_count',
- 'comment_count',
- 'view_count',
- 'favourite_count',
- 'summary',
- 'tagnames',
- 'vote_up_count',
- 'vote_down_count',
- 'last_activity_at',
- 'la_user_id',
- 'la_username',
- 'la_user_gold',
- 'la_user_silver',
- 'la_user_bronze',
- 'la_user_reputation')[:100]
-
- answered_questions = Question.objects.extra(
- select={
- 'vote_up_count' : 'answer.vote_up_count',
- 'vote_down_count' : 'answer.vote_down_count',
- 'answer_id' : 'answer.id',
- 'accepted' : 'answer.accepted',
- 'vote_count' : 'answer.score',
- 'comment_count' : 'answer.comment_count'
- },
- tables=['question', 'answer'],
- where=['answer.deleted=0 AND answer.author_id=%s AND answer.question_id=question.id'],
- params=[user_id],
- order_by=['-vote_count', '-answer_id'],
- select_params=[user_id]
- ).distinct().values('comment_count',
- 'id',
- 'answer_id',
- 'title',
- 'author_id',
- 'accepted',
- 'vote_count',
- 'answer_count',
- 'vote_up_count',
- 'vote_down_count')[:100]
- up_votes = Vote.objects.get_up_vote_count_from_user(user)
- down_votes = Vote.objects.get_down_vote_count_from_user(user)
- votes_today = Vote.objects.get_votes_count_today_from_user(user)
- votes_total = VOTE_RULES['scope_votes_per_user_per_day']
- tags = user.created_tags.all().order_by('-used_count')[:50]
- awards = Award.objects.extra(
- select={'id': 'badge.id', 'count': 'count(badge_id)', 'name':'badge.name', 'description': 'badge.description', 'type': 'badge.type'},
- tables=['award', 'badge'],
- order_by=['-awarded_at'],
- where=['user_id=%s AND badge_id=badge.id'],
- params=[user.id]
- ).values('id', 'count', 'name', 'description', 'type')
- total_awards = awards.count()
- awards.query.group_by = ['badge_id']
-
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "questions" : questions,
- "answered_questions" : answered_questions,
- "up_votes" : up_votes,
- "down_votes" : down_votes,
- "total_votes": up_votes + down_votes,
- "votes_today_left": votes_total-votes_today,
- "votes_total_per_day": votes_total,
- "tags" : tags,
- "awards": awards,
- "total_awards" : total_awards,
- }, context_instance=RequestContext(request))
-
-def user_recent(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- def get_type_name(type_id):
- for item in TYPE_ACTIVITY:
- if type_id in item:
- return item[1]
-
- class Event:
- def __init__(self, time, type, title, summary, answer_id, question_id):
- self.time = time
- self.type = get_type_name(type)
- self.type_id = type
- self.title = title
- self.summary = summary
- #python 2.4 issue - Adolfo Fitoria
- #self.title_link = u'/questions/%s/%s#%s' %(question_id, title, answer_id)\
- # if int(answer_id) > 0 else u'/questions/%s/%s' %(question_id, title)
- if (int(answer_id)>0):
- self.title_link = u'/questions/%s/%s#%s' %(question_id, title, answer_id)
- else:
- self.title_link = u'/questions/%s/%s' %(question_id, title)
-
- class AwardEvent:
- def __init__(self, time, type, id):
- self.time = time
- self.type = get_type_name(type)
- self.type_id = type
- self.badge = get_object_or_404(Badge, id=id)
-
- activities = []
- # ask questions
- questions = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'active_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'question'],
- where=['activity.content_type_id = %s AND activity.object_id = ' +
- 'question.id AND activity.user_id = %s AND activity.activity_type = %s'],
- params=[question_type_id, user_id, TYPE_ACTIVITY_ASK_QUESTION],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'active_at',
- 'activity_type'
- )
- if len(questions) > 0:
- questions = [(Event(q['active_at'], q['activity_type'], q['title'], '', '0', \
- q['question_id'])) for q in questions]
- activities.extend(questions)
-
- # answers
- answers = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'active_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'answer', 'question'],
- where=['activity.content_type_id = %s AND activity.object_id = answer.id AND ' +
- 'answer.question_id=question.id AND activity.user_id=%s AND activity.activity_type=%s'],
- params=[answer_type_id, user_id, TYPE_ACTIVITY_ANSWER],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'active_at',
- 'activity_type'
- )
- if len(answers) > 0:
- answers = [(Event(q['active_at'], q['activity_type'], q['title'], '', q['answer_id'], \
- q['question_id'])) for q in answers]
- activities.extend(answers)
-
- # question comments
- comments = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'comment.object_id',
- 'added_at' : 'comment.added_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'question', 'comment'],
-
- where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+
- 'activity.user_id = comment.user_id AND comment.object_id=question.id AND '+
- 'comment.content_type_id=%s AND activity.user_id = %s AND activity.activity_type=%s'],
- params=[comment_type_id, question_type_id, user_id, TYPE_ACTIVITY_COMMENT_QUESTION],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'activity_type'
- )
-
- if len(comments) > 0:
- comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \
- q['question_id'])) for q in comments]
- activities.extend(comments)
-
- # answer comments
- comments = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'comment.added_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'question', 'answer', 'comment'],
-
- where=['activity.content_type_id = %s AND activity.object_id = comment.id AND '+
- 'activity.user_id = comment.user_id AND comment.object_id=answer.id AND '+
- 'comment.content_type_id=%s AND question.id = answer.question_id AND '+
- 'activity.user_id = %s AND activity.activity_type=%s'],
- params=[comment_type_id, answer_type_id, user_id, TYPE_ACTIVITY_COMMENT_ANSWER],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'activity_type'
- )
-
- if len(comments) > 0:
- comments = [(Event(q['added_at'], q['activity_type'], q['title'], '', q['answer_id'], \
- q['question_id'])) for q in comments]
- activities.extend(comments)
-
- # question revisions
- revisions = Activity.objects.extra(
- select={
- 'title' : 'question_revision.title',
- 'question_id' : 'question_revision.question_id',
- 'added_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type',
- 'summary' : 'question_revision.summary'
- },
- tables=['activity', 'question_revision'],
- where=['activity.content_type_id = %s AND activity.object_id = question_revision.id AND '+
- 'activity.user_id = question_revision.author_id AND activity.user_id = %s AND '+
- 'activity.activity_type=%s'],
- params=[question_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_QUESTION],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'activity_type',
- 'summary'
- )
-
- if len(revisions) > 0:
- revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], '0', \
- q['question_id'])) for q in revisions]
- activities.extend(revisions)
-
- # answer revisions
- revisions = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type',
- 'summary' : 'answer_revision.summary'
- },
- tables=['activity', 'answer_revision', 'question', 'answer'],
-
- where=['activity.content_type_id = %s AND activity.object_id = answer_revision.id AND '+
- 'activity.user_id = answer_revision.author_id AND activity.user_id = %s AND '+
- 'answer_revision.answer_id=answer.id AND answer.question_id = question.id AND '+
- 'activity.activity_type=%s'],
- params=[answer_revision_type_id, user_id, TYPE_ACTIVITY_UPDATE_ANSWER],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'answer_id',
- 'activity_type',
- 'summary'
- )
-
- if len(revisions) > 0:
- revisions = [(Event(q['added_at'], q['activity_type'], q['title'], q['summary'], \
- q['answer_id'], q['question_id'])) for q in revisions]
- activities.extend(revisions)
-
- # accepted answers
- accept_answers = Activity.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'added_at' : 'activity.active_at',
- 'activity_type' : 'activity.activity_type',
- },
- tables=['activity', 'answer', 'question'],
- where=['activity.content_type_id = %s AND activity.object_id = answer.id AND '+
- 'activity.user_id = question.author_id AND activity.user_id = %s AND '+
- 'answer.question_id=question.id AND activity.activity_type=%s'],
- params=[answer_type_id, user_id, TYPE_ACTIVITY_MARK_ANSWER],
- order_by=['-activity.active_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'activity_type',
- )
- if len(accept_answers) > 0:
- accept_answers = [(Event(q['added_at'], q['activity_type'], q['title'], '', '0', \
- q['question_id'])) for q in accept_answers]
- activities.extend(accept_answers)
- #award history
- awards = Activity.objects.extra(
- select={
- 'badge_id' : 'badge.id',
- 'awarded_at': 'award.awarded_at',
- 'activity_type' : 'activity.activity_type'
- },
- tables=['activity', 'award', 'badge'],
- where=['activity.user_id = award.user_id AND activity.user_id = %s AND '+
- 'award.badge_id=badge.id AND activity.object_id=award.id AND activity.activity_type=%s'],
- params=[user_id, TYPE_ACTIVITY_PRIZE],
- order_by=['-activity.active_at']
- ).values(
- 'badge_id',
- 'awarded_at',
- 'activity_type'
- )
- if len(awards) > 0:
- awards = [(AwardEvent(q['awarded_at'], q['activity_type'], q['badge_id'])) for q in awards]
- activities.extend(awards)
-
- activities.sort(lambda x,y: cmp(y.time, x.time))
-
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "activities" : activities[:user_view.data_size]
- }, context_instance=RequestContext(request))
-
-def user_responses(request, user_id, user_view):
- """
- We list answers for question, comments, and answer accepted by others for this user.
- """
- class Response:
- def __init__(self, type, title, question_id, answer_id, time, username, user_id, content):
- self.type = type
- self.title = title
- self.titlelink = u'/questions/%s/%s#%s' % (question_id, title, answer_id)
- self.time = time
- self.userlink = u'/users/%s/%s/' % (user_id, username)
- self.username = username
- self.content = u'%s ...' % strip_tags(content)[:300]
-
- def __unicode__(self):
- return u'%s %s' % (self.type, self.titlelink)
-
- user = get_object_or_404(User, id=user_id)
- responses = []
- answers = Answer.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'answer.added_at',
- 'html' : 'answer.html',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- select_params=[user_id],
- tables=['answer', 'question', 'auth_user'],
- where=['answer.question_id = question.id AND answer.deleted=0 AND question.deleted = 0 AND '+
- 'question.author_id = %s AND answer.author_id <> %s AND answer.author_id=auth_user.id'],
- params=[user_id, user_id],
- order_by=['-answer.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'html',
- 'username',
- 'user_id'
- )
- if len(answers) > 0:
- answers = [(Response(TYPE_RESPONSE['QUESTION_ANSWERED'], a['title'], a['question_id'],
- a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers]
- responses.extend(answers)
-
-
- # question comments
- comments = Comment.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'comment.object_id',
- 'added_at' : 'comment.added_at',
- 'comment' : 'comment.comment',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- tables=['question', 'auth_user', 'comment'],
- where=['question.deleted = 0 AND question.author_id = %s AND comment.object_id=question.id AND '+
- 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id'],
- params=[user_id, question_type_id, user_id],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'added_at',
- 'comment',
- 'username',
- 'user_id'
- )
-
- if len(comments) > 0:
- comments = [(Response(TYPE_RESPONSE['QUESTION_COMMENTED'], c['title'], c['question_id'],
- '', c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments]
- responses.extend(comments)
-
- # answer comments
- comments = Comment.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'comment.added_at',
- 'comment' : 'comment.comment',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- tables=['answer', 'auth_user', 'comment', 'question'],
- where=['answer.deleted = 0 AND answer.author_id = %s AND comment.object_id=answer.id AND '+
- 'comment.content_type_id=%s AND comment.user_id <> %s AND comment.user_id = auth_user.id '+
- 'AND question.id = answer.question_id'],
- params=[user_id, answer_type_id, user_id],
- order_by=['-comment.added_at']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'comment',
- 'username',
- 'user_id'
- )
-
- if len(comments) > 0:
- comments = [(Response(TYPE_RESPONSE['ANSWER_COMMENTED'], c['title'], c['question_id'],
- c['answer_id'], c['added_at'], c['username'], c['user_id'], c['comment'])) for c in comments]
- responses.extend(comments)
-
- # answer has been accepted
- answers = Answer.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'added_at' : 'answer.accepted_at',
- 'html' : 'answer.html',
- 'username' : 'auth_user.username',
- 'user_id' : 'auth_user.id'
- },
- select_params=[user_id],
- tables=['answer', 'question', 'auth_user'],
- where=['answer.question_id = question.id AND answer.deleted=0 AND question.deleted = 0 AND '+
- 'answer.author_id = %s AND answer.accepted=1 AND question.author_id=auth_user.id'],
- params=[user_id],
- order_by=['-answer.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'added_at',
- 'html',
- 'username',
- 'user_id'
- )
- if len(answers) > 0:
- answers = [(Response(TYPE_RESPONSE['ANSWER_ACCEPTED'], a['title'], a['question_id'],
- a['answer_id'], a['added_at'], a['username'], a['user_id'], a['html'])) for a in answers]
- responses.extend(answers)
-
- # sort posts by time
- responses.sort(lambda x,y: cmp(y.time, x.time))
-
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "responses" : responses[:user_view.data_size],
-
- }, context_instance=RequestContext(request))
-
-def user_votes(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- if not can_view_user_votes(request.user, user):
- raise Http404
- votes = []
- question_votes = Vote.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 0,
- 'voted_at' : 'vote.voted_at',
- 'vote' : 'vote',
- },
- select_params=[user_id],
- tables=['vote', 'question', 'auth_user'],
- where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = question.id '+
- 'AND vote.user_id=auth_user.id'],
- params=[question_type_id, user_id],
- order_by=['-vote.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'voted_at',
- 'vote',
- )
- if(len(question_votes) > 0):
- votes.extend(question_votes)
-
- answer_votes = Vote.objects.extra(
- select={
- 'title' : 'question.title',
- 'question_id' : 'question.id',
- 'answer_id' : 'answer.id',
- 'voted_at' : 'vote.voted_at',
- 'vote' : 'vote',
- },
- select_params=[user_id],
- tables=['vote', 'answer', 'question', 'auth_user'],
- where=['vote.content_type_id = %s AND vote.user_id = %s AND vote.object_id = answer.id '+
- 'AND answer.question_id = question.id AND vote.user_id=auth_user.id'],
- params=[answer_type_id, user_id],
- order_by=['-vote.id']
- ).values(
- 'title',
- 'question_id',
- 'answer_id',
- 'voted_at',
- 'vote',
- )
- if(len(answer_votes) > 0):
- votes.extend(answer_votes)
- votes.sort(lambda x,y: cmp(y['voted_at'], x['voted_at']))
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "votes" : votes[:user_view.data_size]
-
- }, context_instance=RequestContext(request))
-
-def user_reputation(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- reputation = Repute.objects.extra(
- select={'positive': 'sum(positive)', 'negative': 'sum(negative)', 'question_id':'question_id',
- 'title': 'question.title'},
- tables=['repute', 'question'],
- order_by=['-reputed_at'],
- where=['user_id=%s AND question_id=question.id'],
- params=[user.id]
- ).values('positive', 'negative', 'question_id', 'title', 'reputed_at', 'reputation')
-
- reputation.query.group_by = ['question_id']
-
-
- rep_list = []
- for rep in Repute.objects.filter(user=user).order_by('reputed_at'):
- dic = '[%s,%s]' % (calendar.timegm(rep.reputed_at.timetuple()) * 1000, rep.reputation)
- rep_list.append(dic)
- reps = ','.join(rep_list)
- reps = '[%s]' % reps
-
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- "reputation" : reputation,
- "reps" : reps
- }, context_instance=RequestContext(request))
-
-def user_favorites(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- questions = Question.objects.extra(
- select={
- 'vote_count' : 'question.vote_up_count + question.vote_down_count',
- 'favorited_myself' : 'SELECT count(*) FROM favorite_question f WHERE f.user_id = %s '+
- 'AND f.question_id = question.id',
- 'la_user_id' : 'auth_user.id',
- 'la_username' : 'auth_user.username',
- 'la_user_gold' : 'auth_user.gold',
- 'la_user_silver' : 'auth_user.silver',
- 'la_user_bronze' : 'auth_user.bronze',
- 'la_user_reputation' : 'auth_user.reputation'
- },
- select_params=[user_id],
- tables=['question', 'auth_user', 'favorite_question'],
- where=['question.deleted = 0 AND question.last_activity_by_id = auth_user.id '+
- 'AND favorite_question.question_id = question.id AND favorite_question.user_id = %s'],
- params=[user_id],
- order_by=['-vote_count', '-question.id']
- ).values('vote_count',
- 'favorited_myself',
- 'id',
- 'title',
- 'author_id',
- 'added_at',
- 'answer_accepted',
- 'answer_count',
- 'comment_count',
- 'view_count',
- 'favourite_count',
- 'summary',
- 'tagnames',
- 'vote_up_count',
- 'vote_down_count',
- 'last_activity_at',
- 'la_user_id',
- 'la_username',
- 'la_user_gold',
- 'la_user_silver',
- 'la_user_bronze',
- 'la_user_reputation')
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "questions" : questions[:user_view.data_size],
- "view_user" : user
- }, context_instance=RequestContext(request))
-
-
-def user_preferences(request, user_id, user_view):
- user = get_object_or_404(User, id=user_id)
- return render_to_response(user_view.template_file,{
- "tab_name" : user_view.id,
- "tab_description" : user_view.tab_description,
- "page_title" : user_view.page_title,
- "view_user" : user,
- }, context_instance=RequestContext(request))
-
-def question_comments(request, id):
- question = get_object_or_404(Question, id=id)
- user = request.user
- return __comments(request, question, 'question', user)
-
-def answer_comments(request, id):
- answer = get_object_or_404(Answer, id=id)
- user = request.user
- return __comments(request, answer, 'answer', user)
-
-def __comments(request, obj, type, user):
- # only support get comments by ajax now
- if request.is_ajax():
- if request.method == "GET":
- return __generate_comments_json(obj, type, user)
- elif request.method == "POST":
- comment_data = request.POST.get('comment')
- comment = Comment(content_object=obj, comment=comment_data, user=request.user)
- comment.save()
- obj.comment_count = obj.comment_count + 1
- obj.save()
- return __generate_comments_json(obj, type, user)
-
-def __generate_comments_json(obj, type, user):
- comments = obj.comments.all().order_by('-id')
- # {"Id":6,"PostId":38589,"CreationDate":"an hour ago","Text":"hello there!","UserDisplayName":"Jarrod Dixon","UserUrl":"/users/3/jarrod-dixon","DeleteUrl":null}
- json_comments = []
- for comment in comments:
- comment_user = comment.user
- delete_url = ""
- if user != None and auth.can_delete_comment(user, comment):
- #/posts/392845/comments/219852/delete
- delete_url = "/" + type + "s/%s/comments/%s/delete/" % (obj.id, comment.id)
- json_comments.append({"id" : comment.id,
- "object_id" : obj.id,
- "add_date" : comment.added_at.strftime('%Y-%m-%d'),
- "text" : comment.comment,
- "user_display_name" : comment_user.username,
- "user_url" : "/users/%s/%s" % (comment_user.id, comment_user.username),
- "delete_url" : delete_url
- })
-
- data = simplejson.dumps(json_comments)
- return HttpResponse(data, mimetype="application/json")
-
-def delete_question_comment(request, question_id, comment_id):
- if request.is_ajax():
- question = get_object_or_404(Question, id=question_id)
- comment = get_object_or_404(Comment, id=comment_id)
-
- question.comments.remove(comment)
- question.comment_count = question.comment_count - 1
- question.save()
- user = request.user
- return __generate_comments_json(question, 'question', user)
-
-def delete_answer_comment(request, answer_id, comment_id):
- if request.is_ajax():
- answer = get_object_or_404(Answer, id=answer_id)
- comment = get_object_or_404(Comment, id=comment_id)
-
- answer.comments.remove(comment)
- answer.comment_count = answer.comment_count - 1
- answer.save()
- user = request.user
- return __generate_comments_json(answer, 'answer', user)
-
-def logout(request):
- url = request.GET.get('next')
- return render_to_response('logout.html', {
- 'next' : url,
- }, context_instance=RequestContext(request))
-
-def badges(request):
- badges = Badge.objects.all().order_by('type')
- my_badges = []
- if request.user.is_authenticated():
- my_badges = Award.objects.filter(user=request.user)
- my_badges.query.group_by = ['badge_id']
-
- return render_to_response('badges.html', {
- 'badges' : badges,
- 'mybadges' : my_badges,
- }, context_instance=RequestContext(request))
-
-def badge(request, id):
- badge = get_object_or_404(Badge, id=id)
- awards = Award.objects.extra(
- select={'id': 'auth_user.id',
- 'name': 'auth_user.username',
- 'rep':'auth_user.reputation',
- 'gold': 'auth_user.gold',
- 'silver': 'auth_user.silver',
- 'bronze': 'auth_user.bronze'},
- tables=['award', 'auth_user'],
- where=['badge_id=%s AND user_id=auth_user.id'],
- params=[id]
- ).values('id').distinct()
-
- return render_to_response('badge.html', {
- 'awards' : awards,
- 'badge' : badge,
- }, context_instance=RequestContext(request))
-
-def read_message(request):
- if request.method == "POST":
- if request.POST['formdata'] == 'required':
- request.session['message_silent'] = 1
-
- if request.user.is_authenticated():
- request.user.delete_messages()
- return HttpResponse('')
-
-def upload(request):
- class FileTypeNotAllow(Exception):
- pass
- class FileSizeNotAllow(Exception):
- pass
- class UploadPermissionNotAuthorized(Exception):
- pass
-
- #<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>
- xml_template = "<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>"
-
- try:
- f = request.FILES['file-upload']
- # check upload permission
- if not can_upload_files(request.user):
- raise UploadPermissionNotAuthorized
-
- # check file type
- file_name_suffix = os.path.splitext(f.name)[1].lower()
- if not file_name_suffix in settings.ALLOW_FILE_TYPES:
- raise FileTypeNotAllow
-
- # genetate new file name
- new_file_name = str(time.time()).replace('.', str(random.randint(0,100000))) + file_name_suffix
- # use default storage to store file
- default_storage.save(new_file_name, f)
- # check file size
- # byte
- size = default_storage.size(new_file_name)
- if size > settings.ALLOW_MAX_FILE_SIZE:
- default_storage.delete(new_file_name)
- raise FileSizeNotAllow
-
- result = xml_template % ('Good', '', default_storage.url(new_file_name))
- except UploadPermissionNotAuthorized:
- result = xml_template % ('', _('uploading images is limited to users with >60 reputation points'), '')
- except FileTypeNotAllow:
- result = xml_template % ('', _("allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'"), '')
- except FileSizeNotAllow:
- result = xml_template % ('', _("maximum upload file size is %sK") % settings.ALLOW_MAX_FILE_SIZE / 1024, '')
- except Exception as e:
- result = xml_template % ('', _('Error uploading file. Please contact the site administrator. Thank you. %s' % e), '')
-
- return HttpResponse(result, mimetype="application/xml")
-
-def books(request):
- return HttpResponseRedirect("/books/mysql-zhaoyang")
-
-def book(request, short_name, unanswered=False):
- """
- 1. questions list
- 2. book info
- 3. author info and blog rss items
- """
- """
- List of Questions, Tagged questions, and Unanswered questions.
- """
- books = Book.objects.extra(where=['short_name = %s'], params=[short_name])
- match_count = len(books)
- if match_count == 0 :
- raise Http404
- else:
- # the book info
- book = books[0]
- # get author info
- author_info = BookAuthorInfo.objects.get(book=book)
- # get author rss info
- author_rss = BookAuthorRss.objects.filter(book=book)
-
- # get pagesize from session, if failed then get default value
- user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE)
- # set pagesize equal to logon user specified value in database
- if request.user.is_authenticated() and request.user.questions_per_page > 0:
- user_page_size = request.user.questions_per_page
-
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
-
- view_id = request.GET.get('sort', None)
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-added_at"
-
- # check if request is from tagged questions
- if unanswered:
- # check if request is from unanswered questions
- # Article.objects.filter(publications__id__exact=1)
- objects = Question.objects.filter(book__id__exact=book.id, deleted=False, answer_count=0).order_by(orderby)
- else:
- objects = Question.objects.filter(book__id__exact=book.id, deleted=False).order_by(orderby)
-
- # RISK - inner join queries
- objects = objects.select_related();
- objects_list = Paginator(objects, user_page_size)
- questions = objects_list.page(page)
-
- return render_to_response('book.html', {
- "book" : book,
- "author_info" : author_info,
- "author_rss" : author_rss,
- "questions" : questions,
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': questions.has_previous(),
- 'has_next': questions.has_next(),
- 'previous': questions.previous_page_number(),
- 'next': questions.next_page_number(),
- 'base_url' : request.path + '?sort=%s&' % view_id,
- 'pagesize' : user_page_size
- }
- }, context_instance=RequestContext(request))
-
-@login_required
-def ask_book(request, short_name):
- if request.method == "POST":
- form = AskForm(request.POST)
- if form.is_valid():
- added_at = datetime.datetime.now()
- html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
- question = Question(
- title = strip_tags(form.cleaned_data['title']),
- author = request.user,
- added_at = added_at,
- last_activity_at = added_at,
- last_activity_by = request.user,
- wiki = form.cleaned_data['wiki'],
- tagnames = form.cleaned_data['tags'].strip(),
- html = html,
- summary = strip_tags(html)[:120]
- )
- if question.wiki:
- question.last_edited_by = question.author
- question.last_edited_at = added_at
- question.wikified_at = added_at
-
- question.save()
-
- # create the first revision
- QuestionRevision.objects.create(
- question = question,
- revision = 1,
- title = question.title,
- author = request.user,
- revised_at = added_at,
- tagnames = question.tagnames,
- summary = CONST['default_version'],
- text = form.cleaned_data['text']
- )
-
- books = Book.objects.extra(where=['short_name = %s'], params=[short_name])
- match_count = len(books)
- if match_count == 1:
- # the book info
- book = books[0]
- book.questions.add(question)
-
- return HttpResponseRedirect(question.get_absolute_url())
- else:
- form = AskForm()
-
- tags = _get_tags_cache_json()
- return render_to_response('ask.html', {
- 'form' : form,
- 'tags' : tags,
- }, context_instance=RequestContext(request))
-
-def search(request):
- """
- Search by question, user and tag keywords.
- For questions now we only search keywords in question title.
- """
- if request.method == "GET":
- keywords = request.GET.get("q")
- search_type = request.GET.get("t")
- try:
- page = int(request.GET.get('page', '1'))
- except ValueError:
- page = 1
- if keywords is None:
- return HttpResponseRedirect('/')
- if search_type == 'tag':
- return HttpResponseRedirect('/etiquetas/?q=%s&page=%s' % (keywords.strip(), page))
- elif search_type == "user":
- return HttpResponseRedirect('/usuarios/?q=%s&page=%s' % (keywords.strip(), page))
- elif search_type == "question":
-
- template_file = "questions.html"
- # Set flag to False by default. If it is equal to True, then need to be saved.
- pagesize_changed = False
- # get pagesize from session, if failed then get default value
- user_page_size = request.session.get("pagesize", QUESTIONS_PAGE_SIZE)
- # set pagesize equal to logon user specified value in database
- if request.user.is_authenticated() and request.user.questions_per_page > 0:
- user_page_size = request.user.questions_per_page
-
- try:
- page = int(request.GET.get('page', '1'))
- # get new pagesize from UI selection
- pagesize = int(request.GET.get('pagesize', user_page_size))
- if pagesize <> user_page_size:
- pagesize_changed = True
-
- except ValueError:
- page = 1
- pagesize = user_page_size
-
- # save this pagesize to user database
- if pagesize_changed:
- request.session["pagesize"] = pagesize
- if request.user.is_authenticated():
- user = request.user
- user.questions_per_page = pagesize
- user.save()
-
- view_id = request.GET.get('sort', None)
- view_dic = {"latest":"-added_at", "active":"-last_activity_at", "hottest":"-answer_count", "mostvoted":"-score" }
- try:
- orderby = view_dic[view_id]
- except KeyError:
- view_id = "latest"
- orderby = "-added_at"
-
- objects = Question.objects.filter(deleted=False).extra(where=['title like %s'], params=['%' + keywords + '%']).order_by(orderby)
-
- # RISK - inner join queries
- objects = objects.select_related();
- objects_list = Paginator(objects, pagesize)
- questions = objects_list.page(page)
-
- # Get related tags from this page objects
- related_tags = []
- for question in questions.object_list:
- tags = list(question.tags.all())
- for tag in tags:
- if tag not in related_tags:
- related_tags.append(tag)
-
- return render_to_response(template_file, {
- "questions" : questions,
- "tab_id" : view_id,
- "questions_count" : objects_list.count,
- "tags" : related_tags,
- "searchtag" : None,
- "searchtitle" : keywords,
- "keywords" : keywords,
- "is_unanswered" : False,
- "context" : {
- 'is_paginated' : True,
- 'pages': objects_list.num_pages,
- 'page': page,
- 'has_previous': questions.has_previous(),
- 'has_next': questions.has_next(),
- 'previous': questions.previous_page_number(),
- 'next': questions.next_page_number(),
- 'base_url' : request.path + '?t=question&q=%s&sort=%s&' % (keywords, view_id),
- 'pagesize' : pagesize
- }}, context_instance=RequestContext(request))
-
- else:
- raise Http404
-
-======= # encoding:utf-8 import os.path import time, datetime, calendar, random diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo Binary files differindex 39dba67d..11d15deb 100644 --- a/locale/en/LC_MESSAGES/django.mo +++ b/locale/en/LC_MESSAGES/django.mo diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index cc42454c..3dda9ce9 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -148,7 +148,7 @@ msgstr "" #: django_authopenid/views.py:417 django_authopenid/views.py:544 msgid "Welcome" -msgstr "Verification Email from NMR Wiki Q&A" +msgstr "Verification Email from Q&A forum" #: django_authopenid/views.py:507 msgid "Password changed." @@ -1013,12 +1013,6 @@ msgid "" "Most importanly - questions should be <strong>relevant</strong> to this " "community." msgstr "" -"Please ask questions about all aspects of <strong>Magnetic Resonance</" -"strong> - <strong>NMR</strong>, <strong>EPR</strong>, <strong>MRI</strong>. " -"Questions about both theory and practice in these fields are welcome, " -"including questions about the physical foundations, scientific applications, " -"instrumentation, interpretation of data, software, preparation and handling " -"of samples etc. " #: templates/faq.html:18 msgid "" @@ -1037,9 +1031,6 @@ msgid "" "Please avoid asking questions that are not relevant to this community, too " "subjective and argumentative." msgstr "" -"Please avoid asking questions that are not relevant to the subjects of NMR, " -"EPR or MRI, also please avoid asking questions that are too argumentative or " -"subjective." #: templates/faq.html:27 msgid "What should I avoid in my answers?" @@ -1047,7 +1038,7 @@ msgstr "" #: templates/faq.html:28 templates/faq.html.py:132 msgid "site title" -msgstr "NMR Wiki Q&A" +msgstr "" #: templates/faq.html:28 msgid "" @@ -1190,9 +1181,6 @@ msgstr "" #: templates/faq.html:124 msgid "Goal of this site is..." msgstr "" -"<span class='orange'>NMR Wiki Q&A</span> aims for offering a place for " -"efficient exchange of ideas among users of <strong>Magnetic Resonance</" -"strong>and specialists working in this field." #: templates/faq.html:124 msgid "" @@ -1339,7 +1327,7 @@ msgstr "" #: templates/index.html:80 msgid "welcome to website" -msgstr "Welcome to NMR Wiki Q&A" +msgstr "" #: templates/index.html:89 msgid "Recent tags" @@ -1399,9 +1387,6 @@ msgid "" "As a registered user you can login with your OpenID, log out of the site or " "permanently remove your account." msgstr "" -"Clicking <strong>Logout</strong> will log you out from NMR Wiki Q&A.</" -"p><p>If you wish to sign off completely - please make sure to log out from " -"your OpenID provider." #: templates/logout.html:21 msgid "Logout now" @@ -2107,12 +2092,6 @@ msgstr "" #, python-format msgid "validate %(email)s info" msgstr "" -"<span class=\"strong big\">An email with a validation link has been sent to %" -"(email)s.</span> Please <strong>follow the emailed link</strong> with your " -"web browser. Email validation is necessary to help insure the proper use of " -"email on <span class=\"orange\">NMR Wiki Q&A</span>. If you would like to " -"use <strong>another email</strong>, please <a href=\"/email/change/" -"\"><strong>change it again</strong></a>." #: templates/authopenid/changeemail.html:50 msgid "Email not changed" diff --git a/locale/es/LC_MESSAGES/django.mo b/locale/es/LC_MESSAGES/django.mo Binary files differindex a68a2fd3..a2a27c2f 100644 --- a/locale/es/LC_MESSAGES/django.mo +++ b/locale/es/LC_MESSAGES/django.mo diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index 488bd87a..b209c72c 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-08-05 22:28-0400\n" -"PO-Revision-Date: 2009-08-06 11:39-0600\n" +"PO-Revision-Date: 2009-08-07 11:21-0600\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" @@ -117,14 +117,12 @@ msgid "Incorrect username." msgstr "Nombre de usuario incorrecto" #: django_authopenid/urls.py:10 -#, fuzzy msgid "newquestion/" -msgstr "pregunta" +msgstr "nueva-pregunta/" #: django_authopenid/urls.py:11 -#, fuzzy msgid "newanswer/" -msgstr "resputa" +msgstr "respuesta-nueva/" #: django_authopenid/urls.py:12 msgid "signout/" @@ -165,17 +163,17 @@ msgstr "Contraseña modificada" #: django_authopenid/views.py:519 django_authopenid/views.py:524 msgid "your email needs to be validated" -msgstr "" +msgstr "su correo electrónico necesita ser validado" #: django_authopenid/views.py:681 django_authopenid/views.py:833 #, python-format msgid "No OpenID %s found associated in our database" -msgstr "La OpenID %s no esta asociada en nuestra base de datos" +msgstr "El OpenID %s no esta asociada en nuestra base de datos" #: django_authopenid/views.py:685 django_authopenid/views.py:840 #, python-format msgid "The OpenID %s isn't associated to current user logged in" -msgstr "La OpenID %s no esta asociada al usuario actualmente autenticado" +msgstr "El OpenID %s no esta asociada al usuario actualmente autenticado" #: django_authopenid/views.py:693 msgid "Email Changed." @@ -183,12 +181,12 @@ msgstr "Email modificado" #: django_authopenid/views.py:768 msgid "This OpenID is already associated with another account." -msgstr "Esta OpenID ya está asociada a otra cuenta." +msgstr "Este OpenID ya está asociada a otra cuenta." #: django_authopenid/views.py:773 #, python-format msgid "OpenID %s is now associated with your account." -msgstr "La OpenID %s está ahora asociada con tu cuenta." +msgstr "El OpenID %s está ahora asociada con tu cuenta." #: django_authopenid/views.py:843 msgid "Account deleted." @@ -349,23 +347,22 @@ msgid "latest questions" msgstr "últimas preguntas" #: forum/feed.py:19 -#, fuzzy msgid "questions/" -msgstr "preguntas" +msgstr "preguntas/" #: forum/forms.py:14 templates/answer_edit_tips.html:34 #: templates/answer_edit_tips.html.py:38 templates/question_edit_tips.html:31 #: templates/question_edit_tips.html:36 msgid "title" -msgstr "titulo" +msgstr "título" #: forum/forms.py:15 msgid "please enter a descriptive title for your question" -msgstr "ingrese un titulo descriptivo para su pregunta" +msgstr "ingrese un título descriptivo para su pregunta" #: forum/forms.py:20 msgid "title must be > 10 characters" -msgstr "el titulo debe tener al menos 10 caracteres" +msgstr "el título debe tener al menos 10 caracteres" #: forum/forms.py:29 msgid "content" @@ -466,27 +463,27 @@ msgstr "este email ya ha sido registrado, por favor use otro" #: forum/models.py:238 #, fuzzy, python-format msgid "%(author)s modified the question" -msgstr "Cerrar la pregunta" +msgstr "%(author) modificó la pregunta" #: forum/models.py:242 #, python-format msgid "%(people)s posted %(new_answer_count)s new answers" -msgstr "" +msgstr "%(people)s publicaron %(new_answer_count)s nuevas respuestas" #: forum/models.py:247 -#, fuzzy, python-format +#, python-format msgid "%(people)s commented the question" -msgstr "pregunta comentada" +msgstr "%(people)s comentarion la pregunta" #: forum/models.py:252 -#, fuzzy, python-format +#, python-format msgid "%(people)s commented answers" -msgstr "respuesta comentada" +msgstr "%(people)s comentaron la respuesta" #: forum/models.py:254 -#, fuzzy, python-format +#, python-format msgid "%(people)s commented the answer" -msgstr "respuesta comentada" +msgstr "%(people)s comentaron la respuestas" #: forum/models.py:433 templates/badges.html:52 msgid "gold" @@ -585,14 +582,13 @@ msgid "profile - user preferences" msgstr "perfil - preferencia de " #: forum/views.py:304 -#, fuzzy msgid "/account/" -msgstr "cuenta/" +msgstr "/cuenta/" #: forum/views.py:943 #, python-format msgid "subscription saved, %(email)s needs validation" -msgstr "" +msgstr "subscripción guardada, %(email)s necesita validación" #: forum/views.py:1853 msgid "uploading images is limited to users with >60 reputation points" @@ -617,9 +613,8 @@ msgstr "" "Error al subir el archivo. Por favor, contacte al administrador. Gracias. %s" #: forum/management/commands/send_email_alerts.py:35 -#, fuzzy msgid "updates from website" -msgstr "sitio web del usuario" +msgstr "actualizaciones del sitio" #: forum/templatetags/extra_tags.py:139 forum/templatetags/extra_tags.py:168 #: templates/header.html:33 @@ -821,22 +816,21 @@ msgid "Ask a question" msgstr "Preguntar" #: templates/ask.html:67 -#, fuzzy msgid "login to post question info" -msgstr "<strong>Más recientes</strong> preguntas son mostradas primero." +msgstr "Inicie sesión para publicar pregunta." #: templates/ask.html:73 #, python-format msgid "must have valid %(email)s to post" -msgstr "" +msgstr "debe de tener un %(email)s válido para publicar" #: templates/ask.html:108 msgid "(required)" -msgstr "" +msgstr "(requerido)" #: templates/ask.html:115 msgid "Login/signup to post your question" -msgstr "" +msgstr "Iniciar sesión/registrarse para publicar su pregunta" #: templates/ask.html:117 msgid "Ask your question" @@ -863,13 +857,11 @@ msgid "Community gives you awards for your questions, answers and votes." msgstr "La comunidad te da distinciones por tus preguntas, respuestas y votos." #: templates/badges.html:22 -#, fuzzy msgid "" "Below is the list of available badges and number of times each type of badge " "has been awarded." msgstr "" -"La comunidad te condecora con distinciones por tus preguntas, respuestas y " -"votos. Debajo esta la lista de las distinciones disponibles y la cantidad de " +"Debajo esta la lista de las distinciones disponibles y la cantidad de " "veces que han sido asignadas." #: templates/badges.html:49 @@ -1054,7 +1046,7 @@ msgstr "¿Que debo evitar en mis respuestas?" #: templates/faq.html:28 templates/faq.html.py:132 msgid "site title" -msgstr "titulo del sitio" +msgstr "título del sitio" #: templates/faq.html:28 msgid "" @@ -1091,9 +1083,8 @@ msgid "How does reputation system work?" msgstr "¿Cómo funciona el sistema de reputación?" #: templates/faq.html:41 -#, fuzzy msgid "Rep system summary" -msgstr "resumen de modificación" +msgstr "resumen del sistema de reputación" #: templates/faq.html:59 templates/user_votes.html:14 msgid "upvote" @@ -1112,9 +1103,8 @@ msgid "downvote" msgstr "votar negativo" #: templates/faq.html:75 -#, fuzzy msgid "open and close own questions" -msgstr "abrir cualquier pregunta cerrada" +msgstr "abrir y cerrar sus propias preguntas" #: templates/faq.html:79 msgid "retag questions" @@ -1144,19 +1134,19 @@ msgstr "" #: templates/faq.html:106 msgid "how to validate email title" -msgstr "" +msgstr "como validar el título del correo" #: templates/faq.html:108 msgid "how to validate email info" -msgstr "" +msgstr "como validar la información del correo" #: templates/faq.html:112 msgid "what is gravatar" -msgstr "" +msgstr "qué es gravatar" #: templates/faq.html:113 msgid "gravatar faq info" -msgstr "" +msgstr "preguntas frecuentes sobre gravatar" #: templates/faq.html:116 msgid "To register, do I need to create new password?" @@ -1211,7 +1201,7 @@ msgstr "preguntas" #: templates/faq.html:132 templates/index.html:121 msgid "." -msgstr "" +msgstr "." #: templates/footer.html:7 templates/header.html:14 templates/index.html:83 msgid "about" @@ -1365,7 +1355,6 @@ msgid "Still looking for more? See" msgstr "¿Aún sigues buscando más? Ver" #: templates/index.html:121 -#, fuzzy msgid "complete list of questions" msgstr "lista completa de preguntas" @@ -1378,9 +1367,8 @@ msgid "Please help us answer" msgstr "Ayudanos a responder" #: templates/index.html:121 -#, fuzzy msgid "list of unanswered questions" -msgstr "sin respuesta" +msgstr "lista de preguntas sin respuesta" #: templates/logout.html:6 templates/logout.html.py:17 msgid "Logout" @@ -1696,7 +1684,7 @@ msgstr "Encontradas por etiqueta" #: templates/questions.html:23 msgid "Found by title" -msgstr "Encontradas por titulo" +msgstr "Encontradas por título" #: templates/questions.html:23 msgid "All questions" @@ -1715,7 +1703,7 @@ msgid "active" msgstr "actividad" #: templates/questions.html:109 -#, fuzzy, python-format +#, python-format msgid "" "\n" "\t\t\thave total %(q_num)s questions tagged %(tagname)s\n" @@ -1724,8 +1712,12 @@ msgid_plural "" "\n" "\t\t\thave total %(q_num)s questions tagged %(tagname)s\n" "\t\t\t" -msgstr[0] "ver preguntas etiquetadas '%(tagname)s'" -msgstr[1] "ver pregunta etiquetada '%(tagname)s'" +msgstr[0] "\n" +"\t\t\ttiene un total de %(q_num)s preguntas etiquetadas con %(tagname)s\n" +"\t\t\t" +msgstr[1] "\n" +"\t\t\ttiene un total de %(q_num)s preguntas etiquetadas con %(tagname)s\n" +"\t\t\t" #: templates/questions.html:116 #, fuzzy, python-format @@ -1941,27 +1933,24 @@ msgid "Connect with Twitter" msgstr "" #: templates/user_preferences.html:12 -#, fuzzy msgid "Twitter account name:" -msgstr "Esta cuenta esta inactiva." +msgstr "Nombre de usuario en Twitter:" #: templates/user_preferences.html:14 -#, fuzzy msgid "Twitter password:" -msgstr "Nueva contraseña" +msgstr "Contraseña de Twitter:" #: templates/user_preferences.html:16 msgid "Send my Questions to Twitter" -msgstr "" +msgstr "Enviar mis preguntas a Twitter" #: templates/user_preferences.html:17 msgid "Send my Answers to Twitter" -msgstr "" +msgstr "Enviar mis respuestas a Twitter" #: templates/user_preferences.html:18 -#, fuzzy msgid "Save" -msgstr "Guardar la edición" +msgstr "Guardar" #: templates/user_stats.html:15 msgid "User questions" @@ -2064,7 +2053,7 @@ msgstr "Cambiar dirección email" #: templates/authopenid/changeemail.html:10 #, fuzzy, python-format msgid "change %(email)s info" -msgstr "Cambiar email " +msgstr "Cambiar información del correo electrónico " #: templates/authopenid/changeemail.html:13 #: templates/authopenid/changeopenid.html:14 @@ -2093,9 +2082,8 @@ msgid "validate %(email)s info" msgstr "" #: templates/authopenid/changeemail.html:50 -#, fuzzy msgid "Email not changed" -msgstr "Email modificado." +msgstr "Email no modificado." #: templates/authopenid/changeemail.html:53 #, python-format @@ -2103,7 +2091,6 @@ msgid "old %(email)s kept" msgstr "" #: templates/authopenid/changeemail.html:58 -#, fuzzy msgid "Email changed" msgstr "Email modificado." @@ -2114,15 +2101,15 @@ msgstr "" #: templates/authopenid/changeemail.html:66 msgid "Email verified" -msgstr "" +msgstr "Email verificado" #: templates/authopenid/changeemail.html:69 msgid "thanks for verifying email" -msgstr "" +msgstr "gracias por verificar su correo" #: templates/authopenid/changeemail.html:74 msgid "email key not sent" -msgstr "" +msgstr "llave de correo no enviada" #: templates/authopenid/changeemail.html:77 #, python-format @@ -2197,7 +2184,6 @@ msgid "Screen name label" msgstr "" #: templates/authopenid/complete.html:48 -#, fuzzy msgid "Email address label" msgstr "su email (correo electrónico)" @@ -2231,11 +2217,10 @@ msgstr "" #: templates/authopenid/confirm_email.txt:4 msgid "Your account details are:" -msgstr "" +msgstr "Los detalles de su cuenta son:" #: templates/authopenid/confirm_email.txt:6 #: templates/authopenid/sendpw_email.txt:7 -#, fuzzy msgid "Username:" msgstr "Nombre de usuario" @@ -2246,7 +2231,7 @@ msgstr "Contraseña" #: templates/authopenid/confirm_email.txt:9 msgid "Please sign in here:" -msgstr "" +msgstr "Por favor inicie sesión aquí:" #: templates/authopenid/confirm_email.txt:12 #: templates/authopenid/email_validation.txt:14 @@ -2294,11 +2279,11 @@ msgstr "" #: templates/authopenid/email_validation.txt:4 msgid "To make use of the Forum, please follow the link below:" -msgstr "" +msgstr "Para usar el Foro, siga el siguiente enlace:" #: templates/authopenid/email_validation.txt:8 msgid "Following the link above will help us verify your email address." -msgstr "" +msgstr "El siguiente enlace nos ayudará a verificar su correo electrónico." #: templates/authopenid/email_validation.txt:10 msgid "" @@ -2355,7 +2340,6 @@ msgid "Your new account details are:" msgstr "" #: templates/authopenid/sendpw_email.txt:8 -#, fuzzy msgid "New password:" msgstr "Nueva contraseña" @@ -2441,7 +2425,6 @@ msgid "Login name" msgstr "Nombre de usuario" #: templates/authopenid/signin.html:141 -#, fuzzy msgid "Create new account" msgstr "Crear cuenta nueva" diff --git a/templates/reopen.html b/templates/reopen.html index 7ab59421..37fb69c1 100644 --- a/templates/reopen.html +++ b/templates/reopen.html @@ -1,5 +1,5 @@ -<!-- reopen.html --> {% extends "base_content.html" %} +<!-- reopen.html --> {% load extra_tags %} {% load i18n %} {% load humanize %} @@ -34,7 +34,4 @@ </form> </div> {% endblock %} - - - <!-- end reopen.html --> |