示例#1
0
 def test_unsubscribe_url(self):
     text, html = render_digest(self.user, self.digest, "dummy", "dummy")
     expected_url = "{lms_url_base}/notification_prefs/unsubscribe/{token}/".format(
         lms_url_base=settings.LMS_URL_BASE,
         token=self.user["preferences"][DIGEST_NOTIFICATION_PREFERENCE_KEY]
     )
     self.assertIn(expected_url, text)
     self.assertIn(expected_url, html)
示例#2
0
def generate_and_send_digests(users, from_dt, to_dt):
    """
    This task generates and sends forum digest emails to multiple users in a
    single background operation.

    `users` is an iterable of dictionaries, as returned by the edx user_api
    (required keys are "id", "name", "username", and "email").

    `from_dt` and `to_dt` are datetime objects representing the start and end
    of the time window for which to generate a digest.
    """
    users_by_id = dict((str(u['id']), u) for u in users)
    with closing(get_connection()) as cx:
        msgs = []
        for user_id, digest in generate_digest_content(users_by_id.keys(), from_dt, to_dt):
            user = users_by_id[user_id]
            # format the digest
            text, html = render_digest(
                user, digest, settings.FORUM_DIGEST_EMAIL_TITLE, settings.FORUM_DIGEST_EMAIL_DESCRIPTION)
            # send the message through our mailer
            msg = EmailMultiAlternatives(
                settings.FORUM_DIGEST_EMAIL_SUBJECT,
                text,
                '@'.join(
                    [settings.FORUM_DIGEST_EMAIL_SENDER,
                     settings.EMAIL_DOMAIN]),

                [user['email']]
            )
            msg.attach_alternative(html, "text/html")
            msgs.append(msg)
        if not msgs:
            return
        try:
            cx.send_messages(msgs)
        except SESMaxSendingRateExceededError as e:
            # we've tripped the per-second send rate limit.  we generally
            # rely  on the django_ses auto throttle to prevent this,
            # but in case we creep over, we can re-queue and re-try this task
            # - if and only if none of the messages in our batch were
            # sent yet.
            # this implementation is also non-ideal in that the data will be
            # fetched from the comments service again in the event of a retry.
            if not any((getattr(msg, 'extra_headers', {}).get('status') == 200 for msg in msgs)):
                raise generate_and_send_digests.retry(exc=e)
            else:
                # raise right away, since we don't support partial retry
                raise
示例#3
0
def generate_and_send_digests(users, from_dt, to_dt):
    """
    This task generates and sends forum digest emails to multiple users in a
    single background operation.

    `users` is an iterable of dictionaries, as returned by the edx user_api
    (required keys are "id", "name", "username", and "email").

    `from_dt` and `to_dt` are datetime objects representing the start and end
    of the time window for which to generate a digest.
    """
    users_by_id = dict((str(u['id']), u) for u in users)
    with closing(get_connection()) as cx:
        msgs = []
        for user_id, digest in generate_digest_content(users_by_id.keys(),
                                                       from_dt, to_dt):
            user = users_by_id[user_id]
            # format the digest
            text, html = render_digest(user, digest,
                                       settings.FORUM_DIGEST_EMAIL_TITLE,
                                       settings.FORUM_DIGEST_EMAIL_DESCRIPTION)
            # send the message through our mailer
            msg = EmailMultiAlternatives(settings.FORUM_DIGEST_EMAIL_SUBJECT,
                                         text,
                                         settings.FORUM_DIGEST_EMAIL_SENDER,
                                         [user['email']])
            msg.attach_alternative(html, "text/html")
            msgs.append(msg)
        if not msgs:
            return
        try:
            cx.send_messages(msgs)
        except SESMaxSendingRateExceededError as e:
            # we've tripped the per-second send rate limit.  we generally
            # rely  on the django_ses auto throttle to prevent this,
            # but in case we creep over, we can re-queue and re-try this task
            # - if and only if none of the messages in our batch were
            # sent yet.
            # this implementation is also non-ideal in that the data will be
            # fetched from the comments service again in the event of a retry.
            if not any((getattr(msg, 'extra_headers', {}).get('status') == 200
                        for msg in msgs)):
                raise generate_and_send_digests.retry(exc=e)
            else:
                # raise right away, since we don't support partial retry
                raise
