Exemple #1
0
def VALIDATE_EMAIL(parts=None,
                   reply_address_object=None,
                   from_address=None,
                   **kwargs):
    """process the validation email and save
    the email signature
    todo: go a step further and
    """
    reply_code = reply_address_object.address
    try:
        content, stored_files, signature = mail.process_parts(
            parts, reply_code)
        user = reply_address_object.user
        if signature and signature != user.email_signature:
            user.email_signature = signature
        user.email_isvalid = True
        user.save()

        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': askbot_settings.APP_URL,
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(subject_line=_('Re: Welcome to %(site_name)s') % data,
                       body_text=template.render(Context(data)),
                       recipient_list=[
                           from_address,
                       ])
    except ValueError:
        raise ValueError(
            _('Please reply to the welcome email '
              'without editing it'))
Exemple #2
0
def VALIDATE_EMAIL(parts=None, reply_address_object=None, from_address=None, **kwargs):
    """process the validation email and save
    the email signature
    todo: go a step further and
    """
    reply_code = reply_address_object.address
    try:
        content, stored_files, signature = mail.process_parts(parts, reply_code)
        user = reply_address_object.user
        if signature and signature != user.email_signature:
            user.email_signature = signature
        user.email_isvalid = True
        user.save()

        data = {
            "site_name": askbot_settings.APP_SHORT_NAME,
            "site_url": askbot_settings.APP_URL,
            "ask_address": "ask@" + askbot_settings.REPLY_BY_EMAIL_HOSTNAME,
        }
        template = get_template("email/re_welcome_lamson_on.html")

        mail.send_mail(
            subject_line=_("Re: Welcome to %(site_name)s") % data,
            body_text=template.render(Context(data)),
            recipient_list=[from_address],
        )
    except ValueError:
        raise ValueError(_("Please reply to the welcome email " "without editing it"))
Exemple #3
0
def send_instant_notifications_about_activity_in_post(update_activity=None, post=None, recipients=None):
    # reload object from the database
    post = Post.objects.get(id=post.id)
    if post.is_approved() is False:
        return

    if recipients is None:
        return

    acceptable_types = const.RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS

    if update_activity.activity_type not in acceptable_types:
        return

    # calculate some variables used in the loop below
    update_type_map = const.RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES
    update_type = update_type_map[update_activity.activity_type]
    origin_post = post.get_origin_post()
    headers = mail.thread_headers(post, origin_post, update_activity.activity_type)

    logger = logging.getLogger()
    if logger.getEffectiveLevel() <= logging.DEBUG:
        log_id = uuid.uuid1()
        message = "email-alert %s, logId=%s" % (post.get_absolute_url(), log_id)
        logger.debug(message)
    else:
        log_id = None

    for user in recipients:
        if user.is_blocked():
            continue

        reply_address, alt_reply_address = get_reply_to_addresses(user, post)

        subject_line, body_text = format_instant_notification_email(
            to_user=user,
            from_user=update_activity.user,
            post=post,
            reply_address=reply_address,
            alt_reply_address=alt_reply_address,
            update_type=update_type,
            template=get_template("email/instant_notification.html"),
        )

        headers["Reply-To"] = reply_address
        try:
            mail.send_mail(
                subject_line=subject_line,
                body_text=body_text,
                recipient_list=[user.email],
                related_object=origin_post,
                activity_type=const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
                headers=headers,
                raise_on_failure=True,
            )
        except askbot_exceptions.EmailNotSent, error:
            logger.debug("%s, error=%s, logId=%s" % (user.email, error, log_id))
        else:
            logger.debug("success %s, logId=%s" % (user.email, log_id))
def process_reply(func):
    @functools.wraps(func)
    def wrapped(message, host = None, address = None):
        """processes forwarding rules, and run the handler
        in the case of error, send a bounce email
        """

        try:
            for rule in django_settings.LAMSON_FORWARD:
                if re.match(rule['pattern'], message.base['to']):
                    relay = Relay(host=rule['host'],
                               port=rule['port'], debug=1)
                    relay.deliver(message)
                    return
        except AttributeError:
            pass

        error = None

        try:
            reply_address = ReplyAddress.objects.get(
                                            address = address,
                                            allowed_from_email = message.From
                                        )

            #here is the business part of this function
            parts = get_parts(message)
            for part_type, content in parts:
                if part_type == 'body':
                    print '==============================='
                    print 'message :', content
                    break
                else:
                    continue
            func(
                from_address = message.From,
                subject_line = message['Subject'],
                parts = parts,
                reply_address_object = reply_address
            )

        except ReplyAddress.DoesNotExist:
            error = _("You were replying to an email address\
             unknown to the system or you were replying from a different address from the one where you\
             received the notification.")
        except Exception, e:
            import sys
            sys.stderr.write(str(e))
            import traceback
            sys.stderr.write(traceback.format_exc())

        if error is not None:
            template = get_template('email/reply_by_email_error.html')
            body_text = template.render(Context({'error':error}))
            mail.send_mail(
                subject_line = "Error posting your reply",
                body_text = body_text,
                recipient_list = [message.From],
            )
def notify_moderator(user):
    template = get_template('email/notify_moderator.html')
    subject_line = _('%s moderation alert') % askbot_settings.APP_SHORT_NAME,
    mail.send_mail(
        subject_line=subject_line,
        body_text=template.render({'user': user}),
        recipient_list=[user,]
    )
Exemple #6
0
def notify_moderator(user):
    template = get_template('email/notify_moderator.html')
    subject_line = _('%s moderation alert') % askbot_settings.APP_SHORT_NAME,
    mail.send_mail(subject_line=subject_line,
                   body_text=template.render({'user': user}),
                   recipient_list=[
                       user,
                   ])
Exemple #7
0
def PROCESS(parts=None,
            reply_address_object=None,
            subject_line=None,
            from_address=None,
            **kwargs):
    """handler to process the emailed message
    and make a post to askbot based on the contents of
    the email, including the text body and the file attachments"""
    #1) get actual email content
    #   todo: factor this out into the process_reply decorator
    reply_code = reply_address_object.address
    body_text, stored_files, signature = mail.process_parts(parts, reply_code)

    #2) process body text and email signature
    user = reply_address_object.user
    if signature is not None:  #if there, then it was stripped
        if signature != user.email_signature:
            user.email_signature = signature
    else:  #try to strip signature
        stripped_body_text = user.strip_email_signature(body_text)
        #todo: add test cases for emails without the signature
        if stripped_body_text == body_text and user.email_signature:
            #todo: send an email asking to update the signature
            raise ValueError('email signature changed or unknown')
        body_text = stripped_body_text

    #3) validate email address and save user
    user.email_isvalid = True
    user.save()  #todo: actually, saving is not necessary, if nothing changed

    #4) actually make an edit in the forum
    robj = reply_address_object
    add_post_actions = ('post_comment', 'post_answer',
                        'auto_answer_or_comment')
    if robj.reply_action == 'replace_content':
        robj.edit_post(body_text, title=subject_line)
    elif robj.reply_action == 'append_content':
        robj.edit_post(body_text)  #in this case we don't touch the title
    elif robj.reply_action in add_post_actions:
        if robj.was_used:
            robj.edit_post(body_text, edit_response=True)
        else:
            robj.create_reply(body_text)
    elif robj.reply_action == 'validate_email':
        #todo: this is copy-paste - factor it out to askbot.mail.messages
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': askbot_settings.APP_URL,
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(
            subject_line=_('Re: %s') % subject_line,
            body_text=template.render(Context(data)),  #todo: set lang
            recipient_list=[
                from_address,
            ])
def PROCESS(
    parts = None,
    reply_address_object = None,
    subject_line = None,
    from_address = None,
    **kwargs
):
    """handler to process the emailed message
    and make a post to askbot based on the contents of
    the email, including the text body and the file attachments"""
    #1) get actual email content 
    #   todo: factor this out into the process_reply decorator
    reply_code = reply_address_object.address
    body_text, stored_files, signature = mail.process_parts(parts, reply_code)

    #2) process body text and email signature
    user = reply_address_object.user
    if signature:#if there, then it was stripped
        if signature != user.email_signature:
            user.email_signature = signature
    else:#try to strip signature
        stripped_body_text = user.strip_email_signature(body_text)
        #todo: add test cases for emails without the signature
        if stripped_body_text == body_text and user.email_signature:
            #todo: send an email asking to update the signature
            raise ValueError('email signature changed or unknown')
        body_text = stripped_body_text

    #3) validate email address and save user
    user.email_isvalid = True
    user.save()#todo: actually, saving is not necessary, if nothing changed

    #4) actually make an edit in the forum
    robj = reply_address_object
    add_post_actions = ('post_comment', 'post_answer', 'auto_answer_or_comment')
    if robj.reply_action == 'replace_content':
        robj.edit_post(body_text, title = subject_line)
    elif robj.reply_action == 'append_content':
        robj.edit_post(body_text)#in this case we don't touch the title
    elif robj.reply_action in add_post_actions:
        if robj.was_used:
            robj.edit_post(body_text, edit_response = True)
        else:
            robj.create_reply(body_text)
    elif robj.reply_action == 'validate_email':
        #todo: this is copy-paste - factor it out to askbot.mail.messages
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': askbot_settings.APP_URL,
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(
            subject_line = _('Re: %s') % subject_line,
            body_text = template.render(Context(data)),
            recipient_list = [from_address,]
        )
Exemple #9
0
def PROCESS(parts=None,
            reply_address_object=None,
            subject_line=None,
            from_address=None,
            **kwargs):
    """handler to process the emailed message
    and make a post to askbot based on the contents of
    the email, including the text body and the file attachments"""
    #1) get actual email content
    #   todo: factor this out into the process_reply decorator
    reply_code = reply_address_object.address
    body_text, stored_files, signature = mail.process_parts(
        parts, reply_code, from_address)

    #2) process body text and email signature
    user = reply_address_object.user

    if signature != user.email_signature:
        user.email_signature = signature

    #3) validate email address and save user along with maybe new signature
    user.email_isvalid = True
    user.save()  #todo: actually, saving is not necessary, if nothing changed

    #here we might be in danger of chomping off some of the
    #message is body text ends with a legitimate text coinciding with
    #the user's email signature
    body_text = user.strip_email_signature(body_text)

    #4) actually make an edit in the forum
    robj = reply_address_object
    add_post_actions = ('post_comment', 'post_answer',
                        'auto_answer_or_comment')
    if robj.reply_action == 'replace_content':
        robj.edit_post(body_text, title=subject_line)
    elif robj.reply_action == 'append_content':
        robj.edit_post(body_text)  #in this case we don't touch the title
    elif robj.reply_action in add_post_actions:
        if robj.was_used:
            robj.edit_post(body_text, edit_response=True)
        else:
            robj.create_reply(body_text)
    elif robj.reply_action == 'validate_email':
        #todo: this is copy-paste - factor it out to askbot.mail.messages
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': site_url(reverse('questions')),
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(
            subject_line=_('Re: %s') % subject_line,
            body_text=template.render(Context(data)),  #todo: set lang
            recipient_list=[
                from_address,
            ])
