Example #1
0
    def _validate_expectation_of_json_for_html(self, test_dict,
                                               expected_json_for_html_string):
        """
        Proves that the expectation string is a reasonable one, since it is
        not very human readable with all of the escaping.

        Ensures that after unescaping (html) the string can be parsed to a
        (nearly) equivalent dict.

        Assertions will fail if the expectation is invalid.

        Arguments:
            test_dict: The original dict to be tested in the Mako template.
            expected_json_for_html_string: An html escaped json string that
                should be parseable into a near equivalent to test_dict.

        """
        html_parser = six.moves.html_parser.HTMLParser()

        expected_json = html_parser.unescape(expected_json_for_html_string)
        parsed_expected_dict = json.loads(expected_json)
        # tuples become arrays in json, so it is parsed to a list that is
        # switched back to a tuple before comparing
        parsed_expected_dict['test_tuple'] = tuple(
            parsed_expected_dict['test_tuple'])
        self.assertEqual(test_dict['test_string'],
                         parsed_expected_dict['test_string'])
        self.assertEqual(test_dict['test_tuple'],
                         parsed_expected_dict['test_tuple'])
        self.assertEqual(test_dict['test_number'],
                         parsed_expected_dict['test_number'])
        self.assertEqual(test_dict['test_bool'],
                         parsed_expected_dict['test_bool'])
Example #2
0
    def _validate_expectation_of_json_for_html(self, test_dict, expected_json_for_html_string):
        """
        Proves that the expectation string is a reasonable one, since it is
        not very human readable with all of the escaping.

        Ensures that after unescaping (html) the string can be parsed to a
        (nearly) equivalent dict.

        Assertions will fail if the expectation is invalid.

        Arguments:
            test_dict: The original dict to be tested in the Mako template.
            expected_json_for_html_string: An html escaped json string that
                should be parseable into a near equivalent to test_dict.

        """
        html_parser = six.moves.html_parser.HTMLParser()

        expected_json = html_parser.unescape(expected_json_for_html_string)
        parsed_expected_dict = json.loads(expected_json)
        # tuples become arrays in json, so it is parsed to a list that is
        # switched back to a tuple before comparing
        parsed_expected_dict['test_tuple'] = tuple(parsed_expected_dict['test_tuple'])
        self.assertEqual(test_dict['test_string'].decode(encoding='utf-8'), parsed_expected_dict['test_string'])
        self.assertEqual(test_dict['test_tuple'], parsed_expected_dict['test_tuple'])
        self.assertEqual(test_dict['test_number'], parsed_expected_dict['test_number'])
        self.assertEqual(test_dict['test_bool'], parsed_expected_dict['test_bool'])
Example #3
0
def run_checks(entity, original, string):
    """
    Group all checks related to the base UI that get stored in the DB
    :arg pontoon.base.models.Entity entity: Source entity
    :arg basestring original: an original string
    :arg basestring string: a translation
    """
    checks = defaultdict(list)
    resource_ext = entity.resource.format

    if resource_ext == "lang":
        # Newlines are not allowed in .lang files (bug 1190754)
        if "\n" in string:
            checks["pErrors"].append("Newline characters are not allowed")

        # Prevent translations exceeding the given length limit
        max_length = get_max_length(entity.comment)

        if max_length:
            string_length = len(
                html_parser.unescape(bleach.clean(string, strip=True,
                                                  tags=())))

            if string_length > max_length:
                checks["pErrors"].append("Translation too long")

    # Bug 1599056: Original and translation must either both end in a newline,
    # or none of them should.
    if resource_ext == "po":
        if original.endswith("\n") != string.endswith("\n"):
            checks["pErrors"].append("Ending newline mismatch")

    # Prevent empty translation submissions if not supported
    if string == "" and not entity.resource.allows_empty_translations:
        checks["pErrors"].append("Empty translations are not allowed")

    # FTL checks
    if resource_ext == "ftl" and string != "":
        translation_ast = parser.parse_entry(string)
        entity_ast = parser.parse_entry(entity.string)

        # Parse error
        if isinstance(translation_ast, ast.Junk):
            checks["pErrors"].append(translation_ast.annotations[0].message)

        # Not a localizable entry
        elif not isinstance(translation_ast, localizable_entries):
            checks["pErrors"].append(
                "Translation needs to be a valid localizable entry")

        # Message ID mismatch
        elif entity_ast.id.name != translation_ast.id.name:
            checks["pErrors"].append(
                "Translation key needs to match source string key")

    return checks
