from datetime import datetime import random import string import logging from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy from askbot.models.post import Post from askbot.models.base import BaseQuerySetManager from askbot.conf import settings as askbot_settings from askbot import mail class ReplyAddressManager(BaseQuerySetManager): """A manager for the :class:`ReplyAddress` model""" def get_unused(self, address, allowed_from_email): return self.get( address = address, allowed_from_email = allowed_from_email, used_at__isnull = True ) def create_new(self, **kwargs): """creates a new reply address""" kwargs['allowed_from_email'] = kwargs['user'].email reply_address = ReplyAddress(**kwargs) while True: reply_address.address = ''.join(random.choice(string.letters + string.digits) for i in xrange(random.randint(12, 25))).lower() if self.filter(address = reply_address.address).count() == 0: break reply_address.save() return reply_address REPLY_ACTION_CHOICES = ( ('post_answer', ugettext_lazy('Post an answer')), ('post_comment', ugettext_lazy('Post a comment')), ('replace_content', ugettext_lazy('Edit post')), ('append_content', ugettext_lazy('Append to post')), ('auto_answer_or_comment', ugettext_lazy('Answer or comment, depending on the size of post')), ('validate_email', ugettext_lazy('Validate email and record signature')), ) class ReplyAddress(models.Model): """Stores a reply address for the post and the user""" address = models.CharField(max_length = 25, unique = True) post = models.ForeignKey( Post, null = True,#reply not necessarily to posts related_name = 'reply_addresses' )#the emailed post reply_action = models.CharField( max_length = 32, choices = REPLY_ACTION_CHOICES, default = 'auto_answer_or_comment' ) response_post = models.ForeignKey( Post, null = True, related_name = 'edit_addresses' ) user = models.ForeignKey(User) allowed_from_email = models.EmailField(max_length = 150) used_at = models.DateTimeField(null = True, default = None) objects = ReplyAddressManager() class Meta: app_label = 'askbot' db_table = 'askbot_replyaddress' @property def was_used(self): """True if was used""" return self.used_at != None def as_email_address(self, prefix = 'reply-'): """returns email address, prefix is added in front of the code""" return '%s%s@%s' % ( prefix, self.address, askbot_settings.REPLY_BY_EMAIL_HOSTNAME ) def edit_post( self, body_text, title = None, edit_response = False ): """edits the created post upon repeated response to the same address""" if self.was_used or edit_response: reply_action = 'append_content' else: reply_action = self.reply_action if edit_response: post = self.response_post else: post = self.post if reply_action == 'append_content': body_text = post.text + '\n\n' + body_text revision_comment = _('added content by email') else: assert(reply_action == 'replace_content') revision_comment = _('edited by email') if post.post_type == 'question': assert(post is self.post) self.user.edit_question( question = post, body_text = body_text, title = title, revision_comment = revision_comment, by_email = True ) else: self.user.edit_post( post = post, body_text = body_text, revision_comment = revision_comment, by_email = True ) self.post.thread.invalidate_cached_data() def create_reply(self, body_text): """creates a reply to the post which was emailed to the user """ result = None if self.post.post_type == 'answer': result = self.user.post_comment( self.post, body_text, by_email = True ) elif self.post.post_type == 'question': if self.reply_action == 'auto_answer_or_comment': wordcount = len(body_text)/6#todo: this is a simplistic hack if wordcount > askbot_settings.MIN_WORDS_FOR_ANSWER_BY_EMAIL: reply_action = 'post_answer' else: reply_action = 'post_comment' else: reply_action = self.reply_action if reply_action == 'post_answer': result = self.user.post_answer( self.post, body_text, by_email = True ) elif reply_action == 'post_comment': result = self.user.post_comment( self.post, body_text, by_email = True ) else: logging.critical( 'Unexpected reply action: "%s", post by email failed' % reply_action ) return None#todo: there may be a better action to take here... elif self.post.post_type == 'comment': result = self.user.post_comment( self.post.parent, body_text, by_email = True ) result.thread.invalidate_cached_data() self.response_post = result self.used_at = datetime.now() self.save() return result