Exemple #10
0
def notify_author_of_published_revision_celery_task(revision):
    #todo: move this to ``askbot.mail`` module
    #for answerable email only for now, because
    #we don't yet have the template for the read-only notification

    data = {
        'site_name': askbot_settings.APP_SHORT_NAME,
        'post': revision.post
    }
    headers = None

    if askbot_settings.REPLY_BY_EMAIL:
        #generate two reply codes (one for edit and one for addition)
        #to format an answerable email or not answerable email
        reply_options = {
            'user': revision.author,
            'post': revision.post,
            'reply_action': 'append_content'
        }
        append_content_address = ReplyAddress.objects.create_new(
                                                        **reply_options
                                                    ).as_email_address()
        reply_options['reply_action'] = 'replace_content'
        replace_content_address = ReplyAddress.objects.create_new(
                                                        **reply_options
                                                    ).as_email_address()

        #populate template context variables
        reply_code = append_content_address + ',' + replace_content_address
        if revision.post.post_type == 'question':
            mailto_link_subject = revision.post.thread.title
        else:
            mailto_link_subject = _('make an edit by email')
        #todo: possibly add more mailto thread headers to organize messages

        prompt = _('To add to your post EDIT ABOVE THIS LINE')
        reply_separator_line = const.SIMPLE_REPLY_SEPARATOR_TEMPLATE % prompt
        data['reply_code'] = reply_code
        data['author_email_signature'] = revision.author.email_signature
        data['replace_content_address'] = replace_content_address
        data['reply_separator_line'] = reply_separator_line
        data['mailto_link_subject'] = mailto_link_subject
        headers = {'Reply-To': append_content_address}

    #load the template
    activate_language(revision.post.language_code)
    template = get_template('email/notify_author_about_approved_post.html')
    #todo: possibly add headers to organize messages in threads
    #send the message
    mail.send_mail(
        subject_line = _('Your post at %(site_name)s is now published') % data,
        body_text = template.render(Context(data)),
        recipient_list = [revision.author.email,],
        related_object = revision,
        activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
        headers = headers
    )
Exemple #11
0
def process_reply(func):
    @functools.wraps(func)
    def wrapped(message, host=None, address=None):
        """processes forwarding rules, and run the handler
        in the case of error, send a bounce email
        """

        try:
            for rule in django_settings.LAMSON_FORWARD:
                if re.match(rule['pattern'], message.base['to']):
                    relay = Relay(host=rule['host'],
                                  port=rule['port'],
                                  debug=1)
                    relay.deliver(message)
                    return
        except AttributeError:
            pass

        error = None

        try:
            reply_address = ReplyAddress.objects.get(
                address=address, allowed_from_email=message.From)

            #here is the business part of this function
            parts = get_parts(message)
            for part_type, content in parts:
                if part_type == 'body':
                    print '==============================='
                    print 'message :', content
                    break
                else:
                    continue
            func(from_address=message.From,
                 subject_line=message['Subject'],
                 parts=parts,
                 reply_address_object=reply_address)

        except ReplyAddress.DoesNotExist:
            error = _("You were replying to an email address\
             unknown to the system or you were replying from a different address from the one where you\
             received the notification.")
        except Exception, e:
            import sys
            sys.stderr.write(str(e))
            import traceback
            sys.stderr.write(traceback.format_exc())

        if error is not None:
            template = get_template('email/reply_by_email_error.html')
            body_text = template.render(Context({'error': error}))
            mail.send_mail(
                subject_line="Error posting your reply",
                body_text=body_text,
                recipient_list=[message.From],
            )
def PROCESS(
    parts = None,
    reply_address_object = None,
    subject_line = None,
    from_address = None,
    **kwargs
):
    """handler to process the emailed message
    and make a post to askbot based on the contents of
    the email, including the text body and the file attachments"""
    #1) get actual email content
    #   todo: factor this out into the process_reply decorator
    reply_code = reply_address_object.address
    body_text, stored_files, signature = mail.process_parts(parts, reply_code)

    #2) process body text and email signature
    user = reply_address_object.user

    if signature != user.email_signature:
        user.email_signature = signature

    #3) validate email address and save user along with maybe new signature
    user.email_isvalid = True
    user.save()#todo: actually, saving is not necessary, if nothing changed

    #here we might be in danger of chomping off some of the 
    #message is body text ends with a legitimate text coinciding with
    #the user's email signature
    body_text = user.strip_email_signature(body_text)

    #4) actually make an edit in the forum
    robj = reply_address_object
    add_post_actions = ('post_comment', 'post_answer', 'auto_answer_or_comment')
    if robj.reply_action == 'replace_content':
        robj.edit_post(body_text, title = subject_line)
    elif robj.reply_action == 'append_content':
        robj.edit_post(body_text)#in this case we don't touch the title
    elif robj.reply_action in add_post_actions:
        if robj.was_used:
            robj.edit_post(body_text, edit_response = True)
        else:
            robj.create_reply(body_text)
    elif robj.reply_action == 'validate_email':
        #todo: this is copy-paste - factor it out to askbot.mail.messages
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': site_url(reverse('questions')),
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(
            subject_line = _('Re: %s') % subject_line,
            body_text = template.render(Context(data)),#todo: set lang
            recipient_list = [from_address,]
        )
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER,
            askbot_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY,
            askbot_settings.MAX_ACCEPT_ANSWER_REMINDERS)

        questions = models.Post.objects.get_questions().exclude(
            deleted=True).added_between(
                start=schedule.start_cutoff_date, end=schedule.end_cutoff_date
            ).filter(thread__answer_count__gt=0).filter(
                thread__accepted_answer__isnull=True  #answer_accepted = False
            ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status='b'):
            user_questions = questions.filter(author=user)

            final_question_list = user_questions.get_questions_needing_reminder(
                activity_type=const.TYPE_ACTIVITY_ACCEPT_ANSWER_REMINDER_SENT,
                user=user,
                recurrence_delay=schedule.recurrence_delay)
            #todo: rewrite using query set filter
            #may be a lot more efficient

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            reminder_phrase = _('Please select the best responses to:')

            data = {
                'site_url': site_url(''),  #here we need only the domain name
                'questions': final_question_list,
                'reminder_phrase': reminder_phrase,
                'recipient_user': user
            }

            template = get_template('email/accept_answer_reminder.html')
            body_text = template.render(Context(data))  #todo: set lang

            subject_line = askbot_settings.WORDS_ACCEPT_BEST_ANSWERS_FOR_YOUR_QUESTIONS
            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(subject_line=subject_line,
                               body_text=body_text,
                               recipient_list=(user.email, ))
Exemple #14
0
def feedback(request):
    data = {'page_class': 'meta'}
    form = None

    if askbot_settings.ALLOW_ANONYMOUS_FEEDBACK is False:
        if request.user.is_anonymous():
            message = _('Please sign in or register to send your feedback')
            request.user.message_set.create(message=message)
            redirect_url = get_login_url() + '?next=' + request.path
            return HttpResponseRedirect(redirect_url)

    if request.method == "POST":
        form = FeedbackForm(
            is_auth=request.user.is_authenticated(),
            data=request.POST
        )
        if form.is_valid():

            if not request.user.is_authenticated():
                data['email'] = form.cleaned_data.get('email', None)
            else:
                data['email'] = request.user.email

            data['message'] = form.cleaned_data['message']
            data['name'] = form.cleaned_data.get('name', None)
            template = get_template('email/feedback_email.txt')
            message = template.render(RequestContext(request, data))

            headers = {}
            if data['email']:
                headers = {'Reply-To': data['email']}
            subject = _('Q&A forum feedback')
            if askbot_settings.FEEDBACK_EMAILS:
                recipients = re.split('\s*,\s*', askbot_settings.FEEDBACK_EMAILS)
                send_mail(
                    subject_line=subject,
                    body_text=message,
                    headers=headers,
                    recipient_list=recipients,
                )
            else:
                mail_moderators(
                    subject_line=subject,
                    body_text=message,
                    headers=headers
                )
            msg = _('Thanks for the feedback!')
            request.user.message_set.create(message=msg)
            return HttpResponseRedirect(get_next_url(request))
    else:
        form = FeedbackForm(is_auth = request.user.is_authenticated(),
                            initial={'next':get_next_url(request)})

    data['form'] = form
    return render(request, 'feedback.html', data)
Exemple #15
0
def notify_author_of_published_revision_celery_task(revision):
    #todo: move this to ``askbot.mail`` module
    #for answerable email only for now, because
    #we don't yet have the template for the read-only notification
    if askbot_settings.REPLY_BY_EMAIL:
        #generate two reply codes (one for edit and one for addition)
        #to format an answerable email or not answerable email
        reply_options = {
            'user': revision.author,
            'post': revision.post,
            'reply_action': 'append_content'
        }
        append_content_address = ReplyAddress.objects.create_new(
            **reply_options).as_email_address()
        reply_options['reply_action'] = 'replace_content'
        replace_content_address = ReplyAddress.objects.create_new(
            **reply_options).as_email_address()

        #populate template context variables
        reply_code = append_content_address + ',' + replace_content_address
        if revision.post.post_type == 'question':
            mailto_link_subject = revision.post.thread.title
        else:
            mailto_link_subject = _('make an edit by email')
        #todo: possibly add more mailto thread headers to organize messages

        prompt = _('To add to your post EDIT ABOVE THIS LINE')
        reply_separator_line = const.SIMPLE_REPLY_SEPARATOR_TEMPLATE % prompt
        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'post': revision.post,
            'author_email_signature': revision.author.email_signature,
            'replace_content_address': replace_content_address,
            'reply_separator_line': reply_separator_line,
            'mailto_link_subject': mailto_link_subject,
            'reply_code': reply_code
        }

        #load the template
        activate_language(revision.post.language_code)
        template = get_template('email/notify_author_about_approved_post.html')
        #todo: possibly add headers to organize messages in threads
        headers = {'Reply-To': append_content_address}
        #send the message
        mail.send_mail(
            subject_line=_('Your post at %(site_name)s is now published') %
            data,
            body_text=template.render(Context(data)),
            recipient_list=[
                revision.author.email,
            ],
            related_object=revision,
            activity_type=const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
            headers=headers)
Exemple #16
0
def __notify_if_duplicate_subject(subject, user, link):
    presentations = models.Presentation.objects.filter(subject=subject, deleted=False)
    if presentations.count() > 1:
        from askbot import mail, const
        mail.send_mail(
            subject_line = "Duplicate presentation subject",
            body_text = "You may need to change the subject of <a href='http://askbot%s'>this post</a>. <br/> <br/>\
                This mail is sent automatically, please do not reply." % link,
            recipient_list = [user.email],
            activity_type = const.TYPE_ACTIVITY_VALIDATION_EMAIL_SENT,
            headers = {'Reply-To': "*****@*****.**"}
        )
Exemple #17
0
def feedback(request):
    data = {'page_class': 'meta'}
    form = None

    if askbot_settings.ALLOW_ANONYMOUS_FEEDBACK is False:
        if request.user.is_anonymous():
            message = _('Please sign in or register to send your feedback')
            request.user.message_set.create(message=message)
            redirect_url = get_login_url() + '?next=' + request.path
            return HttpResponseRedirect(redirect_url)

    if request.method == "POST":
        form = FeedbackForm(is_auth=request.user.is_authenticated(),
                            data=request.POST)
        if form.is_valid():

            if not request.user.is_authenticated():
                data['email'] = form.cleaned_data.get('email', None)
            else:
                data['email'] = request.user.email

            data['message'] = form.cleaned_data['message']
            data['name'] = form.cleaned_data.get('name', None)
            template = get_template('email/feedback_email.txt')
            message = template.render(RequestContext(request, data))

            headers = {}
            if data['email']:
                headers = {'Reply-To': data['email']}
            subject = _('Q&A forum feedback')
            if askbot_settings.FEEDBACK_EMAILS:
                recipients = re.split('\s*,\s*',
                                      askbot_settings.FEEDBACK_EMAILS)
                send_mail(
                    subject_line=subject,
                    body_text=message,
                    headers=headers,
                    recipient_list=recipients,
                )
            else:
                mail_moderators(subject_line=subject,
                                body_text=message,
                                headers=headers)
            msg = _('Thanks for the feedback!')
            request.user.message_set.create(message=msg)
            return HttpResponseRedirect(get_next_url(request))
    else:
        form = FeedbackForm(is_auth=request.user.is_authenticated(),
                            initial={'next': get_next_url(request)})

    data['form'] = form
    return render(request, 'feedback.html', data)
