# encoding:utf-8
import datetime
import hashlib
from urllib import quote_plus, urlencode
from django.db import models, IntegrityError
from django.utils.http import urlquote as django_urlquote
from django.utils.html import strip_tags
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.template.defaultfilters import slugify
from django.db.models.signals import post_delete, post_save, pre_save
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
import django.dispatch
import settings
import logging
if settings.USE_SPHINX_SEARCH == True:
from djangosphinx.models import SphinxSearch
from forum.managers import *
from const import *
def get_object_comments(self):
comments = self.comments.all().order_by('id')
return comments
def post_get_last_update_info(self):
when = self.added_at
who = self.author
if self.last_edited_at and self.last_edited_at > when:
when = self.last_edited_at
who = self.last_edited_by
comments = self.comments.all()
if len(comments) > 0:
for c in comments:
if c.added_at > when:
when = c.added_at
who = c.user
return when, who
class EmailFeedSetting(models.Model):
DELTA_TABLE = {
'w':datetime.timedelta(7),
'd':datetime.timedelta(1),
'n':datetime.timedelta(-1),
}
FEED_TYPES = (
('q_all',_('Entire forum')),
('q_ask',_('Questions that I asked')),
('q_ans',_('Questions that I answered')),
('q_sel',_('Individually selected questions')),
)
UPDATE_FREQUENCY = (
('w',_('Weekly')),
('d',_('Daily')),
('n',_('No email')),
)
subscriber = models.ForeignKey(User)
feed_type = models.CharField(max_length=16,choices=FEED_TYPES)
frequency = models.CharField(max_length=8,choices=UPDATE_FREQUENCY,default='n')
added_at = models.DateTimeField(auto_now_add=True)
reported_at = models.DateTimeField(null=True)
def save(self,*args,**kwargs):
type = self.feed_type
subscriber = self.subscriber
similar = self.__class__.objects.filter(feed_type=type,subscriber=subscriber).exclude(pk=self.id)
if len(similar) > 0:
raise IntegrityError('email feed setting already exists')
super(EmailFeedSetting,self).save(*args,**kwargs)
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')
# 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)
followed_by = models.ManyToManyField(User, related_name='followed_questions')
# 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)
if settings.USE_SPHINX_SEARCH == True:
search = SphinxSearch(
index=' '.join(settings.SPHINX_SEARCH_INDICES),
mode='SPH_MATCH_ALL',
)
logging.debug('have sphinx search')
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 tagname_meta_generator(self):
return u','.join([unicode(tag) for tag in self.tagname_list()])
def get_absolute_url(self):
return '%s%s' % (reverse('question', args=[self.id]), django_urlquote(slugify(self.title)))
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]
get_comments = get_object_comments
def get_last_update_info(self):
when, who = post_get_last_update_info(self)
answers = self.answers.all()
if len(answers) > 0:
for a in answers:
a_when, a_who = a.get_last_update_info()
if a_when > when:
when = a_when
who = a_who
return when, who
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 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 = '%s:
\n' % (url,self.title)
out = map(lambda x: '
' + x + '',out)
retval += '
\n'
return retval
else:
return None
def __unicode__(self):
return self.title
class Meta:
db_table = u'question'
class QuestionView(models.Model):
question = models.ForeignKey(Question, related_name='viewed')
who = models.ForeignKey(User, related_name='question_views')
when = models.DateTimeField()
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 MarkedTag(models.Model):
TAG_MARK_REASONS = (('good',_('interesting')),('bad',_('ignored')))
tag = models.ForeignKey(Tag)
user = models.ForeignKey(User)
reason = models.CharField(max_length=16, choices=TAG_MARK_REASONS)
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):
print 'in QuestionRevision.get_absolute_url()'
return reverse('question_revisions', args=[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()
get_comments = get_object_comments
get_last_update_info = post_get_last_update_info
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]), django_urlquote(slugify(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 reverse('answer_revisions', kwargs={'id':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 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 reverse('book', args=[django_urlquote(slugify(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)
# User extend properties
QUESTIONS_PER_PAGE_CHOICES = (
(10, u'10'),
(30, u'30'),
(50, u'50'),
)
def user_is_username_taken(cls,username):
try:
cls.objects.get(username=username)
return True
except cls.MultipleObjectsReturned:
return True
except cls.DoesNotExist:
return False
def user_get_q_sel_email_feed_frequency(self):
print 'looking for frequency for user %s' % self
try:
feed_setting = EmailFeedSetting.objects.get(subscriber=self,feed_type='q_sel')
except Exception, e:
print 'have error %s' % e.message
raise e
print 'have freq=%s' % feed_setting.frequency
return feed_setting.frequency
User.add_to_class('is_approved', models.BooleanField(default=False))
User.add_to_class('email_isvalid', models.BooleanField(default=False))
User.add_to_class('email_key', models.CharField(max_length=32, 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('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))
User.add_to_class('is_username_taken',classmethod(user_is_username_taken))
User.add_to_class('get_q_sel_email_feed_frequency',user_get_q_sel_email_feed_frequency)
User.add_to_class('hide_ignored_questions', models.BooleanField(default=False))
User.add_to_class('tag_filter_setting',
models.CharField(
max_length=16,
choices=TAG_EMAIL_FILTER_CHOICES,
default='ignored'
)
)
# 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]), slugify(self.username))
def get_profile_link(self):
profile_link = u'%s' % (self.get_profile_url(),self.username)
logging.debug('in get profile link %s' % profile_link)
return mark_safe(profile_link)
User.add_to_class('get_profile_url', get_profile_url)
User.add_to_class('get_profile_link', get_profile_link)
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
if (instance.content_type_id == question_type_id):
type = TYPE_ACTIVITY_COMMENT_QUESTION
else:
type = 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)