Example #4
0
def cleanup(text):
    if text is not None and text:
        text = unescape(text)
        text = re.sub("<[\s\S]*?>", "", text)
        text = re.sub("\t", " ", text)
        text = re.sub("\s*$", "", text)
        text = re.sub("^\s*", "", text)
        text = re.sub(" {2,}", " ", text)
        text = re.sub("\n{2,}", "\n", text)
    return text
 def get_email_subject(self):
     """
     WARNING: It is MANDATORY to override method if you are going to
     send email using the  `send_notification_email` method.
     Your class must define an `email_subject_tmpl` attribute
     containing a template path to a file that has your email subject.
     """
     # Convert the html back to plaintext after rendering it using template
     # to get rid of html ampersand character codes
     html_email = self._get_email_field('email_subject_tmpl',
                                        'get_email_subject')
     return html_parser.unescape(html_email)
Example #6
0
def run_checks(entity, string):
    """
    Group all checks related to the base UI that get stored in the DB
    :arg pontoon.base.models.Entity entity: Source entity
    :arg basestring string: a translation
    """
    checks = defaultdict(list)
    resource_ext = entity.resource.format

    if resource_ext == 'lang':
        # Newlines are not allowed in .lang files (bug 1190754)
        if '\n' in string:
            checks['pErrors'].append('Newline characters are not allowed')

        # Prevent translations exceeding the given length limit
        max_length = get_max_length(entity.comment)

        if max_length:
            string_length = len(
                html_parser.unescape(bleach.clean(string, strip=True,
                                                  tags=())))

            if string_length > max_length:
                checks['pErrors'].append('Translation too long')

    # Prevent empty translation submissions if not supported
    if string == '' and not entity.resource.allows_empty_translations:
        checks['pErrors'].append('Empty translations are not allowed')

    # FTL checks
    if resource_ext == 'ftl' and string != '':
        translation_ast = parser.parse_entry(string)
        entity_ast = parser.parse_entry(entity.string)

        # Parse error
        if isinstance(translation_ast, ast.Junk):
            checks['pErrors'].append(translation_ast.annotations[0].message)

        # Not a localizable entry
        elif not isinstance(translation_ast, localizable_entries):
            checks['pErrors'].append(
                'Translation needs to be a valid localizable entry')

        # Message ID mismatch
        elif entity_ast.id.name != translation_ast.id.name:
            checks['pErrors'].append(
                'Translation key needs to match source string key')

    return checks
Example #7
0
    def replacer(match):
        try:
            lang = match.group('lang')
            lang = _LANG_ALIASES.get(lang, lang)
            lexer = pygments.lexers.get_lexer_by_name(lang)
        except ValueError:
            lexer = pygments.lexers.TextLexer()

        code = match.group('code')

        # Decode html entities in the code. cmark tries to be helpful and
        # translate '"' to '&quot;', but it confuses pygments. Pygments will
        # escape any html entities when re-writing the code, and we run
        # everything through bleach after.
        code = unescape(code)

        highlighted = pygments.highlight(code, lexer, formatter)

        return '<pre>{}</pre>'.format(highlighted)