Exemple #18
0
def send_email_key(email, key, handler_url_name="user_account_recover"):
    """private function. sends email containing validation key
    to user's email address
    """
    subject = _("Recover your %(site)s account") % {"site": askbot_settings.APP_SHORT_NAME}

    data = {
        "site_name": askbot_settings.APP_SHORT_NAME,
        "validation_link": site_url(reverse(handler_url_name)) + "?validation_code=" + key,
    }
    template = get_template("authopenid/email_validation.html")
    message = template.render(data)  # todo: inject language preference
    send_mail(subject, message, django_settings.DEFAULT_FROM_EMAIL, [email])
Exemple #19
0
 def report_exception(self, user):
     """reports exception that happened during sending email alert to user"""
     message = self.format_debug_msg(user, traceback.format_exc())
     print(message)
     admin_email = askbot_settings.ADMIN_EMAIL
     try:
         subject = "Error processing daily/weekly notification for User '%s' for Site '%s'" % (user.username, SITE_ID)
         send_mail(subject_line=subject, body_text=message, recipient_list=[admin_email])
     except:
         message = "ERROR: was unable to report this exception to %s: %s" % (admin_email, traceback.format_exc())
         print(self.format_debug_msg(user, message))
     else:
         message = "Sent email reporting this exception to %s" % admin_email
         print(self.format_debug_msg(user, message))
Exemple #20
0
 def send(self, recipient_list, raise_on_failure=False, headers=None, attachments=None):
     if self.is_enabled():
         from askbot.mail import send_mail
         send_mail(
             subject_line=self.render_subject(),
             body_text=self.render_body(),
             from_email=None,
             recipient_list=recipient_list,
             headers=headers or self.get_headers(),
             raise_on_failure=raise_on_failure,
             attachments=attachments or self.get_attachments()
         )
     else:
         LOG.warning('Attempting to send disabled email "%s"' % force_text(self.title))
Exemple #21
0
 def send(self, recipient_list, raise_on_failure=False, headers=None, attachments=None):
     if self.is_enabled():
         from askbot.mail import send_mail
         send_mail(
             subject_line=self.render_subject(),
             body_text=self.render_body(),
             from_email=None,
             recipient_list=recipient_list,
             headers=headers or self.get_headers(),
             raise_on_failure=raise_on_failure,
             attachments=attachments or self.get_attachments()
         )
     else:
         LOG.warning('Attempting to send disabled email "%s"' % self.title)
    def handle(self, *args, **options):

        if len(args) != 1:
            raise CommandError('Recipients email address required')

        try:
            validate_email(args[0])
        except ValidationError:
            raise CommandError('%s is not a valid email address' % (args[0]))

        send_mail(
            subject_line='Askbot Mail Test',
            body_text='Askbot Mail Test',
            recipient_list=[args[0]],
        )
Exemple #23
0
    def handle(self, *args, **options):

        if len(args) != 1:
            raise CommandError('Recipients email address required')

        try:
            validate_email(args[0])
        except ValidationError:
            raise CommandError('%s is not a valid email address' % (args[0]))

        send_mail(
            subject_line = 'Askbot Mail Test',
            body_text = 'Askbot Mail Test',
            recipient_list = [args[0]],
        )
def VALIDATE_EMAIL(
    parts = None,
    reply_address_object = None,
    from_address = None,
    **kwargs
):
    """process the validation email and save
    the email signature
    todo: go a step further and
    """
    reply_code = reply_address_object.address

    if DEBUG_EMAIL:
        msg = u'Received email validation from %s\n' % from_address
        sys.stderr.write(msg.encode('utf-8'))

    try:
        content, stored_files, signature = mail.process_parts(parts, reply_code)

        user = reply_address_object.user

        if signature != user.email_signature:
            user.email_signature = signature

        user.email_isvalid = True
        user.save()

        data = {
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME,
            'can_post_by_email': user.can_post_by_email(),
            'recipient_user': user,
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': site_url(reverse('questions')),
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(
            subject_line = _('Re: Welcome to %(site_name)s') % data,
            body_text = template.render(Context(data)),#todo: set lang
            recipient_list = [from_address,]
        )
    except ValueError:
        raise ValueError(
            _(
                'Please reply to the welcome email '
                'without editing it'
            )
        )
Exemple #25
0
def send_email_key(email, key, handler_url_name='user_account_recover'):
    """private function. sends email containing validation key
    to user's email address
    """
    subject = _("Recover your %(site)s account") % \
                {'site': askbot_settings.APP_SHORT_NAME}

    url = urlparse(askbot_settings.APP_URL)
    data = {
        'validation_link': url.scheme + '://' + url.netloc + \
                            reverse(handler_url_name) +\
                            '?validation_code=' + key
    }
    template = get_template('authopenid/email_validation.html')
    message = template.render(data)
    send_mail(subject, message, django_settings.DEFAULT_FROM_EMAIL, [email])
Exemple #26
0
def VALIDATE_EMAIL(
    parts = None,
    reply_address_object = None,
    from_address = None,
    **kwargs
):
    """process the validation email and save
    the email signature
    todo: go a step further and
    """
    reply_code = reply_address_object.address

    if DEBUG_EMAIL:
        msg = u'Received email validation from %s\n' % from_address
        sys.stderr.write(msg.encode('utf-8'))

    try:
        content, stored_files, signature = mail.process_parts(parts, reply_code)

        user = reply_address_object.user

        if signature != user.email_signature:
            user.email_signature = signature

        user.email_isvalid = True
        user.save()

        data = {
            'site_name': askbot_settings.APP_SHORT_NAME,
            'site_url': site_url(reverse('questions')),
            'ask_address': 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME,
            'can_post_by_email': user.can_post_by_email()
        }
        template = get_template('email/re_welcome_lamson_on.html')

        mail.send_mail(
            subject_line = _('Re: Welcome to %(site_name)s') % data,
            body_text = template.render(Context(data)),#todo: set lang
            recipient_list = [from_address,]
        )
    except ValueError:
        raise ValueError(
            _(
                'Please reply to the welcome email '
                'without editing it'
            )
        )
Exemple #27
0
def notify_author_of_published_revision_celery_task(revision):
    # todo: move this to ``askbot.mail`` module
    # for answerable email only for now, because
    # we don't yet have the template for the read-only notification
    if askbot_settings.REPLY_BY_EMAIL:
        # generate two reply codes (one for edit and one for addition)
        # to format an answerable email or not answerable email
        reply_options = {"user": revision.author, "post": revision.post, "reply_action": "append_content"}
        append_content_address = ReplyAddress.objects.create_new(**reply_options).as_email_address()
        reply_options["reply_action"] = "replace_content"
        replace_content_address = ReplyAddress.objects.create_new(**reply_options).as_email_address()

        # populate template context variables
        reply_code = append_content_address + "," + replace_content_address
        if revision.post.post_type == "question":
            mailto_link_subject = revision.post.thread.title
        else:
            mailto_link_subject = _("An edit for my answer")
        # todo: possibly add more mailto thread headers to organize messages

        prompt = _("To add to your post EDIT ABOVE THIS LINE")
        reply_separator_line = const.SIMPLE_REPLY_SEPARATOR_TEMPLATE % prompt
        data = {
            "site_name": askbot_settings.APP_SHORT_NAME,
            "post": revision.post,
            "author_email_signature": revision.author.email_signature,
            "replace_content_address": replace_content_address,
            "reply_separator_line": reply_separator_line,
            "mailto_link_subject": mailto_link_subject,
            "reply_code": reply_code,
        }

        # load the template
        template = get_template("email/notify_author_about_approved_post.html")
        # todo: possibly add headers to organize messages in threads
        headers = {"Reply-To": append_content_address}
        # send the message
        mail.send_mail(
            subject_line=_("Your post at %(site_name)s is now published") % data,
            body_text=template.render(Context(data)),
            recipient_list=[revision.author.email],
            related_object=revision,
            activity_type=const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
            headers=headers,
        )
Exemple #28
0
 def report_exception(self, user):
     """reports exception that happened during sending email alert to user"""
     message = self.format_debug_msg(user, traceback.format_exc())
     print(message)
     admin_email = askbot_settings.ADMIN_EMAIL
     try:
         subject = "Error processing daily/weekly notification for User '%s' for Site '%s'" % (
             user.username, SITE_ID)
         send_mail(subject_line=subject,
                   body_text=message,
                   recipient_list=[admin_email])
     except:
         message = "ERROR: was unable to report this exception to %s: %s" % (
             admin_email, traceback.format_exc())
         print(self.format_debug_msg(user, message))
     else:
         message = "Sent email reporting this exception to %s" % admin_email
         print(self.format_debug_msg(user, message))
Exemple #29
0
 def send_email_alert(self):
     """signal handler for the message post-save"""
     root_message = self.get_root_message()
     data = {
         'messages': self.get_timeline(),
         'message': self,
     }
     for user in self.get_recipients_users():
         # todo change url scheme so that all users have the same
         # urls within their personal areas of the user profile
         # so that we don't need to have loops like this one
         thread_url = root_message.get_absolute_url(user)
         thread_url = thread_url.replace('&', '&amp;')
         # in the template we have a placeholder to be replaced like this:
         data['recipient_user'] = user
         email = GroupMessagingEmailAlert(data)
         body_text = email.render_body()
         body_text = body_text.replace('THREAD_URL_HOLE', thread_url)
         send_mail(email.render_subject(), body_text, django_settings.DEFAULT_FROM_EMAIL, [user.email])
Exemple #30
0
 def send_email_alert(self):
     """signal handler for the message post-save"""
     root_message = self.get_root_message()
     data = {'messages': self.get_timeline()}
     template = get_template('group_messaging/email_alert.html')
     body_text = template.render(data)
     subject = self.get_email_subject_line()
     for user in self.get_recipients_users():
         #todo change url scheme so that all users have the same
         #urls within their personal areas of the user profile
         #so that we don't need to have loops like this one
         thread_url = root_message.get_absolute_url(user)
         thread_url = thread_url.replace('&', '&amp;')
         #in the template we have a placeholder to be replaced like this:
         body_text = body_text.replace('THREAD_URL_HOLE', thread_url)
         send_mail(
             subject,
             body_text,
             django_settings.DEFAULT_FROM_EMAIL,
             [user.email,],
         )
Exemple #31
0
 def send_email_alert(self):
     """signal handler for the message post-save"""
     root_message = self.get_root_message()
     data = {'messages': self.get_timeline()}
     template = get_template('group_messaging/email_alert.html')
     body_text = template.render(data)
     subject = self.get_email_subject_line()
     for user in self.get_recipients_users():
         #todo change url scheme so that all users have the same
         #urls within their personal areas of the user profile
         #so that we don't need to have loops like this one
         thread_url = root_message.get_absolute_url(user)
         thread_url = thread_url.replace('&', '&amp;')
         #in the template we have a placeholder to be replaced like this:
         body_text = body_text.replace('THREAD_URL_HOLE', thread_url)
         send_mail(
             subject,
             body_text,
             django_settings.DEFAULT_FROM_EMAIL,
             [user.email,],
         )
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER,
            askbot_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY,
            askbot_settings.MAX_ACCEPT_ANSWER_REMINDERS
        )

        questions = models.Post.objects.get_questions().exclude(
                                        deleted = True
                                    ).added_between(
                                        start = schedule.start_cutoff_date,
                                        end = schedule.end_cutoff_date
                                    ).filter(
                                        thread__answer_count__gt = 0
                                    ).filter(
                                        thread__accepted_answer__isnull=True #answer_accepted = False
                                    ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status = 'b'):
            user_questions = questions.filter(author = user)

            final_question_list = user_questions.get_questions_needing_reminder(
                activity_type = const.TYPE_ACTIVITY_ACCEPT_ANSWER_REMINDER_SENT,
                user = user,
                recurrence_delay = schedule.recurrence_delay
            )
            #todo: rewrite using query set filter
            #may be a lot more efficient

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            subject_line = _(
                'Accept the best answer for %(question_count)d of your questions'
            ) % {'question_count': question_count}

            #todo - make a template for these
            if question_count == 1:
                reminder_phrase = _('Please accept the best answer for this question:')
            else:
                reminder_phrase = _('Please accept the best answer for these questions:')
            body_text = '<p>' + reminder_phrase + '</p>'
            body_text += '<ul>'
            for question in final_question_list:
                body_text += '<li><a href="%s%s?sort=latest">%s</a></li>' \
                            % (
                                askbot_settings.APP_URL,
                                question.get_absolute_url(),
                                question.thread.title
                            )
            body_text += '</ul>'

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(
                    subject_line = subject_line,
                    body_text = body_text,
                    recipient_list = (user.email,)
                )
    def send_email_alerts(self):
        #does not change the database, only sends the email
        #todo: move this to template
        activate_language(django_settings.LANGUAGE_CODE)
        template = get_template('email/delayed_email_alert.html')
        for user in User.objects.all():
            user.add_missing_askbot_subscriptions()
            #todo: q_list is a dictionary, not a list
            q_list = self.get_updated_questions_for_user(user)
            if len(q_list.keys()) == 0:
                continue
            num_q = 0
            for question, meta_data in q_list.items():
                if meta_data['skip']:
                    del q_list[question]
                else:
                    num_q += 1
            if num_q > 0:
                threads = Thread.objects.filter(
                    id__in=[qq.thread_id for qq in q_list.keys()])
                tag_summary = Thread.objects.get_tag_summary_from_threads(
                    threads)

                question_count = len(q_list.keys())

                if tag_summary:
                    subject_line = ungettext(
                        '%(question_count)d update about %(topics)s',
                        '%(question_count)d updates about %(topics)s',
                        question_count) % {
                            'question_count': question_count,
                            'topics': tag_summary
                        }
                else:
                    subject_line = ungettext(
                        '%(question_count)d update',
                        '%(question_count)d updates', question_count) % {
                            'question_count': question_count,
                        }

                items_added = 0
                items_unreported = 0
                questions_data = list()
                for q, meta_data in q_list.items():
                    act_list = []
                    if meta_data['skip']:
                        continue
                    if items_added >= askbot_settings.MAX_ALERTS_PER_EMAIL:
                        items_unreported = num_q - items_added  #may be inaccurate actually, but it's ok
                        break
                    else:
                        items_added += 1
                        if meta_data['new_q']:
                            act_list.append(_('new question'))
                        format_action_count('%(num)d rev', meta_data['q_rev'],
                                            act_list)
                        format_action_count('%(num)d ans',
                                            meta_data['new_ans'], act_list)
                        format_action_count('%(num)d ans rev',
                                            meta_data['ans_rev'], act_list)
                        questions_data.append({
                            'url':
                            site_url(q.get_absolute_url()),
                            'info':
                            ', '.join(act_list),
                            'title':
                            q.thread.title
                        })

                activate_language(user.get_primary_language())
                text = template.render({
                    'recipient_user':
                    user,
                    'questions':
                    questions_data,
                    'name':
                    user.username,
                    'admin_email':
                    askbot_settings.ADMIN_EMAIL,
                    'site_name':
                    askbot_settings.APP_SHORT_NAME,
                    'is_multilingual':
                    getattr(django_settings, 'ASKBOT_MULTILINGUAL', False)
                })

                if DEBUG_THIS_COMMAND == True:
                    recipient_email = askbot_settings.ADMIN_EMAIL
                else:
                    recipient_email = user.email

                mail.send_mail(subject_line=subject_line,
                               body_text=text,
                               recipient_list=[recipient_email])
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_UNANSWERED_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date
        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_UNANSWERED_REMINDER,
            askbot_settings.UNANSWERED_REMINDER_FREQUENCY,
            max_reminders = askbot_settings.MAX_UNANSWERED_REMINDERS
        )

        questions = models.Post.objects.get_questions().exclude(
                                        thread__closed = True
                                    ).exclude(
                                        deleted = True
                                    ).added_between(
                                        start = schedule.start_cutoff_date,
                                        end = schedule.end_cutoff_date
                                    ).filter(
                                        thread__answer_count = 0
                                    ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status = 'b'):
            user_questions = questions.exclude(author = user)
            user_questions = user.get_tag_filtered_questions(user_questions)

            if askbot_settings.GROUPS_ENABLED:
                user_groups = user.get_groups()
                user_questions = user_questions.filter(groups__in = user_groups)

            final_question_list = user_questions.get_questions_needing_reminder(
                user = user,
                activity_type = const.TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT,
                recurrence_delay = schedule.recurrence_delay
            )

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            threads = Thread.objects.filter(id__in=[qq.thread_id for qq in final_question_list])
            tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

            subject_line = ungettext(
                '%(question_count)d unanswered question about %(topics)s',
                '%(question_count)d unanswered questions about %(topics)s',
                question_count
            ) % {
                'question_count': question_count,
                'topics': tag_summary
            }

            data = {
                    'site_url': site_url(''),
                    'questions': final_question_list,
                    'subject_line': subject_line
                   }

            template = get_template('email/unanswered_question_reminder.html')
            body_text = template.render(Context(data))#todo: set lang


            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(
                    subject_line = subject_line,
                    body_text = body_text,
                    recipient_list = (user.email,)
                )