示例#4
0
def generate_and_send_digests(users, from_dt, to_dt):
    """
    This task generates and sends forum digest emails to multiple users in a
    single background operation.

    `users` is an iterable of dictionaries, as returned by the edx user_api
    (required keys are "id", "name", "email", "preferences", and "course_info").

    `from_dt` and `to_dt` are datetime objects representing the start and end
    of the time window for which to generate a digest.
    """
    logger.info("DIGEST TASK UPLOAD")
    users_by_id = dict((str(u['id']), u) for u in users)
    msgs = []
    try:
        with closing(get_connection()) as cx:
            for user_id, digest in generate_digest_content(
                    users_by_id, from_dt, to_dt):
                user = users_by_id[user_id]
                # format the digest
                text, html = render_digest(
                    user, digest, settings.FORUM_DIGEST_EMAIL_TITLE,
                    settings.FORUM_DIGEST_EMAIL_DESCRIPTION)
                # send the message through our mailer
                msg = EmailMultiAlternatives(
                    settings.FORUM_DIGEST_EMAIL_SUBJECT, text,
                    settings.FORUM_DIGEST_EMAIL_SENDER, [user['email']])
                msg.attach_alternative(html, "text/html")
                msgs.append(msg)
            if msgs:
                cx.send_messages(msgs)
            if settings.DEAD_MANS_SNITCH_URL:
                requests.post(settings.DEAD_MANS_SNITCH_URL)
    except (CommentsServiceException, SESMaxSendingRateExceededError) as e:
        # only retry if no messages were successfully sent yet.
        if not any((getattr(msg, 'extra_headers', {}).get('status') == 200
                    for msg in msgs)):

            raise generate_and_send_digests.retry(exc=e)
        else:
            # raise right away, since we don't support partial retry
            raise
示例#5
0
 def _test_unicode_data(self, input_text, expected_text, expected_html=None):
     user = {
         "id": "0",
         "username": "******",
     }
     digest = Digest([
         DigestCourse(
             TEST_COURSE_ID,
             [DigestThread(
                 "0",
                 TEST_COURSE_ID,
                 TEST_COMMENTABLE,
                 input_text,
                 [DigestItem("test content", None, None)]
             )]
         )
     ])
     (rendered_text, rendered_html) = render_digest(user, digest, "Test Title", "Test Description")
     self.assertIn(expected_text, rendered_text)
     self.assertIn(expected_html if expected_html else expected_text, rendered_html)
示例#6
0
    def show_rendered(self, fmt, users, from_dt, to_dt):
        users_by_id = dict((str(u['id']), u) for u in users)

        def _fail(msg):
            logger.warning('could not show rendered %s: %s', fmt, msg)

        try:
            user_id, digest = generate_digest_content(users_by_id, from_dt,
                                                      to_dt).next()
        except StopIteration:
            _fail('no digests found')
            return

        text, html = render_digest(users_by_id[user_id], digest,
                                   settings.FORUM_DIGEST_EMAIL_TITLE,
                                   settings.FORUM_DIGEST_EMAIL_DESCRIPTION)
        if fmt == 'text':
            print >> self.stdout, text
        elif fmt == 'html':
            print >> self.stdout, html
示例#7
0
 def _test_unicode_data(self,
                        input_text,
                        expected_text,
                        expected_html=None):
     user = {
         "id": "0",
         "username": "******",
     }
     digest = Digest([
         DigestCourse(TEST_COURSE_ID, [
             DigestThread("0", TEST_COURSE_ID, TEST_COMMENTABLE, input_text,
                          [DigestItem("test content", None, None)])
         ])
     ])
     (rendered_text, rendered_html) = render_digest(user, digest,
                                                    "Test Title",
                                                    "Test Description")
     self.assertIn(expected_text, rendered_text)
     self.assertIn(expected_html if expected_html else expected_text,
                   rendered_html)
示例#8
0
def generate_and_send_digests(users, from_dt, to_dt, language=None):
    """
    This task generates and sends forum digest emails to multiple users in a
    single background operation.

    `users` is an iterable of dictionaries, as returned by the edx user_api
    (required keys are "id", "name", "email", "preferences", and "course_info").

    `from_dt` and `to_dt` are datetime objects representing the start and end
    of the time window for which to generate a digest.
    """
    settings.LANGUAGE_CODE = language or settings.LANGUAGE_CODE or DEFAULT_LANGUAGE
    users_by_id = dict((str(u['id']), u) for u in users)
    msgs = []
    try:
        with closing(get_connection()) as cx:
            for user_id, digest in generate_digest_content(users_by_id, from_dt, to_dt):
                user = users_by_id[user_id]
                # format the digest
                text, html = render_digest(
                    user, digest, settings.FORUM_DIGEST_EMAIL_TITLE, settings.FORUM_DIGEST_EMAIL_DESCRIPTION)
                # send the message through our mailer
                msg = EmailMultiAlternatives(
                    settings.FORUM_DIGEST_EMAIL_SUBJECT,
                    text,
                    settings.FORUM_DIGEST_EMAIL_SENDER,
                    [user['email']]
                )
                msg.attach_alternative(html, "text/html")
                msgs.append(msg)
            if msgs:
                cx.send_messages(msgs)
            if settings.DEAD_MANS_SNITCH_URL:
                requests.post(settings.DEAD_MANS_SNITCH_URL)
    except (CommentsServiceException, SESMaxSendingRateExceededError) as e:
        # only retry if no messages were successfully sent yet.
        if not any((getattr(msg, 'extra_headers', {}).get('status') == 200 for msg in msgs)):
            raise generate_and_send_digests.retry(exc=e)
        else:
            # raise right away, since we don't support partial retry
            raise
