Exemplo n.º 1
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],
            )
Exemplo n.º 2
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 openode 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 openode.mail.messages
        data = {
            'site_name': openode_settings.APP_SHORT_NAME,
            'site_url': openode_settings.APP_URL,
            'ask_address': 'ask@' + openode_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,]
        )
Exemplo n.º 3
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="Openode Mail Test", body_text="Openode Mail Test", recipient_list=[args[0]])
Exemplo n.º 4
0
def notify_about_requests(user_list, subject, text):
    data = {
            'text': text,
            'site_name': openode_settings.APP_SHORT_NAME,
            'site_url': openode_settings.APP_URL
        }

    template = get_template('email/notification.html')
    message = template.render(data)
    email_list = [user.email for user in user_list]

    mail.send_mail(subject, message, django_settings.DEFAULT_FROM_EMAIL, email_list, raise_on_failure=True)
Exemplo n.º 5
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 = 'Openode Mail Test',
            body_text = 'Openode Mail Test',
            recipient_list = [args[0]],
        )
Exemplo n.º 6
0
def notify_about_requests(user_list, subject, text):
    data = {
        'text': text,
        'site_name': openode_settings.APP_SHORT_NAME,
        'site_url': openode_settings.APP_URL
    }

    template = get_template('email/notification.html')
    message = template.render(data)
    email_list = [user.email for user in user_list]

    mail.send_mail(subject,
                   message,
                   django_settings.DEFAULT_FROM_EMAIL,
                   email_list,
                   raise_on_failure=True)
Exemplo n.º 7
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': openode_settings.APP_SHORT_NAME,
            'site_url': openode_settings.APP_URL,
            'ask_address': 'ask@' + openode_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'
            )
        )