Exemple #35
0
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_UNANSWERED_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date
        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_UNANSWERED_REMINDER,
            askbot_settings.UNANSWERED_REMINDER_FREQUENCY,
            max_reminders = askbot_settings.MAX_UNANSWERED_REMINDERS
        )

        questions = models.Post.objects.get_questions().exclude(
                                        thread__closed = True
                                    ).exclude(
                                        deleted = True
                                    ).added_between(
                                        start = schedule.start_cutoff_date,
                                        end = schedule.end_cutoff_date
                                    ).filter(
                                        thread__answer_count = 0
                                    ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status = 'b'):
            user_questions = questions.exclude(author = user)
            user_questions = user.get_tag_filtered_questions(user_questions)

            final_question_list = user_questions.get_questions_needing_reminder(
                user = user,
                activity_type = const.TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT,
                recurrence_delay = schedule.recurrence_delay
            )

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            threads = Thread.objects.filter(id__in=[qq.thread_id for qq in final_question_list])
            tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

            subject_line = ungettext(
                '%(question_count)d unanswered question about %(topics)s',
                '%(question_count)d unanswered questions about %(topics)s',
                question_count
            ) % {
                'question_count': question_count,
                'topics': tag_summary
            }

            body_text = '<ul>'
            for question in final_question_list:
                body_text += '<li><a href="%s%s?sort=latest">%s</a></li>' \
                            % (
                                askbot_settings.APP_URL,
                                question.get_absolute_url(),
                                question.thread.title
                            )
            body_text += '</ul>'

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(
                    subject_line = subject_line,
                    body_text = body_text,
                    recipient_list = (user.email,)
                )
    def send_email_alerts(self):
        #does not change the database, only sends the email
        #todo: move this to template
        for user in User.objects.all():
            user.add_missing_askbot_subscriptions()
            #todo: q_list is a dictionary, not a list
            q_list = self.get_updated_questions_for_user(user)
            if len(q_list.keys()) == 0:
                continue
            num_q = 0
            for question, meta_data in q_list.items():
                if meta_data['skip']:
                    del q_list[question]
                else:
                    num_q += 1
            if num_q > 0:
                threads = Thread.objects.filter(id__in=[qq.thread_id for qq in q_list.keys()])
                tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

                question_count = len(q_list.keys())

                subject_line = ungettext(
                    '%(question_count)d updated question about %(topics)s',
                    '%(question_count)d updated questions about %(topics)s',
                    question_count
                ) % {
                    'question_count': question_count,
                    'topics': tag_summary
                }

                #todo: send this to special log
                #print 'have %d updated questions for %s' % (num_q, user.username)
                text = ungettext(
                    '<p>Dear %(name)s,</p><p>The following question has been updated '
                    '%(sitename)s</p>',
                    '<p>Dear %(name)s,</p><p>The following %(num)d questions have been '
                    'updated on %(sitename)s:</p>',
                    num_q
                ) % {
                    'num':num_q,
                    'name':user.username,
                    'sitename': askbot_settings.APP_SHORT_NAME
                }

                text += '<ul>'
                items_added = 0
                items_unreported = 0
                for q, meta_data in q_list.items():
                    act_list = []
                    if meta_data['skip']:
                        continue
                    if items_added >= askbot_settings.MAX_ALERTS_PER_EMAIL:
                        items_unreported = num_q - items_added #may be inaccurate actually, but it's ok
                        
                    else:
                        items_added += 1
                        if meta_data['new_q']:
                            act_list.append(_('new question'))
                        format_action_count('%(num)d rev', meta_data['q_rev'],act_list)
                        format_action_count('%(num)d ans', meta_data['new_ans'],act_list)
                        format_action_count('%(num)d ans rev',meta_data['ans_rev'],act_list)
                        act_token = ', '.join(act_list)
                        text += '<li><a href="%s?sort=latest">%s</a> <font color="#777777">(%s)</font></li>' \
                                    % (site_url(q.get_absolute_url()), q.thread.title, act_token)
                text += '</ul>'
                text += '<p></p>'
                #if len(q_list.keys()) >= askbot_settings.MAX_ALERTS_PER_EMAIL:
                #    text += _('There may be more questions updated since '
                #                'you have logged in last time as this list is '
                #                'abridged for your convinience. Please visit '
                #                'the askbot and see what\'s new!<br>'
                #              )

                link = reverse(
                    'user_subscriptions', 
                    kwargs = {
                        'id': user.id,
                        'slug': slugify(user.username)
                    }
                )

                text += _(
                    '<p>Please remember that you can always <a '
                    'href="%(email_settings_link)s">adjust</a> frequency of the email updates or '
                    'turn them off entirely.<br/>If you believe that this message was sent in an '
                    'error, please email about it the forum administrator at %(admin_email)s.</'
                    'p><p>Sincerely,</p><p>Your friendly %(sitename)s server.</p>'
                ) % {
                    'email_settings_link': site_url(link),
                    'admin_email': django_settings.ADMINS[0][1],
                    'sitename': askbot_settings.APP_SHORT_NAME
                }
                if DEBUG_THIS_COMMAND == True:
                    recipient_email = django_settings.ADMINS[0][1]
                else:
                    recipient_email = user.email

                mail.send_mail(
                    subject_line = subject_line,
                    body_text = text,
                    recipient_list = [recipient_email]
                )