示例#9
0
    def show_rendered(self, fmt, users, from_dt, to_dt):
        users_by_id = dict((str(u['id']), u) for u in users)

        def _fail(msg):
            logger.warning('could not show rendered %s: %s', fmt, msg)

        try:
            user_id, digest = next(generate_digest_content(users_by_id, from_dt, to_dt))
        except StopIteration:
            _fail('no digests found')
            return

        text, html = render_digest(
            users_by_id[user_id],
            digest,
            settings.FORUM_DIGEST_EMAIL_TITLE,
            settings.FORUM_DIGEST_EMAIL_DESCRIPTION
        )
        if fmt == 'text':
            print >> self.stdout, text
        elif fmt == 'html':
            print >> self.stdout, html
示例#10
0
 def _test_unicode_data(self, input_text, expected_text, expected_html=None):
     self.set_digest(input_text)
     (rendered_text, rendered_html) = render_digest(self.user, self.digest, "Test Title", "Test Description")
     self.assertIn(expected_text, rendered_text)
     self.assertIn(expected_html if expected_html else expected_text, rendered_html)
示例#11
0
 def test_user_lang_pref_absent(self, mock_activate):
     if LANGUAGE_PREFERENCE_KEY in self.user["preferences"]:
         del self.user["preferences"][LANGUAGE_PREFERENCE_KEY]
     render_digest(self.user, self.digest, "dummy", "dummy")
     mock_activate.assert_not_called()
示例#12
0
 def test_user_lang_pref_unsupported(self, mock_activate):
     user_lang = "x-unsupported-lang"
     self.user["preferences"][LANGUAGE_PREFERENCE_KEY] = user_lang
     render_digest(self.user, self.digest, "dummy", "dummy")
     mock_activate.assert_not_called()
示例#13
0
 def test_user_lang_pref_supported(self, mock_activate, mock_deactivate):
     user_lang = "fr"
     self.user["preferences"][LANGUAGE_PREFERENCE_KEY] = user_lang
     render_digest(self.user, self.digest, "dummy", "dummy")
     mock_activate.assert_called_with(user_lang)
     mock_deactivate.assert_called()
示例#14
0
class Command(BaseCommand):

    """
    """

    option_list = BaseCommand.option_list + (
        make_option('--to_datetime',
                    action='store',
                    dest='to_datetime',
                    default=None,
                    help='datetime as of which to generate digest content, in ISO-8601 format (UTC).  Defaults to today at midnight (UTC).'),
        make_option('--minutes',
                    action='store',
                    dest='minutes',
                    type='int',
                    default=1440,
                    help='number of minutes up to TO_DATETIME for which to generate digest content.  Defaults to 1440 (one day).'),
        make_option('--users',
                    action='store',
                    dest='users_str',
                    default=None,
                    help='send digests for the specified users only (regardless of opt-out settings!)'),
        make_option('--show-content',
                    action='store_true',
                    dest='show_content',
                    default=None,
                    help='output the retrieved content only (don\'t send anything)'),
        make_option('--show-users',
                    action='store_true',
                    dest='show_users',
                    default=None,
                    help='output the retrieved users only (don\'t fetch content or send anything)'),
        make_option('--show-text',
                    action='store_true',
                    dest='show_text',
                    default=None,
                    help='output the rendered text body of the first user-digest generated, and exit (don\'t send anything)'),
        make_option('--show-html',
                    action='store_true',
                    dest='show_html',
                    default=None,
                    help='output the rendered html body of the first user-digest generated, and exit (don\'t send anything)'),
    )

    def get_specific_users(self, user_ids):
        # this makes an individual HTTP request for each user -
        # it is only intended for use with small numbers of users
        # (e.g. for diagnostic purposes).
        users = []
        for user_id in user_ids:
            user = get_user(user_id)
            if user:
                users.append(user)
        return users

    def show_users(self, users):
        json.dump(list(users), self.stdout)

    def show_content(self, users, from_dt, to_dt):
        all_content = generate_digest_content(
            (u['id'] for u in users), from_dt, to_dt)
        # use django's encoder; builtin one doesn't handle datetime objects
        json.dump(list(all_content), self.stdout, cls=DigestJSONEncoder)

    def show_rendered(self, fmt, users, from_dt, to_dt):

        def _fail(msg):
            logger.warning('could not show rendered %s: %s', fmt, msg)

        try:
            user = list(users)[0]
        except IndexError, e:
            _fail('no users found')
            return

        try:
            user_id, digest = generate_digest_content(
                [user['id']], from_dt, to_dt).next()
        except StopIteration:
            _fail('no digests found')
            return

        text, html = render_digest(
            user, digest, settings.FORUM_DIGEST_EMAIL_TITLE, settings.FORUM_DIGEST_EMAIL_DESCRIPTION)
        if fmt == 'text':
            print >> self.stdout, text
        elif fmt == 'html':
            print >> self.stdout, html