Exemplo n.º 8
0
def immediately_notify_users(post):

    # we don't want to disturb original routine
    try:
        # set default language TODO - language per user - add user atribute
        old_lang = get_language()
        activate(django_settings.LANGUAGE_CODE)

        DEBUG_THIS_COMMAND = getattr(django_settings,
                                     'DEBUG_SEND_EMAIL_NOTIFICATIONS', True)

        # compose subject according to the post type
        subject_line = _('Notification')
        if post.post_type == const.POST_TYPE_QUESTION:
            subject_line += ': ' + _('Question')
        elif post.post_type == const.POST_TYPE_DOCUMENT:
            subject_line += ': ' + _('Document')
        elif post.post_type == const.POST_TYPE_COMMENT:
            subject_line += ': ' + _('Comment')
        elif post.post_type == const.POST_TYPE_THREAD_POST:
            if post.thread.thread_type == const.THREAD_TYPE_QUESTION:
                subject_line += ': ' + _('Answer')
            elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION:
                subject_line += ': ' + _('Discussion post')
        else:
            # post type is probably only a description, do nothing
            activate(old_lang)
            return False

        subject_line += ' - ' + post.thread.title

        # compose message according to post type
        url_prefix = openode_settings.APP_URL
        # link to node
        # text = u'<p>%s: <a href="%s">%s</a></p>' % (_('Node'), url_prefix + post.thread.node.get_absolute_url(), post.thread.node.full_title())
        text = u'<p>%s: %s</p>' % (_('Node'), post.thread.node.full_title())
        # title according to the post type
        text += '<h2>'
        if post.last_edited_by:
            # post was updated
            if post.post_type == const.POST_TYPE_QUESTION:
                text += _('Updated question')
            elif post.post_type == const.POST_TYPE_DOCUMENT:
                text += _('Updated document')
            elif post.post_type == const.POST_TYPE_COMMENT:
                text += _('Updated comment')
            elif post.post_type == const.POST_TYPE_THREAD_POST:
                if post.thread.thread_type == const.THREAD_TYPE_QUESTION:
                    text += _('Updated answer')
                elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION:
                    text += _('Updated discussion post')
        else:
            # post is new
            if post.post_type == const.POST_TYPE_QUESTION:
                text += _('New question')
            elif post.post_type == const.POST_TYPE_DOCUMENT:
                text += _('New document')
            elif post.post_type == const.POST_TYPE_COMMENT:
                text += _('New comment')
            elif post.post_type == const.POST_TYPE_THREAD_POST:
                if post.thread.thread_type == const.THREAD_TYPE_QUESTION:
                    text += _('New answer')
                elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION:
                    text += _('New discussion post')
        text += '</h2>'

        # link to post
        if post.post_type == const.POST_TYPE_DOCUMENT:
            url = url_prefix + post.thread.get_absolute_url()
        else:
            url = url_prefix + post.get_absolute_url()
        text += '<p><a href="%(url)s">%(url)s</a></p>' % {"url": url}

        # author
        text += '<p>'
        if post.last_edited_by:
            # post was updated
            text += _(u'%(datetime)s changed by <strong>%(user)s</strong>') % {
                'datetime': humanize_datetime(post.last_edited_at, 0),
                'user': post.last_edited_by.screen_name
            }
        else:
            # post is new
            text += _(u'%(datetime)s created by <strong>%(user)s</strong>') % {
                'datetime': humanize_datetime(post.added_at, 0),
                'user': post.author.screen_name
            }
        text += '</p>'

        # show post text
        text += post.html

        # show related post if convenient
        if post.post_type == const.POST_TYPE_THREAD_POST and post.thread.thread_type == const.THREAD_TYPE_QUESTION:
            text += '<h3>'
            text += _('Question')
            text += '</h3>'
            # text += '<p><a href="%s">%s</a></p>' % (url_prefix + post.thread._main_post().get_absolute_url(), url_prefix + post.thread._main_post().get_absolute_url())
            text += post.thread._main_post().html
        elif post.post_type == const.POST_TYPE_COMMENT:
            text += '<h3>'
            text += _('Commented post')
            text += '</h3>'
            # text += '<p><a href="%s">%s</a></p>' % (url_prefix + post.parent.get_absolute_url(), url_prefix + post.parent.get_absolute_url())
            text += post.parent.html

        # message bottom
        text += '<hr />'
        text += '<p>'
        text += _(
            'Please remember that you can always adjust frequency of the email updates or turn them off entirely in your profile.'
        )
        text += '</p>'
        text += '<p>'
        text += _(
            'If you believe that this message was sent in an error, please contact us.'
        )
        text += '</p>'

        # render email
        data = {
            'text': text,
            'site_name': openode_settings.APP_SHORT_NAME,
            'site_url': openode_settings.APP_URL
        }
        template = get_template('email/instant_notification.html')
        message = template.render(data)

        recipients = {}
        # get all thread followers
        for user in post.thread.followed_by.filter(
                notification_subscriptions__frequency='i',
                notification_subscriptions__feed_type='q_sel'):
            recipients[user.pk] = user

        # get all node followers
        for user in post.thread.node.followed_by.filter(
                notification_subscriptions__frequency='i',
                notification_subscriptions__feed_type='q_sel'):
            recipients[user.pk] = user

        # remove author of this editation from recipients
        if post.last_edited_by:
            # post was updated
            recipients.pop(post.last_edited_by.pk, None)
        else:
            # post is new
            recipients.pop(post.author.pk, None)

        # send all emails
        for user in recipients.values():
            if DEBUG_THIS_COMMAND:
                recipient_email = django_settings.ADMINS[0][1]
            else:
                recipient_email = user.email

            mail.send_mail(subject_line,
                           message,
                           django_settings.DEFAULT_FROM_EMAIL,
                           [recipient_email],
                           raise_on_failure=True)
            logging.info('Email notification sent: %s' %
                         repr({
                             "user": user.screen_name,
                             "user_email": recipient_email,
                             "user_pk": user.pk,
                             "post_pk": post.pk
                         }))

        activate(old_lang)
        return True

    except Exception, e:
        logging.error(
            'Email notification - failed to send immediate notification for post: %s'
            % repr({
                "post_pk": post.pk,
                "error": e
            }))
    def handle_noargs(self, **options):
        if openode_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if openode_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            openode_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER,
            openode_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY,
            openode_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:')

            data = {
                    'site_url': openode_settings.APP_URL,
                    'questions': final_question_list,
                    'reminder_phrase': reminder_phrase
                   }

            template = get_template('email/accept_answer_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,)
                )