Exemple #37
0
def moderate_post_edits(request):
    if request.user.is_anonymous():
        raise exceptions.PermissionDenied()
    if not request.user.is_administrator_or_moderator():
        raise exceptions.PermissionDenied()

    post_data = simplejson.loads(request.raw_post_data)
    #{'action': 'decline-with-reason', 'items': ['posts'], 'reason': 1, 'edit_ids': [827]}

    memo_set = models.ActivityAuditStatus.objects.filter(
        id__in=post_data['edit_ids'])
    result = {'message': '', 'memo_ids': set()}

    #if we are approving or declining users we need to expand the memo_set
    #to all of their edits of those users
    if post_data['action'] in ('block',
                               'approve') and 'users' in post_data['items']:
        editors = exclude_admins(get_editors(memo_set))
        items = models.Activity.objects.filter(
            activity_type__in=const.MODERATED_EDIT_ACTIVITY_TYPES,
            user__in=editors)
        memo_filter = Q(user=request.user, activity__in=items)
        memo_set = models.ActivityAuditStatus.objects.filter(memo_filter)

    memo_set.select_related('activity')

    if post_data['action'] == 'approve':
        num_posts = 0
        if 'posts' in post_data['items']:
            for memo in memo_set:
                if memo.activity.activity_type == const.TYPE_ACTIVITY_MARK_OFFENSIVE:
                    #unflag the post
                    content_object = memo.activity.content_object
                    request.user.flag_post(content_object,
                                           cancel_all=True,
                                           force=True)
                    num_posts += 1
                else:
                    revision = memo.activity.content_object
                    if isinstance(revision, models.PostRevision):
                        request.user.approve_post_revision(revision)
                        num_posts += 1

            if num_posts > 0:
                posts_message = ungettext('%d post approved',
                                          '%d posts approved',
                                          num_posts) % num_posts
                result['message'] = concat_messages(result['message'],
                                                    posts_message)

        if 'users' in post_data['items']:
            editors = exclude_admins(get_editors(memo_set))
            assert (request.user not in editors)
            for editor in editors:
                editor.set_status('a')

            num_users = len(editors)
            if num_users:
                users_message = ungettext('%d user approved',
                                          '%d users approved',
                                          num_users) % num_users
                result['message'] = concat_messages(result['message'],
                                                    users_message)

    elif post_data['action'] == 'decline-with-reason':
        #todo: bunch notifications - one per recipient
        num_posts = 0
        for memo in memo_set:
            post = get_object(memo)
            request.user.delete_post(post)
            reject_reason = models.PostFlagReason.objects.get(
                id=post_data['reason'])
            template = get_template('email/rejected_post.html')
            data = {
                'post': post.html,
                'reject_reason': reject_reason.details.html
            }
            body_text = template.render(RequestContext(request, data))
            mail.send_mail(subject_line=_('your post was not accepted'),
                           body_text=unicode(body_text),
                           recipient_list=[
                               post.author.email,
                           ])
            num_posts += 1

        #message to moderator
        if num_posts:
            posts_message = ungettext('%d post deleted', '%d posts deleted',
                                      num_posts) % num_posts
            result['message'] = concat_messages(result['message'],
                                                posts_message)

    elif post_data['action'] == 'block':

        num_users = 0
        num_posts = 0
        num_ips = 0

        moderate_ips = getattr(django_settings, 'ASKBOT_IP_MODERATION_ENABLED',
                               False)
        # If we block by IPs we always block users and posts
        # so we use a "spider" algorithm to find posts, users and IPs to block.
        # once we find users, posts and IPs, we block all of them summarily.
        if moderate_ips and 'ips' in post_data['items']:
            assert ('users' in post_data['items'])
            assert ('posts' in post_data['items'])
            assert (len(post_data['items']) == 3)

            revs = get_revision_set(memo_set)
            revs = expand_revision_set(revs)
            ips, users = get_revision_ips_and_authors(revs)
            memo_set = get_memos_by_revisions(revs, request.user)

            #to make sure to not block the admin and
            #in case REMOTE_ADDR is a proxy server - not
            #block access to the site
            my_ip = request.META.get('REMOTE_ADDR')
            if my_ip in ips:
                ips.remove(my_ip)

            #block IPs
            from stopforumspam.models import Cache
            already_blocked = Cache.objects.filter(ip__in=ips)
            already_blocked.update(permanent=True)
            already_blocked_ips = already_blocked.values_list('ip', flat=True)
            ips = ips - set(already_blocked_ips)
            for ip in ips:
                cache = Cache(ip=ip, permanent=True)
                cache.save()

            #block users and all their content
            users = exclude_admins(users)
            for user in users:
                user.set_status('b')
                #delete all content by the user
                num_posts += request.user.delete_all_content_authored_by_user(
                    user)

            num_ips = len(ips)
            num_users = len(users)

        elif 'users' in post_data['items']:
            editors = exclude_admins(get_editors(memo_set))
            assert (request.user not in editors)
            for editor in editors:
                #block user
                editor.set_status('b')
                #delete all content by the user
                num_posts += request.user.delete_all_content_authored_by_user(
                    editor)
            num_users = len(editors)

        if num_ips:
            ips_message = ungettext('%d ip blocked', '%d ips blocked',
                                    num_ips) % num_ips
            result['message'] = concat_messages(result['message'], ips_message)

        if num_users:
            users_message = ungettext('%d user blocked', '%d users blocked',
                                      num_users) % num_users
            result['message'] = concat_messages(result['message'],
                                                users_message)

        if num_posts:
            posts_message = ungettext('%d post deleted', '%d posts deleted',
                                      num_posts) % num_posts
            result['message'] = concat_messages(result['message'],
                                                posts_message)

    result['memo_ids'] = [memo.id
                          for memo in memo_set]  #why values_list() fails here?
    result['message'] = force_text(result['message'])

    #delete items from the moderation queue
    act_ids = list(memo_set.values_list('activity_id', flat=True))
    acts = models.Activity.objects.filter(id__in=act_ids)

    memos = models.ActivityAuditStatus.objects.filter(activity__id__in=act_ids)
    memos.delete()

    acts.delete()

    request.user.update_response_counts()
    result['memo_count'] = request.user.get_notifications(
        const.MODERATED_ACTIVITY_TYPES).count()
    return result
Exemple #38
0
def user_moderate(request, subject, context):
    """user subview for moderation
    """
    moderator = request.user

    if moderator.is_authenticated() and not moderator.can_moderate_user(subject):
        raise Http404

    user_rep_changed = False
    user_status_changed = False
    message_sent = False
    email_error_message = None

    user_rep_form = forms.ChangeUserReputationForm()
    send_message_form = forms.SendMessageForm()
    if request.method == "POST":
        if "change_status" in request.POST:
            user_status_form = forms.ChangeUserStatusForm(request.POST, moderator=moderator, subject=subject)
            if user_status_form.is_valid():
                subject.set_status(user_status_form.cleaned_data["user_status"])
            user_status_changed = True
        elif "send_message" in request.POST:
            send_message_form = forms.SendMessageForm(request.POST)
            if send_message_form.is_valid():
                subject_line = send_message_form.cleaned_data["subject_line"]
                body_text = send_message_form.cleaned_data["body_text"]

                try:
                    send_mail(
                        subject_line=subject_line,
                        body_text=body_text,
                        recipient_list=[subject.email],
                        headers={"Reply-to": moderator.email},
                        raise_on_failure=True,
                    )
                    message_sent = True
                except exceptions.EmailNotSent, e:
                    email_error_message = unicode(e)
                send_message_form = forms.SendMessageForm()
        else:
            reputation_change_type = None
            if "subtract_reputation" in request.POST:
                rep_change_type = "subtract"
            elif "add_reputation" in request.POST:
                rep_change_type = "add"
            else:
                raise Http404

            user_rep_form = forms.ChangeUserReputationForm(request.POST)
            if user_rep_form.is_valid():
                rep_delta = user_rep_form.cleaned_data["user_reputation_delta"]
                comment = user_rep_form.cleaned_data["comment"]

                if rep_change_type == "subtract":
                    rep_delta = -1 * rep_delta

                moderator.moderate_user_reputation(
                    user=subject, reputation_change=rep_delta, comment=comment, timestamp=datetime.datetime.now()
                )
                # reset form to preclude accidentally repeating submission
                user_rep_form = forms.ChangeUserReputationForm()
                user_rep_changed = True
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER,
            askbot_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY,
            askbot_settings.MAX_ACCEPT_ANSWER_REMINDERS
        )

        questions = models.Post.objects.get_questions().exclude(
                                        deleted = True
                                    ).added_between(
                                        start = schedule.start_cutoff_date,
                                        end = schedule.end_cutoff_date
                                    ).filter(
                                        thread__answer_count__gt = 0
                                    ).filter(
                                        thread__accepted_answer__isnull=True #answer_accepted = False
                                    ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status = 'b'):
            user_questions = questions.filter(author = user)

            final_question_list = user_questions.get_questions_needing_reminder(
                activity_type = const.TYPE_ACTIVITY_ACCEPT_ANSWER_REMINDER_SENT,
                user = user,
                recurrence_delay = schedule.recurrence_delay
            )
            #todo: rewrite using query set filter
            #may be a lot more efficient

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            reminder_phrase = _('Please select the best responses to:')

            data = {
                    'site_url': site_url(''),#here we need only the domain name
                    'questions': final_question_list,
                    'reminder_phrase': reminder_phrase
                   }

            template = get_template('email/accept_answer_reminder.html')
            body_text = template.render(Context(data))#todo: set lang

            subject_line = askbot_settings.WORDS_ACCEPT_BEST_ANSWERS_FOR_YOUR_QUESTIONS
            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(
                    subject_line = subject_line,
                    body_text = body_text,
                    recipient_list = (user.email,)
                )
    def send_email_alerts(self, user, template):
        #does not change the database, only sends the email
        #todo: move this to template
        user.add_missing_askbot_subscriptions()
        #todo: q_list is a dictionary, not a list
        q_list = self.get_updated_questions_for_user(user)
        if len(q_list.keys()) == 0:
            return
        num_q = 0
        for question, meta_data in q_list.items():
            if meta_data['skip']:
                del q_list[question]
            else:
                num_q += 1
        if num_q > 0:
            threads = Thread.objects.filter(id__in=[qq.thread_id for qq in q_list.keys()])
            tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

            question_count = len(q_list.keys())

            if tag_summary:
                subject_line = ungettext(
                    '%(question_count)d update about %(topics)s',
                    '%(question_count)d updates about %(topics)s',
                    question_count
                ) % {
                    'question_count': question_count,
                    'topics': tag_summary
                }
            else:
                subject_line = ungettext(
                    '%(question_count)d update',
                    '%(question_count)d updates',
                    question_count
                ) % {
                    'question_count': question_count,
                }

            items_added = 0
            items_unreported = 0
            questions_data = list()
            for q, meta_data in q_list.items():
                act_list = []
                if meta_data['skip']:
                    continue
                if items_added >= askbot_settings.MAX_ALERTS_PER_EMAIL:
                    items_unreported = num_q - items_added #may be inaccurate actually, but it's ok
                    break
                else:
                    items_added += 1
                    if meta_data['new_q']:
                        act_list.append(_('new question'))
                    format_action_count('%(num)d rev', meta_data['q_rev'], act_list)
                    format_action_count('%(num)d ans', meta_data['new_ans'], act_list)
                    format_action_count('%(num)d ans rev', meta_data['ans_rev'], act_list)
                    questions_data.append({
                        'url': site_url(q.get_absolute_url()),
                        'info': ', '.join(act_list),
                        'title': q.thread.title
                    })

            activate_language(user.get_primary_language())
            text = template.render({
                'recipient_user': user,
                'questions': questions_data,
                'name': user.username,
                'admin_email': askbot_settings.ADMIN_EMAIL,
                'site_name': askbot_settings.APP_SHORT_NAME,
                'is_multilingual': getattr(django_settings, 'ASKBOT_MULTILINGUAL', False)
            })

            if DEBUG_THIS_COMMAND == True:
                recipient_email = askbot_settings.ADMIN_EMAIL
            else:
                recipient_email = user.email

            mail.send_mail(
                subject_line = subject_line,
                body_text = text,
                recipient_list = [recipient_email]
            )
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_ACCEPT_PROBLEM_REMINDERS == False:
            return
        #get exercises without problems, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_ACCEPT_PROBLEM_REMINDER,
            askbot_settings.ACCEPT_PROBLEM_REMINDER_FREQUENCY,
            askbot_settings.MAX_ACCEPT_PROBLEM_REMINDERS
        )

        exercises = models.Post.objects.get_exercises().exclude(
                                        deleted = True
                                    ).added_between(
                                        start = schedule.start_cutoff_date,
                                        end = schedule.end_cutoff_date
                                    ).filter(
                                        thread__problem_count__gt = 0
                                    ).filter(
                                        thread__accepted_problem__isnull=True #problem_accepted = False
                                    ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status = 'b'):
            user_exercises = exercises.filter(author = user)

            final_exercise_list = user_exercises.get_exercises_needing_reminder(
                activity_type = const.TYPE_ACTIVITY_ACCEPT_PROBLEM_REMINDER_SENT,
                user = user,
                recurrence_delay = schedule.recurrence_delay
            )
            #todo: rewrite using query set filter
            #may be a lot more efficient

            exercise_count = len(final_exercise_list)
            if exercise_count == 0:
                continue

            subject_line = _(
                'Accept the best problem for %(exercise_count)d of your exercises'
            ) % {'exercise_count': exercise_count}

            #todo - make a template for these
            if exercise_count == 1:
                reminder_phrase = _('Please accept the best problem for this exercise:')
            else:
                reminder_phrase = _('Please accept the best problem for these exercises:')

            data = {
                    'site_url': askbot_settings.APP_URL,
                    'exercises': final_exercise_list,
                    'reminder_phrase': reminder_phrase
                   }

            template = get_template('email/accept_problem_reminder.html')
            body_text = template.render(Context(data))

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(
                    subject_line = subject_line,
                    body_text = body_text,
                    recipient_list = (user.email,)
                )