Example #8
0
def send_credit_notifications(username, course_key):
    """Sends email notification to user on different phases during credit
    course e.g., credit eligibility, credit payment etc.
    """
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        log.error(u'No user with %s exist', username)
        return

    course = modulestore().get_course(course_key, depth=0)
    course_display_name = course.display_name
    tracking_context = tracker.get_tracker().resolve_context()
    tracking_id = str(tracking_context.get('user_id'))
    client_id = str(tracking_context.get('client_id'))
    events = '&t=event&ec=email&ea=open'
    tracking_pixel = 'https://www.google-analytics.com/collect?v=1&tid' + tracking_id + '&cid' + client_id + events
    dashboard_link = _email_url_parser('dashboard')
    credit_course_link = _email_url_parser('courses', '?type=credit')

    # get attached branded logo
    logo_image = cache.get('credit.email.attached-logo')
    if logo_image is None:
        branded_logo = {
            'title': 'Logo',
            'path': settings.NOTIFICATION_EMAIL_EDX_LOGO,
            'cid': str(uuid.uuid4())
        }
        logo_image_id = branded_logo['cid']
        logo_image = attach_image(branded_logo, 'Header Logo')
        if logo_image:
            cache.set('credit.email.attached-logo', logo_image,
                      settings.CREDIT_NOTIFICATION_CACHE_TIMEOUT)
    else:
        # strip enclosing angle brackets from 'logo_image' cache 'Content-ID'
        logo_image_id = logo_image.get('Content-ID', '')[1:-1]

    providers_names = get_credit_provider_attribute_values(
        course_key, 'display_name')
    providers_string = make_providers_strings(providers_names)
    context = {
        'full_name':
        user.get_full_name(),
        'platform_name':
        configuration_helpers.get_value('PLATFORM_NAME',
                                        settings.PLATFORM_NAME),
        'course_name':
        course_display_name,
        'branded_logo':
        logo_image_id,
        'dashboard_link':
        dashboard_link,
        'credit_course_link':
        credit_course_link,
        'tracking_pixel':
        tracking_pixel,
        'providers':
        providers_string,
    }

    # create the root email message
    notification_msg = MIMEMultipart('related')
    # add 'alternative' part to root email message to encapsulate the plain and
    # HTML versions, so message agents can decide which they want to display.
    msg_alternative = MIMEMultipart('alternative')
    notification_msg.attach(msg_alternative)
    # render the credit notification templates
    subject = _(u'Course Credit Eligibility')

    if providers_string:
        subject = _(u'You are eligible for credit from {providers_string}'
                    ).format(providers_string=providers_string)

    # add alternative plain text message
    email_body_plain = render_to_string(
        'credit_notifications/credit_eligibility_email.txt', context)
    msg_alternative.attach(
        SafeMIMEText(email_body_plain, _subtype='plain', _charset='utf-8'))

    # add alternative html message
    email_body_content = cache.get('credit.email.css-email-body')
    if email_body_content is None:
        html_file_path = file_path_finder(
            'templates/credit_notifications/credit_eligibility_email.html')
        if html_file_path:
            with open(html_file_path, 'r') as cur_file:
                cur_text = cur_file.read()
                # use html parser to unescape html characters which are changed
                # by the 'pynliner' while adding inline css to html content
                html_parser = six.moves.html_parser.HTMLParser()
                email_body_content = html_parser.unescape(
                    with_inline_css(cur_text))
                # cache the email body content before rendering it since the
                # email context will change for each user e.g., 'full_name'
                cache.set('credit.email.css-email-body', email_body_content,
                          settings.CREDIT_NOTIFICATION_CACHE_TIMEOUT)
        else:
            email_body_content = ''

    email_body = Template(email_body_content).render(context)
    msg_alternative.attach(
        SafeMIMEText(email_body, _subtype='html', _charset='utf-8'))

    # attach logo image
    if logo_image:
        notification_msg.attach(logo_image)

    # add email addresses of sender and receiver
    from_address = configuration_helpers.get_value('email_from_address',
                                                   settings.DEFAULT_FROM_EMAIL)
    to_address = user.email

    # send the root email message
    msg = EmailMessage(subject, '', from_address, [to_address])
    msg.attach(notification_msg)
    msg.send()
Example #9
0
def run_checks(entity, string):
    """
    Group all checks related to the base UI that get stored in the DB
    :arg pontoon.base.models.Entity entity: Source entity
    :arg basestring string: a translation
    """
    checks = defaultdict(list)
    resource_ext = entity.resource.format

    if resource_ext == 'lang':
        # Newlines are not allowed in .lang files (bug 1190754)
        if '\n' in string:
            checks['pErrors'].append(
                'Newline characters are not allowed'
            )

        # Prevent translations exceeding the given length limit
        max_length = get_max_length(entity.comment)

        if max_length:
            string_length = len(
                html_parser.unescape(
                    bleach.clean(
                        string,
                        strip=True,
                        tags=()
                    )
                )
            )

            if string_length > max_length:
                checks['pErrors'].append(
                    'Translation too long'
                )

    # Prevent empty translation submissions if not supported
    if string == '' and not entity.resource.allows_empty_translations:
        checks['pErrors'].append(
            'Empty translations are not allowed'
        )

    # FTL checks
    if resource_ext == 'ftl' and string != '':
        translation_ast = parser.parse_entry(string)
        entity_ast = parser.parse_entry(entity.string)

        # Parse error
        if isinstance(translation_ast, ast.Junk):
            checks['pErrors'].append(
                translation_ast.annotations[0].message
            )

        # Not a localizable entry
        elif not isinstance(translation_ast, localizable_entries):
            checks['pErrors'].append(
                'Translation needs to be a valid localizable entry'
            )

        # Message ID mismatch
        elif entity_ast.id.name != translation_ast.id.name:
            checks['pErrors'].append(
                'Translation key needs to match source string key'
            )

    return checks