Exemplo n.º 10
0
def immediately_notify_users(post):

    # we don't want to disturb original routine
    try:
        # set default language TODO - language per user - add user atribute
        old_lang = get_language()
        activate(django_settings.LANGUAGE_CODE)

        DEBUG_THIS_COMMAND = getattr(django_settings, 'DEBUG_SEND_EMAIL_NOTIFICATIONS', True)

        # compose subject according to the post type
        subject_line = _('Notification')
        if post.post_type == const.POST_TYPE_QUESTION:
            subject_line += ': ' + _('Question')
        elif post.post_type == const.POST_TYPE_DOCUMENT:
            subject_line += ': ' + _('Document')
        elif post.post_type == const.POST_TYPE_COMMENT:
            subject_line += ': ' + _('Comment')
        elif post.post_type == const.POST_TYPE_THREAD_POST:
            if post.thread.thread_type == const.THREAD_TYPE_QUESTION:
                subject_line += ': ' + _('Answer')
            elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION:
                subject_line += ': ' + _('Discussion post')
        else:
            # post type is probably only a description, do nothing
            activate(old_lang)
            return False

        subject_line += ' - ' + post.thread.title

        # compose message according to post type
        url_prefix = openode_settings.APP_URL
        # link to node
        # text = u'<p>%s: <a href="%s">%s</a></p>' % (_('Node'), url_prefix + post.thread.node.get_absolute_url(), post.thread.node.full_title())
        text = u'<p>%s: %s</p>' % (_('Node'), post.thread.node.full_title())
        # title according to the post type
        text += '<h2>'
        if post.last_edited_by:
            # post was updated
            if post.post_type == const.POST_TYPE_QUESTION:
                text += _('Updated question')
            elif post.post_type == const.POST_TYPE_DOCUMENT:
                text += _('Updated document')
            elif post.post_type == const.POST_TYPE_COMMENT:
                text += _('Updated comment')
            elif post.post_type == const.POST_TYPE_THREAD_POST:
                if post.thread.thread_type == const.THREAD_TYPE_QUESTION:
                    text += _('Updated answer')
                elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION:
                    text += _('Updated discussion post')
        else:
            # post is new
            if post.post_type == const.POST_TYPE_QUESTION:
                text += _('New question')
            elif post.post_type == const.POST_TYPE_DOCUMENT:
                text += _('New document')
            elif post.post_type == const.POST_TYPE_COMMENT:
                text += _('New comment')
            elif post.post_type == const.POST_TYPE_THREAD_POST:
                if post.thread.thread_type == const.THREAD_TYPE_QUESTION:
                    text += _('New answer')
                elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION:
                    text += _('New discussion post')
        text += '</h2>'

        # link to post
        if post.post_type == const.POST_TYPE_DOCUMENT:
            url = url_prefix + post.thread.get_absolute_url()
        else:
            url = url_prefix + post.get_absolute_url()
        text += '<p><a href="%(url)s">%(url)s</a></p>' % {"url": url}

        # author
        text += '<p>'
        if post.last_edited_by:
            # post was updated
            text += _(u'%(datetime)s changed by <strong>%(user)s</strong>') % {'datetime': humanize_datetime(post.last_edited_at, 0), 'user': post.last_edited_by.screen_name}
        else:
            # post is new
            text += _(u'%(datetime)s created by <strong>%(user)s</strong>') % {'datetime': humanize_datetime(post.added_at, 0), 'user': post.author.screen_name}
        text += '</p>'

        # show post text
        text += post.html

        # show related post if convenient
        if post.post_type == const.POST_TYPE_THREAD_POST and post.thread.thread_type == const.THREAD_TYPE_QUESTION:
            text += '<h3>'
            text += _('Question')
            text += '</h3>'
            # text += '<p><a href="%s">%s</a></p>' % (url_prefix + post.thread._main_post().get_absolute_url(), url_prefix + post.thread._main_post().get_absolute_url())
            text += post.thread._main_post().html
        elif post.post_type == const.POST_TYPE_COMMENT:
            text += '<h3>'
            text += _('Commented post')
            text += '</h3>'
            # text += '<p><a href="%s">%s</a></p>' % (url_prefix + post.parent.get_absolute_url(), url_prefix + post.parent.get_absolute_url())
            text += post.parent.html

        # message bottom
        text += '<hr />'
        text += '<p>'
        text += _('Please remember that you can always adjust frequency of the email updates or turn them off entirely in your profile.')
        text += '</p>'
        text += '<p>'
        text += _('If you believe that this message was sent in an error, please contact us.')
        text += '</p>'

        # render email
        data = {
            'text': text,
            'site_name': openode_settings.APP_SHORT_NAME,
            'site_url': openode_settings.APP_URL
        }
        template = get_template('email/instant_notification.html')
        message = template.render(data)

        recipients = {}
        # get all thread followers
        for user in post.thread.followed_by.filter(notification_subscriptions__frequency='i', notification_subscriptions__feed_type='q_sel'):
            recipients[user.pk] = user

        # get all node followers
        for user in post.thread.node.followed_by.filter(notification_subscriptions__frequency='i', notification_subscriptions__feed_type='q_sel'):
            recipients[user.pk] = user

        # remove author of this editation from recipients
        if post.last_edited_by:
            # post was updated
            recipients.pop(post.last_edited_by.pk, None)
        else:
            # post is new
            recipients.pop(post.author.pk, None)

        # send all emails
        for user in recipients.values():
            if DEBUG_THIS_COMMAND:
                recipient_email = django_settings.ADMINS[0][1]
            else:
                recipient_email = user.email

            mail.send_mail(subject_line, message, django_settings.DEFAULT_FROM_EMAIL, [recipient_email], raise_on_failure=True)
            logging.info('Email notification sent: %s' % repr({
                "user": user.screen_name,
                "user_email": recipient_email,
                "user_pk": user.pk,
                "post_pk": post.pk
            }))

        activate(old_lang)
        return True

    except Exception, e:
        logging.error('Email notification - failed to send immediate notification for post: %s' % repr({
            "post_pk": post.pk,
            "error": e
        }))