def moderate_post_edits(request):
    if request.user.is_anonymous():
        raise exceptions.PermissionDenied()
    if not request.user.is_administrator_or_moderator():
        raise exceptions.PermissionDenied()

    post_data = simplejson.loads(request.raw_post_data)
    #{'action': 'decline-with-reason', 'items': ['posts'], 'reason': 1, 'edit_ids': [827]}

    memo_set = models.ActivityAuditStatus.objects.filter(id__in=post_data['edit_ids'])
    result = {
        'message': '',
        'memo_ids': set()
    }

    #if we are approving or declining users we need to expand the memo_set
    #to all of their edits of those users
    if post_data['action'] in ('block', 'approve') and 'users' in post_data['items']:
        editors = filter_admins(get_editors(memo_set))
        items = models.Activity.objects.filter(
                                activity_type__in=const.MODERATED_EDIT_ACTIVITY_TYPES,
                                user__in=editors
                            )
        memo_filter = Q(id__in=post_data['edit_ids']) | Q(user=request.user, activity__in=items)
        memo_set = models.ActivityAuditStatus.objects.filter(memo_filter)

    memo_set.select_related('activity')

    if post_data['action'] == 'decline-with-reason':
        #todo: bunch notifications - one per recipient
        num_posts = 0
        for memo in memo_set:
            post = get_object(memo)
            request.user.delete_post(post)
            reject_reason = models.PostFlagReason.objects.get(id=post_data['reason'])
            template = get_template('email/rejected_post.html')
            data = {
                    'post': post.html,
                    'reject_reason': reject_reason.details.html
                   }
            body_text = template.render(RequestContext(request, data))
            mail.send_mail(
                subject_line = _('your post was not accepted'),
                body_text = unicode(body_text),
                recipient_list = [post.author.email,]
            )
            num_posts += 1

        #message to moderator
        if num_posts:
            posts_message = ungettext('%d post deleted', '%d posts deleted', num_posts) % num_posts
            result['message'] = concat_messages(result['message'], posts_message)

    elif post_data['action'] == 'approve':
        num_posts = 0
        if 'posts' in post_data['items']:
            for memo in memo_set:
                if memo.activity.activity_type == const.TYPE_ACTIVITY_MARK_OFFENSIVE:
                    #unflag the post
                    content_object = memo.activity.content_object
                    request.user.flag_post(content_object, cancel_all=True, force=True)
                    num_posts += 1
                else:
                    revision = memo.activity.content_object
                    if isinstance(revision, models.PostRevision):
                        request.user.approve_post_revision(revision)
                        num_posts += 1

            if num_posts > 0:
                posts_message = ungettext('%d post approved', '%d posts approved', num_posts) % num_posts
                result['message'] = concat_messages(result['message'], posts_message)

        if 'users' in post_data['items']:
            editors = filter_admins(get_editors(memo_set))
            assert(request.user not in editors)
            for editor in editors:
                editor.set_status('a')

            num_editors = len(editors)
            if num_editors:
                users_message = ungettext('%d user approved', '%d users approved', num_editors) % num_editors
                result['message'] = concat_messages(result['message'], users_message)
            
    elif post_data['action'] == 'block':
        if 'users' in post_data['items']:
            editors = filter_admins(get_editors(memo_set))
            assert(request.user not in editors)
            num_posts = 0
            for editor in editors:
                #block user
                editor.set_status('b')
                #delete all content by the user
                num_posts += request.user.delete_all_content_authored_by_user(editor)

            if num_posts:
                posts_message = ungettext('%d post deleted', '%d posts deleted', num_posts) % num_posts
                result['message'] = concat_messages(result['message'], posts_message)

            num_editors = len(editors)
            if num_editors:
                users_message = ungettext('%d user blocked', '%d users blocked', num_editors) % num_editors
                result['message'] = concat_messages(result['message'], users_message)

        moderate_ips = getattr(django_settings, 'ASKBOT_IP_MODERATION_ENABLED', False)
        if moderate_ips and 'ips' in post_data['items']:
            ips = set()
            for memo in memo_set:
                obj = memo.activity.content_object
                if isinstance(obj, models.PostRevision):
                    ips.add(obj.ip_addr)

            #to make sure to not block the admin and 
            #in case REMOTE_ADDR is a proxy server - not
            #block access to the site
            my_ip = request.META.get('REMOTE_ADDR')
            if my_ip in ips:
                ips.remove(my_ip)

            from stopforumspam.models import Cache
            already_blocked = Cache.objects.filter(ip__in=ips)
            already_blocked.update(permanent=True)
            already_blocked_ips = already_blocked.values_list('ip', flat=True)
            ips = ips - set(already_blocked_ips)
            for ip in ips:
                cache = Cache(ip=ip, permanent=True)
                cache.save()

            num_ips = len(ips)
            if num_ips:
                ips_message = ungettext('%d ip blocked', '%d ips blocked', num_ips) % num_ips
                result['message'] = concat_messages(result['message'], ips_message)

    result['memo_ids'] = [memo.id for memo in memo_set]#why values_list() fails here?
    result['message'] = force_text(result['message'])

    #delete items from the moderation queue
    act_ids = list(memo_set.values_list('activity_id', flat=True))
    acts = models.Activity.objects.filter(id__in=act_ids)

    memos = models.ActivityAuditStatus.objects.filter(activity__id__in=act_ids)
    memos.delete()

    acts.delete()

    request.user.update_response_counts()
    result['memo_count'] = request.user.get_notifications(const.MODERATED_ACTIVITY_TYPES).count()
    return result
Exemple #43
0
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_UNANSWERED_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date
        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_UNANSWERED_REMINDER,
            askbot_settings.UNANSWERED_REMINDER_FREQUENCY,
            max_reminders=askbot_settings.MAX_UNANSWERED_REMINDERS)

        questions = models.Post.objects.get_questions()

        #we don't report closed, deleted or moderation queue questions
        exclude_filter = Q(thread__closed=True) | Q(deleted=True)
        if askbot_settings.CONTENT_MODERATION_MODE == 'premoderation':
            exclude_filter |= Q(approved=False)
        questions = questions.exclude(exclude_filter)

        #select questions within the range of the reminder schedule
        questions = questions.added_between(start=schedule.start_cutoff_date,
                                            end=schedule.end_cutoff_date)

        #take only questions with zero answers
        questions = questions.filter(thread__answer_count=0)

        if questions.count() == 0:
            #nothing to do
            return

        questions = questions.order_by('-added_at')

        if askbot_settings.UNANSWERED_REMINDER_RECIPIENTS == 'admins':
            recipient_statuses = ('d', 'm')
        else:
            recipient_statuses = ('a', 'w', 'd', 'm')

        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.filter(status__in=recipient_statuses):
            user_questions = questions.exclude(author=user)
            user_questions = user.get_tag_filtered_questions(user_questions)

            if askbot_settings.GROUPS_ENABLED:
                user_groups = user.get_groups()
                user_questions = user_questions.filter(groups__in=user_groups)

            final_question_list = user_questions.get_questions_needing_reminder(
                user=user,
                activity_type=const.TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT,
                recurrence_delay=schedule.recurrence_delay)

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            threads = Thread.objects.filter(
                id__in=[qq.thread_id for qq in final_question_list])
            tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

            if question_count == 1:
                unanswered_questions_phrase = askbot_settings.WORDS_UNANSWERED_QUESTION_SINGULAR
            else:
                unanswered_questions_phrase = askbot_settings.WORDS_UNANSWERED_QUESTION_PLURAL

            subject_line = ungettext(
                '%(question_count)d %(unanswered_questions)s about %(topics)s',
                '%(question_count)d %(unanswered_questions)s about %(topics)s',
                question_count) % {
                    'question_count': question_count,
                    'unanswered_questions': unanswered_questions_phrase,
                    'topics': tag_summary
                }

            data = {
                'site_url': site_url(''),
                'questions': final_question_list,
                'subject_line': subject_line
            }

            template = get_template('email/unanswered_question_reminder.html')
            body_text = template.render(Context(data))  #todo: set lang

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(subject_line=subject_line,
                               body_text=body_text,
                               recipient_list=(user.email, ))
Exemple #44
0
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_UNANSWERED_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date
        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_UNANSWERED_REMINDER,
            askbot_settings.UNANSWERED_REMINDER_FREQUENCY,
            max_reminders=askbot_settings.MAX_UNANSWERED_REMINDERS)

        questions = models.Post.objects.get_questions().exclude(
            thread__closed=True).exclude(deleted=True).added_between(
                start=schedule.start_cutoff_date,
                end=schedule.end_cutoff_date).filter(
                    thread__answer_count=0).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status='b'):
            user_questions = questions.exclude(author=user)
            user_questions = user.get_tag_filtered_questions(user_questions)

            if askbot_settings.GROUPS_ENABLED:
                user_groups = user.get_groups()
                user_questions = user_questions.filter(groups__in=user_groups)

            final_question_list = user_questions.get_questions_needing_reminder(
                user=user,
                activity_type=const.TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT,
                recurrence_delay=schedule.recurrence_delay)

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            threads = Thread.objects.filter(
                id__in=[qq.thread_id for qq in final_question_list])
            tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

            subject_line = ungettext(
                '%(question_count)d unanswered question about %(topics)s',
                '%(question_count)d unanswered questions about %(topics)s',
                question_count) % {
                    'question_count': question_count,
                    'topics': tag_summary
                }

            data = {
                'site_url': site_url(''),
                'questions': final_question_list,
                'subject_line': subject_line
            }

            template = get_template('email/unanswered_question_reminder.html')
            body_text = template.render(Context(data))  #todo: set lang

            if TRACK_USER_EMAIL:
                print "%s:%s" % (user.email, subject_line)

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(subject_line=subject_line,
                               body_text=body_text,
                               recipient_list=(user.email, ))
