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'])
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'])
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
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)
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
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 '"', 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)
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 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
def title(self): return html_parser.unescape(self.data['title']).decode('utf8')
def author(self): return html_parser.unescape(self.data['author']).decode('utf8')
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()