Exemplo n.º 11
0
    def handle_noargs(self, **options):
        if openode_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if openode_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date

        schedule = ReminderSchedule(
            openode_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER,
            openode_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY,
            openode_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:')

            data = {
                'site_url': openode_settings.APP_URL,
                'questions': final_question_list,
                'reminder_phrase': reminder_phrase
            }

            template = get_template('email/accept_answer_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, ))
Exemplo n.º 12
0
def user_overview(request, user, context):
    question_filter = {}

    #
    # Questions
    #
    questions = user.posts.get_questions(
        user=request.user
    ).filter(
        **question_filter
    ).order_by(
        '-points', '-thread__last_activity_at'
    ).select_related(
        'thread', 'thread__last_activity_by'
    )[:100]

    #added this if to avoid another query if questions is less than 100
    if len(questions) < 100:
        question_count = len(questions)
    else:
        question_count = user.posts.get_questions().filter(**question_filter).count()

    #
    # Top answers
    #
    top_answers = user.posts.get_answers(
        request.user
    ).filter(
        deleted=False,
        thread__posts__deleted=False,
        thread__posts__post_type='question',
    ).select_related(
        'thread'
    ).order_by(
        '-points', '-added_at'
    )[:100]

    top_answer_count = len(top_answers)
    #
    # Votes
    #
    up_votes = models.Vote.objects.get_up_vote_count_from_user(user)
    down_votes = models.Vote.objects.get_down_vote_count_from_user(user)
    votes_today = models.Vote.objects.get_votes_count_today_from_user(user)
    votes_total = openode_settings.MAX_VOTES_PER_USER_PER_DAY

    #
    # Tags
    #
    # INFO: There's bug in Django that makes the following query kind of broken (GROUP BY clause is problematic):
    #       http://stackoverflow.com/questions/7973461/django-aggregation-does-excessive-organization-by-clauses
    #       Fortunately it looks like it returns correct results for the test data
    user_tags = models.Tag.objects.filter(
        threads__posts__author=user
    ).distinct().annotate(
        user_tag_usage_count=Count('threads')
    ).order_by(
        '-user_tag_usage_count'
    )[:const.USER_VIEW_DATA_SIZE]
    user_tags = list(user_tags)  # evaluate

    when = openode_settings.MARKED_TAGS_ARE_PUBLIC_WHEN
    if when == 'always' or \
        (when == 'when-user-wants' and user.show_marked_tags == True):
        #refactor into: user.get_marked_tag_names('good'/'bad'/'subscribed')
        interesting_tag_names = user.get_marked_tag_names('good')
        ignored_tag_names = user.get_marked_tag_names('bad')
        subscribed_tag_names = user.get_marked_tag_names('subscribed')
    else:
        interesting_tag_names = None
        ignored_tag_names = None
        subscribed_tag_names = None

#    tags = models.Post.objects.filter(author=user).values('id', 'thread', 'thread__tags')
#    post_ids = set()
#    thread_ids = set()
#    tag_ids = set()
#    for t in tags:
#        post_ids.add(t['id'])
#        thread_ids.add(t['thread'])
#        tag_ids.add(t['thread__tags'])
#        if t['thread__tags'] == 11:
#            print t['thread'], t['id']
#    import ipdb; ipdb.set_trace()

    #
    #
    # post_type = ContentType.objects.get_for_model(models.Post)

    if request.user != user and request.user.is_authenticated() and user.privacy_email_form:
        if request.method == 'POST':
            email_form = UserEmailForm(request.POST)
            if email_form.is_valid():
                subject = email_form.cleaned_data['subject']
                text = email_form.cleaned_data['text']
                url = urlparse(openode_settings.APP_URL)
                data = {
                    'from_user_url': url.scheme + '://' + url.netloc + reverse('user_profile', args=[request.user.pk]),
                    'from_user_screen_name': request.user.screen_name,
                    'text': text,
                    "request": request
                }
                template = get_template('email/user_profile_email.html')
                message = template.render(data)

                send_mail(subject_line=subject,
                    body_text=message,
                    from_email=django_settings.DEFAULT_FROM_EMAIL,
                    recipient_list=[user.email],
                )

                request.user.log(user, const.LOG_ACTION_SEND_EMAIL_TO_USER)
                request.user.message_set.create(message=_('Email has been succesfully sent.'))
                email_form = UserEmailForm()
        else:
            email_form = UserEmailForm()
    else:
        email_form = None

    # if request.user.is_authenticated():
    #     managed_nodes = user.nodes.filter(node_users__role=const.NODE_USER_ROLE_MANAGER)
    # else:
    #     managed_nodes = None

    # TODO not all variables are necessary
    data = {
        'active_tab': 'users',
        'page_class': 'user-profile-page',
        'support_custom_avatars': ('avatar' in django_settings.INSTALLED_APPS),
        'tab_description': _('user profile'),
        'page_title': _('user profile overview'),
        'user_status_for_display': user.get_status_display(soft=True),
        'questions': questions,
        'question_count': question_count,

        'top_answers': top_answers,
        'top_answer_count': top_answer_count,

        'up_votes': up_votes,
        'down_votes': down_votes,
        'total_votes': up_votes + down_votes,
        'votes_today_left': votes_total - votes_today,
        'votes_total_per_day': votes_total,

        # 'managed_nodes': managed_nodes,
        'user_tags': user_tags,
        'interesting_tag_names': interesting_tag_names,
        'ignored_tag_names': ignored_tag_names,
        'subscribed_tag_names': subscribed_tag_names,
        'email_form': email_form
    }
    context.update(data)

    view_user = context.get('view_user')
    if view_user is not None and not view_user.is_active:
        return render_into_skin('user_profile/user_overview_disabled.html', context, request)

    return render_into_skin('user_profile/user_overview.html', context, request)
Exemplo n.º 13
0
def user_overview(request, user, context):
    question_filter = {}

    #
    # Questions
    #
    questions = user.posts.get_questions(
        user=request.user
    ).filter(
        **question_filter
    ).order_by(
        '-points', '-thread__last_activity_at'
    ).select_related(
        'thread', 'thread__last_activity_by'
    )[:100]

    #added this if to avoid another query if questions is less than 100
    if len(questions) < 100:
        question_count = len(questions)
    else:
        question_count = user.posts.get_questions().filter(**question_filter).count()

    #
    # Top answers
    #
    top_answers = user.posts.get_answers(
        request.user
    ).filter(
        deleted=False,
        thread__posts__deleted=False,
        thread__posts__post_type='question',
    ).select_related(
        'thread'
    ).order_by(
        '-points', '-added_at'
    )[:100]

    top_answer_count = len(top_answers)
    #
    # Votes
    #
    up_votes = models.Vote.objects.get_up_vote_count_from_user(user)
    down_votes = models.Vote.objects.get_down_vote_count_from_user(user)
    votes_today = models.Vote.objects.get_votes_count_today_from_user(user)
    votes_total = openode_settings.MAX_VOTES_PER_USER_PER_DAY

    #
    # Tags
    #
    # INFO: There's bug in Django that makes the following query kind of broken (GROUP BY clause is problematic):
    #       http://stackoverflow.com/questions/7973461/django-aggregation-does-excessive-organization-by-clauses
    #       Fortunately it looks like it returns correct results for the test data
    user_tags = models.Tag.objects.filter(
        threads__posts__author=user
    ).distinct().annotate(
        user_tag_usage_count=Count('threads')
    ).order_by(
        '-user_tag_usage_count'
    )[:const.USER_VIEW_DATA_SIZE]
    user_tags = list(user_tags)  # evaluate

    when = openode_settings.MARKED_TAGS_ARE_PUBLIC_WHEN
    if when == 'always' or \
        (when == 'when-user-wants' and user.show_marked_tags == True):
        #refactor into: user.get_marked_tag_names('good'/'bad'/'subscribed')
        interesting_tag_names = user.get_marked_tag_names('good')
        ignored_tag_names = user.get_marked_tag_names('bad')
        subscribed_tag_names = user.get_marked_tag_names('subscribed')
    else:
        interesting_tag_names = None
        ignored_tag_names = None
        subscribed_tag_names = None

#    tags = models.Post.objects.filter(author=user).values('id', 'thread', 'thread__tags')
#    post_ids = set()
#    thread_ids = set()
#    tag_ids = set()
#    for t in tags:
#        post_ids.add(t['id'])
#        thread_ids.add(t['thread'])
#        tag_ids.add(t['thread__tags'])
#        if t['thread__tags'] == 11:
#            print t['thread'], t['id']
#    import ipdb; ipdb.set_trace()

    #
    #
    # post_type = ContentType.objects.get_for_model(models.Post)

    if request.user != user and request.user.is_authenticated() and user.privacy_email_form:
        if request.method == 'POST':
            email_form = UserEmailForm(request.POST)
            if email_form.is_valid():
                subject = email_form.cleaned_data['subject']
                text = email_form.cleaned_data['text']
                url = urlparse(openode_settings.APP_URL)
                data = {
                    'from_user_url': url.scheme + '://' + url.netloc + reverse('user_profile', args=[request.user.pk]),
                    'from_user_screen_name': request.user.screen_name,
                    'text': text,
                    "request": request
                }
                template = get_template('email/user_profile_email.html')
                message = template.render(data)

                send_mail(subject_line=subject,
                    body_text=message,
                    from_email=django_settings.DEFAULT_FROM_EMAIL,
                    recipient_list=[user.email],
                )

                request.user.log(user, const.LOG_ACTION_SEND_EMAIL_TO_USER)
                request.user.message_set.create(message=_('Email has been succesfully sent.'))
                email_form = UserEmailForm()
        else:
            email_form = UserEmailForm()
    else:
        email_form = None

    # if request.user.is_authenticated():
    #     managed_nodes = user.nodes.filter(node_users__role=const.NODE_USER_ROLE_MANAGER)
    # else:
    #     managed_nodes = None

    # TODO not all variables are necessary
    data = {
        'active_tab': 'users',
        'page_class': 'user-profile-page',
        'support_custom_avatars': ('avatar' in django_settings.INSTALLED_APPS),
        'tab_description': _('user profile'),
        'page_title': _('user profile overview'),
        'user_status_for_display': user.get_status_display(soft=True),
        'questions': questions,
        'question_count': question_count,

        'top_answers': top_answers,
        'top_answer_count': top_answer_count,

        'up_votes': up_votes,
        'down_votes': down_votes,
        'total_votes': up_votes + down_votes,
        'votes_today_left': votes_total - votes_today,
        'votes_total_per_day': votes_total,

        # 'managed_nodes': managed_nodes,
        'user_tags': user_tags,
        'interesting_tag_names': interesting_tag_names,
        'ignored_tag_names': ignored_tag_names,
        'subscribed_tag_names': subscribed_tag_names,
        'email_form': email_form
    }
    context.update(data)

    view_user = context.get('view_user')
    if view_user is not None and not view_user.is_active:
        return render_into_skin('user_profile/user_overview_disabled.html', context, request)

    return render_into_skin('user_profile/user_overview.html', context, request)
Exemplo n.º 14
0
    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_openode_subscriptions()
            #todo: q_list is a dictionary, not a list

            q_list = self.get_updated_threads_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

            print 'user:'******''
                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': openode_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 >= openode_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>' \
                                    % (url_prefix + q.get_absolute_url(), q.thread.title, act_token)
                text += '</ul>'
                text += '<p></p>'
                #if len(q_list.keys()) >= openode_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 openode and see what\'s new!<br>'
                #              )

                link = url_prefix + reverse(
                                        'user_profile',
                                        kwargs={
                                            'id': user.id,
                                            'tab_name': 'email_subscriptions'
                                        }
                                    )

                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': link,
                    'admin_email': django_settings.ADMINS[0][1],
                    'sitename': openode_settings.APP_SHORT_NAME
                }
                if DEBUG_THIS_COMMAND == True:
                    recipient_email = django_settings.ADMINS[0][1]
                else:
                    recipient_email = user.email
                print recipient_email
                mail.send_mail(
                    subject_line=subject_line,
                    body_text=text,
                    recipient_list=[recipient_email]
                )
Exemplo n.º 15
0
    def handle_noargs(self, **options):
        if openode_settings.ENABLE_EMAIL_ALERTS == False:
            return
        if openode_settings.ENABLE_UNANSWERED_REMINDERS == False:
            return
        #get questions without answers, excluding closed and deleted
        #order it by descending added_at date
        schedule = ReminderSchedule(
            openode_settings.DAYS_BEFORE_SENDING_UNANSWERED_REMINDER,
            openode_settings.UNANSWERED_REMINDER_FREQUENCY,
            max_reminders = openode_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)

            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': openode_settings.APP_URL,
                    'questions': final_question_list,
                    'subject_line': subject_line
                   }

            template = get_template('email/unanswered_question_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,)
                )