Exemple #45
0
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_ACCEPT_PROBLEM_REMINDERS == False:
            return
        #get exercises without problems, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_ACCEPT_PROBLEM_REMINDER,
            askbot_settings.ACCEPT_PROBLEM_REMINDER_FREQUENCY,
            askbot_settings.MAX_ACCEPT_PROBLEM_REMINDERS)

        exercises = models.Post.objects.get_exercises(
        ).exclude(deleted=True).added_between(
            start=schedule.start_cutoff_date, end=schedule.end_cutoff_date
        ).filter(thread__problem_count__gt=0).filter(
            thread__accepted_problem__isnull=True  #problem_accepted = False
        ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status='b'):
            user_exercises = exercises.filter(author=user)

            final_exercise_list = user_exercises.get_exercises_needing_reminder(
                activity_type=const.TYPE_ACTIVITY_ACCEPT_PROBLEM_REMINDER_SENT,
                user=user,
                recurrence_delay=schedule.recurrence_delay)
            #todo: rewrite using query set filter
            #may be a lot more efficient

            exercise_count = len(final_exercise_list)
            if exercise_count == 0:
                continue

            subject_line = _(
                'Accept the best problem for %(exercise_count)d of your exercises'
            ) % {
                'exercise_count': exercise_count
            }

            #todo - make a template for these
            if exercise_count == 1:
                reminder_phrase = _(
                    'Please accept the best problem for this exercise:')
            else:
                reminder_phrase = _(
                    'Please accept the best problem for these exercises:')

            data = {
                'site_url': askbot_settings.APP_URL,
                'exercises': final_exercise_list,
                'reminder_phrase': reminder_phrase
            }

            template = get_template('email/accept_problem_reminder.html')
            body_text = template.render(Context(data))

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(subject_line=subject_line,
                               body_text=body_text,
                               recipient_list=(user.email, ))
Exemple #46
0
def user_moderate(request, subject, context):
    """user subview for moderation
    """
    moderator = request.user

    if moderator.is_authenticated(
    ) and not moderator.can_moderate_user(subject):
        raise Http404

    user_rep_changed = False
    user_status_changed = False
    user_status_changed_message = _('User status changed')
    message_sent = False
    email_error_message = None

    user_rep_form = forms.ChangeUserReputationForm()
    send_message_form = forms.SendMessageForm()
    if request.method == 'POST':
        if 'change_status' in request.POST or 'hard_block' in request.POST:
            user_status_form = forms.ChangeUserStatusForm(request.POST,
                                                          moderator=moderator,
                                                          subject=subject)
            if user_status_form.is_valid():
                subject.set_status(
                    user_status_form.cleaned_data['user_status'])
                if user_status_form.cleaned_data['delete_content'] is True:
                    num_deleted = request.user.delete_all_content_authored_by_user(
                        subject)
                    if num_deleted:
                        num_deleted_message = ungettext(
                            '%d post deleted', '%d posts deleted',
                            num_deleted) % num_deleted
                        user_status_changed_message = string_concat(
                            user_status_changed_message, ', ',
                            num_deleted_message)
            user_status_changed = True
        elif 'send_message' in request.POST:
            send_message_form = forms.SendMessageForm(request.POST)
            if send_message_form.is_valid():
                subject_line = send_message_form.cleaned_data['subject_line']
                body_text = send_message_form.cleaned_data['body_text']

                try:
                    send_mail(subject_line=subject_line,
                              body_text=body_text,
                              recipient_list=[subject.email],
                              headers={'Reply-to': moderator.email},
                              raise_on_failure=True)
                    message_sent = True
                except exceptions.EmailNotSent as e:
                    email_error_message = force_text(e)
                send_message_form = forms.SendMessageForm()
        else:
            reputation_change_type = None
            if 'subtract_reputation' in request.POST:
                rep_change_type = 'subtract'
            elif 'add_reputation' in request.POST:
                rep_change_type = 'add'
            else:
                raise Http404

            user_rep_form = forms.ChangeUserReputationForm(request.POST)
            if user_rep_form.is_valid():
                rep_delta = user_rep_form.cleaned_data['user_reputation_delta']
                comment = user_rep_form.cleaned_data['comment']

                if rep_change_type == 'subtract':
                    rep_delta = -1 * rep_delta

                moderator.moderate_user_reputation(user=subject,
                                                   reputation_change=rep_delta,
                                                   comment=comment,
                                                   timestamp=timezone.now())

                # reset form to preclude accidentally repeating submission
                user_rep_form = forms.ChangeUserReputationForm()
                user_rep_changed = True

    # need to re-initialize the form even if it was posted, because
    # initial values will most likely be different from the previous
    user_status_form = forms.ChangeUserStatusForm(moderator=moderator,
                                                  subject=subject)

    context.update({
        'active_tab': 'users',
        'page_class': 'user-profile-page',
        'tab_name': 'moderation',
        'page_title': _('moderate user'),
        'change_user_status_form': user_status_form,
        'change_user_reputation_form': user_rep_form,
        'send_message_form': send_message_form,
        'message_sent': message_sent,
        'email_error_message': email_error_message,
        'user_rep_changed': user_rep_changed,
        'user_status_changed': user_status_changed,
        'user_status_changed_message': user_status_changed_message
    })
    return render(request, 'user_profile/user_moderate.jinja', context)
    def send_email_alerts(self):
        #does not change the database, only sends the email
        #todo: move this to template
        activate_language(django_settings.LANGUAGE_CODE)
        template = get_template('email/delayed_email_alert.html')
        for user in User.objects.all():
            user.add_missing_askbot_subscriptions()
            #todo: q_list is a dictionary, not a list
            q_list = self.get_updated_questions_for_user(user)
            if len(q_list.keys()) == 0:
                continue
            num_q = 0
            for question, meta_data in q_list.items():
                if meta_data['skip']:
                    del q_list[question]
                else:
                    num_q += 1
            if num_q > 0:
                threads = Thread.objects.filter(id__in=[qq.thread_id for qq in q_list.keys()])
                tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

                question_count = len(q_list.keys())

                subject_line = ungettext(
                    '%(question_count)d updated question about %(topics)s',
                    '%(question_count)d updated questions about %(topics)s',
                    question_count
                ) % {
                    'question_count': question_count,
                    'topics': tag_summary
                }

                #todo: send this to special log
                print 'have %d updated questions for %s' % (num_q, user.username)
                if DEBUG_THIS_COMMAND == True:
                   continue
                text = ungettext(
                    '<p>Dear %(name)s,</p><p>The following question has been updated '
                    '%(sitename)s</p>',
                    '<p>Dear %(name)s,</p><p>The following %(num)d questions have been '
                    'updated on %(sitename)s:</p>',
                    num_q
                ) % {
                    'num':num_q,
                    'name':user.username,
                    'sitename': askbot_settings.APP_SHORT_NAME
                }

                text += '<ul>'
                items_added = 0
                items_unreported = 0
                questions_data = list()
                for q, meta_data in q_list.items():
                    act_list = []
                    if meta_data['skip']:
                        continue
                    if items_added >= askbot_settings.MAX_ALERTS_PER_EMAIL:
                        items_unreported = num_q - items_added #may be inaccurate actually, but it's ok
                        break
                    else:
                        items_added += 1
                        if meta_data['new_q']:
                            act_list.append(_('new question'))
                        format_action_count('%(num)d rev', meta_data['q_rev'], act_list)
                        format_action_count('%(num)d ans', meta_data['new_ans'], act_list)
                        format_action_count('%(num)d ans rev', meta_data['ans_rev'], act_list)
                        questions_data.append({
                            'url': site_url(q.get_absolute_url()),
                            'info': ', '.join(act_list),
                            'title': q.thread.title
                        })

                activate_language(user.get_primary_language())
                text = template.render({
                    'recipient_user': user,
                    'questions': questions_data,
                    'name': user.username,
                    'admin_email': askbot_settings.ADMIN_EMAIL,
                    'site_name': askbot_settings.APP_SHORT_NAME,
                    'is_multilingual': django_settings.ASKBOT_MULTILINGUAL
                })

                if DEBUG_THIS_COMMAND == True:
                    recipient_email = askbot_settings.ADMIN_EMAIL
                else:
                    recipient_email = user.email

                mail.send_mail(
                    subject_line = subject_line,
                    body_text = text,
                    recipient_list = [recipient_email]
                )
Exemple #48
0
def send_instant_notifications_about_activity_in_post(
    activity_id=None,
    post_id=None,
    recipients=None,
):

    if recipients is None:
        return

    acceptable_types = const.RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS

    try:
        update_activity = Activity.objects.filter(
            activity_type__in=acceptable_types).get(id=activity_id)
    except Activity.DoesNotExist:
        logger.error("Unable to fetch activity with id %s" % post_id)
        return

    try:
        post = Post.objects.get(id=post_id)
    except Post.DoesNotExist:
        logger.error("Unable to fetch post with id %s" % post_id)
        return

    if post.is_approved() is False:
        return

    #calculate some variables used in the loop below
    update_type_map = const.RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES
    update_type = update_type_map[update_activity.activity_type]
    origin_post = post.get_origin_post()
    headers = mail.thread_headers(post, origin_post,
                                  update_activity.activity_type)

    if logger.getEffectiveLevel() <= logging.DEBUG:
        log_id = uuid.uuid1()
        message = 'email-alert %s, logId=%s' % (post.get_absolute_url(),
                                                log_id)
        logger.debug(message)
    else:
        log_id = None

    for user in recipients:
        if user.is_blocked():
            continue

        reply_address, alt_reply_address = get_reply_to_addresses(user, post)

        activate_language(post.language_code)
        subject_line, body_text = format_instant_notification_email(
            to_user=user,
            from_user=update_activity.user,
            post=post,
            reply_address=reply_address,
            alt_reply_address=alt_reply_address,
            update_type=update_type,
            template=get_template('email/instant_notification.html'))

        headers['Reply-To'] = reply_address
        try:
            mail.send_mail(subject_line=subject_line,
                           body_text=body_text,
                           recipient_list=[user.email],
                           related_object=origin_post,
                           activity_type=const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
                           headers=headers,
                           raise_on_failure=True)
        except askbot_exceptions.EmailNotSent, error:
            logger.debug('%s, error=%s, logId=%s' %
                         (user.email, error, log_id))
        else:
            logger.debug('success %s, logId=%s' % (user.email, log_id))
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_UNANSWERED_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date
        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_UNANSWERED_REMINDER,
            askbot_settings.UNANSWERED_REMINDER_FREQUENCY,
            max_reminders = askbot_settings.MAX_UNANSWERED_REMINDERS
        )

        questions = models.Post.objects.get_questions()

        #we don't report closed, deleted or moderation queue questions
        exclude_filter = Q(thread__closed=True) | Q(deleted=True)
        if askbot_settings.CONTENT_MODERATION_MODE == 'premoderation':
            exclude_filter |= Q(approved=False)
        questions = questions.exclude(exclude_filter)

        #select questions within the range of the reminder schedule
        questions = questions.added_between(
                        start=schedule.start_cutoff_date,
                        end=schedule.end_cutoff_date
                    )

        #take only questions with zero answers
        questions = questions.filter(thread__answer_count=0)

        if questions.count() == 0:
            #nothing to do
            return

        questions = questions.order_by('-added_at')

        if askbot_settings.UNANSWERED_REMINDER_RECIPIENTS == 'admins':
            recipient_statuses = ('d', 'm')
        else:
            recipient_statuses = ('a', 'w', 'd', 'm')

        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.filter(status__in=recipient_statuses):
            user_questions = questions.exclude(author=user)
            user_questions = user.get_tag_filtered_questions(user_questions)

            if askbot_settings.GROUPS_ENABLED:
                user_groups = user.get_groups()
                user_questions = user_questions.filter(groups__in = user_groups)

            final_question_list = user_questions.get_questions_needing_reminder(
                user = user,
                activity_type = const.TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT,
                recurrence_delay = schedule.recurrence_delay
            )

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            threads = Thread.objects.filter(id__in=[qq.thread_id for qq in final_question_list])
            tag_summary = Thread.objects.get_tag_summary_from_threads(threads)

            if question_count == 1:
                unanswered_questions_phrase = askbot_settings.WORDS_UNANSWERED_QUESTION_SINGULAR
            else:
                unanswered_questions_phrase = askbot_settings.WORDS_UNANSWERED_QUESTION_PLURAL

            subject_line = ungettext(
                '%(question_count)d %(unanswered_questions)s about %(topics)s',
                '%(question_count)d %(unanswered_questions)s about %(topics)s',
                question_count
            ) % {
                'question_count': question_count,
                'unanswered_questions': unanswered_questions_phrase,
                'topics': tag_summary
            }

            data = {
                'recipient_user': user,
                'site_url': site_url(''),
                'subject_line': subject_line,
                'questions': final_question_list,
            }

            template = get_template('email/unanswered_question_reminder.html')
            body_text = template.render(Context(data))#todo: set lang


            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(
                    subject_line = subject_line,
                    body_text = body_text,
                    recipient_list = (user.email,)
                )