Example #10
0
 def title(self):
     return html_parser.unescape(self.data['title']).decode('utf8')
Example #11
0
 def author(self):
     return html_parser.unescape(self.data['author']).decode('utf8')
Example #12
0
def send_credit_notifications(username, course_key):
    """Sends email notification to user on different phases during credit
    course e.g., credit eligibility, credit payment etc.
    """
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        log.error(u'No user with %s exist', username)
        return

    course = modulestore().get_course(course_key, depth=0)
    course_display_name = course.display_name
    tracking_context = tracker.get_tracker().resolve_context()
    tracking_id = str(tracking_context.get('user_id'))
    client_id = str(tracking_context.get('client_id'))
    events = '&t=event&ec=email&ea=open'
    tracking_pixel = 'https://www.google-analytics.com/collect?v=1&tid' + tracking_id + '&cid' + client_id + events
    dashboard_link = _email_url_parser('dashboard')
    credit_course_link = _email_url_parser('courses', '?type=credit')

    # get attached branded logo
    logo_image = cache.get('credit.email.attached-logo')
    if logo_image is None:
        branded_logo = {
            'title': 'Logo',
            'path': settings.NOTIFICATION_EMAIL_EDX_LOGO,
            'cid': str(uuid.uuid4())
        }
        logo_image_id = branded_logo['cid']
        logo_image = attach_image(branded_logo, 'Header Logo')
        if logo_image:
            cache.set('credit.email.attached-logo', logo_image, settings.CREDIT_NOTIFICATION_CACHE_TIMEOUT)
    else:
        # strip enclosing angle brackets from 'logo_image' cache 'Content-ID'
        logo_image_id = logo_image.get('Content-ID', '')[1:-1]

    providers_names = get_credit_provider_attribute_values(course_key, 'display_name')
    providers_string = make_providers_strings(providers_names)
    context = {
        'full_name': user.get_full_name(),
        'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
        'course_name': course_display_name,
        'branded_logo': logo_image_id,
        'dashboard_link': dashboard_link,
        'credit_course_link': credit_course_link,
        'tracking_pixel': tracking_pixel,
        'providers': providers_string,
    }

    # create the root email message
    notification_msg = MIMEMultipart('related')
    # add 'alternative' part to root email message to encapsulate the plain and
    # HTML versions, so message agents can decide which they want to display.
    msg_alternative = MIMEMultipart('alternative')
    notification_msg.attach(msg_alternative)
    # render the credit notification templates
    subject = _(u'Course Credit Eligibility')

    if providers_string:
        subject = _(u'You are eligible for credit from {providers_string}').format(
            providers_string=providers_string
        )

    # add alternative plain text message
    email_body_plain = render_to_string('credit_notifications/credit_eligibility_email.txt', context)
    msg_alternative.attach(SafeMIMEText(email_body_plain, _subtype='plain', _charset='utf-8'))

    # add alternative html message
    email_body_content = cache.get('credit.email.css-email-body')
    if email_body_content is None:
        html_file_path = file_path_finder('templates/credit_notifications/credit_eligibility_email.html')
        if html_file_path:
            with open(html_file_path, 'r') as cur_file:
                cur_text = cur_file.read()
                # use html parser to unescape html characters which are changed
                # by the 'pynliner' while adding inline css to html content
                html_parser = six.moves.html_parser.HTMLParser()
                email_body_content = html_parser.unescape(with_inline_css(cur_text))
                # cache the email body content before rendering it since the
                # email context will change for each user e.g., 'full_name'
                cache.set('credit.email.css-email-body', email_body_content, settings.CREDIT_NOTIFICATION_CACHE_TIMEOUT)
        else:
            email_body_content = ''

    email_body = Template(email_body_content).render(context)
    msg_alternative.attach(SafeMIMEText(email_body, _subtype='html', _charset='utf-8'))

    # attach logo image
    if logo_image:
        notification_msg.attach(logo_image)

    # add email addresses of sender and receiver
    from_address = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)
    to_address = user.email

    # send the root email message
    msg = EmailMessage(subject, '', from_address, [to_address])
    msg.attach(notification_msg)
    msg.send()
 def title(self):
     return html_parser.unescape(self.data['title']).decode('utf8')
 def author(self):
     return html_parser.unescape(self.data['author']).decode('utf8')