Exemplo n.º 16
0
    def send_email_alerts(self):
        #does not change the database, only sends the email
        #todo: move this to template
        for user in User.objects.filter(is_active=True):
            user.add_missing_openode_subscriptions()
            #todo: q_list is a dictionary, not a list

            # print 'user:'******'skip']:
                    del q_list[question]
                else:
                    num_q += 1

            logging.info(u'Notification: %s (pk=%s) will recieve %s notices' % (user.screen_name, user.pk, num_q))
            # print 'pocet:', num_q
            if num_q > 0:
                url_prefix = openode_settings.APP_URL

                # 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) #TODO
                # tag_summary = ''
                # question_count = len(q_list.keys())

                subject_line = _('Updates overview')

                #todo: send this to special log
                #print 'have %d updated questions for %s' % (num_q, user.username)
                text = ''

                items_added = 0
                # items_unreported = 0
                for q, meta_data in q_list.items():
                    act_list = []
                    if meta_data['skip']:
                        continue
                    # if items_added >= openode_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']:
                            if q.post_type == const.POST_TYPE_QUESTION:
                                act_list.append(_('new question'))
                            elif q.post_type == const.POST_TYPE_DISCUSSION:
                                act_list.append(_('new discussion'))
                            elif q.post_type == const.POST_TYPE_DOCUMENT:
                                act_list.append(_('new document'))

                        if meta_data['q_rev']:
                            if q.post_type == const.POST_TYPE_QUESTION:
                                act_list.append(_('changed question'))
                            elif q.post_type == const.POST_TYPE_DISCUSSION:
                                act_list.append(_('changed discussion'))
                            elif q.post_type == const.POST_TYPE_DOCUMENT:
                                act_list.append(_('changed document'))

                        if meta_data['new_ans']:
                            if q.post_type == const.POST_TYPE_QUESTION:
                                act_list.append(_('%(num)d new answers') % {'num': meta_data['new_ans']})
                            elif q.post_type == const.POST_TYPE_DISCUSSION:
                                act_list.append(_('%(num)d new posts') % {'num': meta_data['new_ans']})

                        if meta_data['ans_rev']:
                            if q.post_type == const.POST_TYPE_QUESTION:
                                act_list.append(_('%(num)d changed answers') % {'num': meta_data['ans_rev']})
                            elif q.post_type == const.POST_TYPE_DISCUSSION:
                                act_list.append(_('%(num)d changed posts') % {'num': meta_data['ans_rev']})

                        # 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 += '<a href="%s">%s</a> (%s)<br />' % (url_prefix + q.get_absolute_url(), q.thread.title, act_token)

                #if len(q_list.keys()) >= openode_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 openode and see what\'s new!<br>'
                #              )

                # link = url_prefix + reverse(
                #                         'user_profile',
                #                         kwargs={
                #                             'id': user.id,
                #                             'tab_name': 'email_subscriptions'
                #                         }
                #                     )

                text += '<hr />'
                text += '<p>'
                text += _('Please remember that you can always adjust frequency of the email updates or turn them off entirely in your profile.')
                text += '</p>'
                text += '<p>'
                text += _('If you believe that this message was sent in an error, please contact us.')
                text += '</p>'

                if DEBUG_THIS_COMMAND == True:
                    recipient_email = django_settings.ADMINS[0][1]
                else:
                    recipient_email = user.email
                # print 'odeslan email'

                data = {
                    'text': text,
                    'site_name': openode_settings.APP_SHORT_NAME,
                    'site_url': openode_settings.APP_URL
                }
                from openode.skins.loaders import get_template
                template = get_template('email/notification.html')
                message = template.render(data)
                mail.send_mail(subject_line, message, django_settings.DEFAULT_FROM_EMAIL, [recipient_email], raise_on_failure=True)
                logging.info('Notification: %s (pk=%s) mail sent' % (user.screen_name, user.pk))