Exemple #50
0
def manage_inbox(request):
    """delete, mark as new or seen user's
    response memo objects, excluding flags
    request data is memo_list  - list of integer id's of the ActivityAuditStatus items
    and action_type - string - one of delete|mark_new|mark_seen
    """

    response_data = dict()
    try:
        if request.is_ajax():
            if request.method == 'POST':
                post_data = simplejson.loads(request.raw_post_data)
                if request.user.is_authenticated():
                    activity_types = const.RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY
                    activity_types += (
                        const.TYPE_ACTIVITY_MENTION,
                        const.TYPE_ACTIVITY_MARK_OFFENSIVE,
                        const.TYPE_ACTIVITY_MODERATED_NEW_POST,
                        const.TYPE_ACTIVITY_MODERATED_POST_EDIT
                    )
                    user = request.user
                    memo_set = models.ActivityAuditStatus.objects.filter(
                        id__in = post_data['memo_list'],
                        activity__activity_type__in = activity_types,
                        user = user
                    )

                    action_type = post_data['action_type']
                    if action_type == 'delete':
                        memo_set.delete()
                    elif action_type == 'mark_new':
                        memo_set.update(status = models.ActivityAuditStatus.STATUS_NEW)
                    elif action_type == 'mark_seen':
                        memo_set.update(status = models.ActivityAuditStatus.STATUS_SEEN)
                    elif action_type == 'remove_flag':
                        for memo in memo_set:
                            activity_type = memo.activity.activity_type
                            if activity_type == const.TYPE_ACTIVITY_MARK_OFFENSIVE:
                                request.user.flag_post(
                                    post = memo.activity.content_object,
                                    cancel_all = True
                                )
                            elif activity_type in \
                                (
                                    const.TYPE_ACTIVITY_MODERATED_NEW_POST,
                                    const.TYPE_ACTIVITY_MODERATED_POST_EDIT
                                ):
                                post_revision = memo.activity.content_object
                                request.user.approve_post_revision(post_revision)
                                memo.delete()

                    #elif action_type == 'close':
                    #    for memo in memo_set:
                    #        if memo.activity.content_object.post_type == "question":
                    #            request.user.close_question(question = memo.activity.content_object, reason = 7)
                    #            memo.delete()
                    elif action_type == 'delete_post':
                        for memo in memo_set:
                            content_object = memo.activity.content_object
                            if isinstance(content_object, models.PostRevision):
                                post = content_object.post
                            else:
                                post = content_object
                            request.user.delete_post(post)
                            reject_reason = models.PostFlagReason.objects.get(
                                                    id = post_data['reject_reason_id']
                                                )
                            body_text = string_concat(
                                _('Your post (copied in the end),'),
                                '<br/>',
                                _('was rejected for the following reason:'),
                                '<br/><br/>',
                                reject_reason.details.html,
                                '<br/><br/>',
                                _('Here is your original post'),
                                '<br/><br/>',
                                post.text
                            )
                            mail.send_mail(
                                subject_line = _('your post was not accepted'),
                                body_text = unicode(body_text),
                                recipient_list = [post.author.email,]
                            )
                            memo.delete()

                    user.update_response_counts()

                    response_data['success'] = True
                    data = simplejson.dumps(response_data)
                    return HttpResponse(data, mimetype="application/json")
                else:
                    raise exceptions.PermissionDenied(
                        _('Sorry, but anonymous users cannot access the inbox')
                    )
            else:
                raise exceptions.PermissionDenied('must use POST request')
        else:
            #todo: show error page but no-one is likely to get here
            return HttpResponseRedirect(reverse('index'))
    except Exception, e:
        message = unicode(e)
        if message == '':
            message = _('Oops, apologies - there was some error')
        response_data['message'] = message
        response_data['success'] = False
        data = simplejson.dumps(response_data)
        return HttpResponse(data, mimetype="application/json")
Exemple #51
0
def user_moderate(request, subject, context):
    """user subview for moderation
    """
    moderator = request.user

    if moderator.is_authenticated() and not moderator.can_moderate_user(subject):
        raise Http404

    user_rep_changed = False
    user_status_changed = False
    user_status_changed_message = _('User status changed')
    message_sent = False
    email_error_message = None

    user_rep_form = forms.ChangeUserReputationForm()
    send_message_form = forms.SendMessageForm()
    if request.method == 'POST':
        if 'change_status' in request.POST or 'hard_block' in request.POST:
            user_status_form = forms.ChangeUserStatusForm(
                                                    request.POST,
                                                    moderator = moderator,
                                                    subject = subject
                                                )
            if user_status_form.is_valid():
                subject.set_status( user_status_form.cleaned_data['user_status'] )
                if user_status_form.cleaned_data['delete_content'] == True:
                    num_deleted = request.user.delete_all_content_authored_by_user(subject)
                    if num_deleted:
                        num_deleted_message = ungettext('%d post deleted', '%d posts deleted', num_deleted) % num_deleted
                        user_status_changed_message = string_concat(user_status_changed_message, ', ', num_deleted_message)
            user_status_changed = True
        elif 'send_message' in request.POST:
            send_message_form = forms.SendMessageForm(request.POST)
            if send_message_form.is_valid():
                subject_line = send_message_form.cleaned_data['subject_line']
                body_text = send_message_form.cleaned_data['body_text']

                try:
                    send_mail(
                            subject_line = subject_line,
                            body_text = body_text,
                            recipient_list = [subject.email],
                            headers={'Reply-to':moderator.email},
                            raise_on_failure = True
                        )
                    message_sent = True
                except exceptions.EmailNotSent, e:
                    email_error_message = unicode(e)
                send_message_form = forms.SendMessageForm()
        else:
            reputation_change_type = None
            if 'subtract_reputation' in request.POST:
                rep_change_type = 'subtract'
            elif 'add_reputation' in request.POST:
                rep_change_type = 'add'
            else:
                raise Http404

            user_rep_form = forms.ChangeUserReputationForm(request.POST)
            if user_rep_form.is_valid():
                rep_delta = user_rep_form.cleaned_data['user_reputation_delta']
                comment = user_rep_form.cleaned_data['comment']

                if rep_change_type == 'subtract':
                    rep_delta = -1 * rep_delta

                moderator.moderate_user_reputation(
                                    user = subject,
                                    reputation_change = rep_delta,
                                    comment = comment,
                                    timestamp = datetime.datetime.now(),
                                )
                #reset form to preclude accidentally repeating submission
                user_rep_form = forms.ChangeUserReputationForm()
                user_rep_changed = True
Exemple #52
0
def user_moderate(request, subject, context):
    """user subview for moderation
    """
    moderator = request.user

    if moderator.is_authenticated(
    ) and not moderator.can_moderate_user(subject):
        raise Http404

    user_rep_changed = False
    user_status_changed = False
    message_sent = False
    email_error_message = None

    user_rep_form = forms.ChangeUserReputationForm()
    send_message_form = forms.SendMessageForm()
    if request.method == 'POST':
        if 'change_status' in request.POST:
            user_status_form = forms.ChangeUserStatusForm(request.POST,
                                                          moderator=moderator,
                                                          subject=subject)
            if user_status_form.is_valid():
                subject.set_status(
                    user_status_form.cleaned_data['user_status'])
            user_status_changed = True
        elif 'send_message' in request.POST:
            send_message_form = forms.SendMessageForm(request.POST)
            if send_message_form.is_valid():
                subject_line = send_message_form.cleaned_data['subject_line']
                body_text = send_message_form.cleaned_data['body_text']

                try:
                    send_mail(subject_line=subject_line,
                              body_text=body_text,
                              recipient_list=[subject.email],
                              headers={'Reply-to': moderator.email},
                              raise_on_failure=True)
                    message_sent = True
                except exceptions.EmailNotSent, e:
                    email_error_message = unicode(e)
                send_message_form = forms.SendMessageForm()
        else:
            reputation_change_type = None
            if 'subtract_reputation' in request.POST:
                rep_change_type = 'subtract'
            elif 'add_reputation' in request.POST:
                rep_change_type = 'add'
            else:
                raise Http404

            user_rep_form = forms.ChangeUserReputationForm(request.POST)
            if user_rep_form.is_valid():
                rep_delta = user_rep_form.cleaned_data['user_reputation_delta']
                comment = user_rep_form.cleaned_data['comment']

                if rep_change_type == 'subtract':
                    rep_delta = -1 * rep_delta

                moderator.moderate_user_reputation(
                    user=subject,
                    reputation_change=rep_delta,
                    comment=comment,
                    timestamp=datetime.datetime.now(),
                )
                #reset form to preclude accidentally repeating submission
                user_rep_form = forms.ChangeUserReputationForm()
                user_rep_changed = True
    def handle_noargs(self, **options):
        if askbot_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if askbot_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            askbot_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER,
            askbot_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY,
            askbot_settings.MAX_ACCEPT_ANSWER_REMINDERS)

        questions = models.Post.objects.get_questions().exclude(
            deleted=True).added_between(
                start=schedule.start_cutoff_date, end=schedule.end_cutoff_date
            ).filter(thread__answer_count__gt=0).filter(
                thread__accepted_answer__isnull=True  #answer_accepted = False
            ).order_by('-added_at')
        #for all users, excluding blocked
        #for each user, select a tag filtered subset
        #format the email reminder and send it
        for user in models.User.objects.exclude(status='b'):
            user_questions = questions.filter(author=user)

            final_question_list = user_questions.get_questions_needing_reminder(
                activity_type=const.TYPE_ACTIVITY_ACCEPT_ANSWER_REMINDER_SENT,
                user=user,
                recurrence_delay=schedule.recurrence_delay)
            #todo: rewrite using query set filter
            #may be a lot more efficient

            question_count = len(final_question_list)
            if question_count == 0:
                continue

            subject_line = _(
                'Accept the best answer for %(question_count)d of your questions'
            ) % {
                'question_count': question_count
            }

            #todo - make a template for these
            if question_count == 1:
                reminder_phrase = _(
                    'Please accept the best answer for this question:')
            else:
                reminder_phrase = _(
                    'Please accept the best answer for these questions:')
            body_text = '<p>' + reminder_phrase + '</p>'
            body_text += '<ul>'
            for question in final_question_list:
                body_text += '<li><a href="%s%s?sort=latest">%s</a></li>' \
                            % (
                                askbot_settings.APP_URL,
                                question.get_absolute_url(),
                                question.thread.title
                            )
            body_text += '</ul>'

            if DEBUG_THIS_COMMAND:
                print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
                    (user.email, subject_line, body_text)
            else:
                mail.send_mail(subject_line=subject_line,
                               body_text=body_text,
                               recipient_list=(user.email, ))