Example #1
0
    def _renderSharing(self, template, packaging, productseries, upstream,
                       other_template, sourcepackagename):
        """Render a link to `template`.

        :param template: The target `POTemplate`.
        :return: HTML for the "sharing" status of `template`.
        """
        # Testing is easier if we are willing to extract the sourcepackagename
        # from the template.
        if sourcepackagename is None:
            sourcepackagename = template.sourcepackagename
        # Build the edit link.
        escaped_source = html_escape(sourcepackagename.name)
        source_url = '+source/%s' % escaped_source
        details_url = source_url + '/+sharing-details'
        edit_link = ('<a class="sprite edit action-icon" href="%s">Edit</a>' %
                     details_url)

        # If all the conditions are met for sharing...
        if packaging and upstream and other_template is not None:
            escaped_series = html_escape(productseries.name)
            escaped_template = html_escape(template.name)
            pot_url = ('/%s/%s/+pots/%s' %
                       (escaped_source, escaped_series, escaped_template))
            return (edit_link + '<a href="%s">%s/%s</a>' %
                    (pot_url, escaped_source, escaped_series))
        else:
            # Otherwise just say that the template isn't shared and give them
            # a link to change the sharing.
            return edit_link + 'not shared'
Example #2
0
    def _renderSharing(self, template, packaging, productseries, upstream,
            other_template, sourcepackagename):
        """Render a link to `template`.

        :param template: The target `POTemplate`.
        :return: HTML for the "sharing" status of `template`.
        """
        # Testing is easier if we are willing to extract the sourcepackagename
        # from the template.
        if sourcepackagename is None:
            sourcepackagename = template.sourcepackagename
        # Build the edit link.
        escaped_source = html_escape(sourcepackagename.name)
        source_url = '+source/%s' % escaped_source
        details_url = source_url + '/+sharing-details'
        edit_link = (
            '<a class="sprite edit action-icon" href="%s">Edit</a>' %
            details_url)

        # If all the conditions are met for sharing...
        if packaging and upstream and other_template is not None:
            escaped_series = html_escape(productseries.name)
            escaped_template = html_escape(template.name)
            pot_url = ('/%s/%s/+pots/%s' %
                (escaped_source, escaped_series, escaped_template))
            return (edit_link + '<a href="%s">%s/%s</a>'
                % (pot_url, escaped_source, escaped_series))
        else:
            # Otherwise just say that the template isn't shared and give them
            # a link to change the sharing.
            return edit_link + 'not shared'
    def toTerm(self, watch):
        if watch.url.startswith('mailto:'):
            user = getUtility(ILaunchBag).user
            if user is None:
                title = html_escape(
                    FormattersAPI(watch.bugtracker.title).obfuscate_email())
            else:
                url = watch.url
                if url in watch.bugtracker.title:
                    title = html_escape(watch.bugtracker.title).replace(
                        html_escape(url),
                        structured(
                            '<a href="%s">%s</a>', url, url).escapedtext)
                else:
                    title = structured(
                        '%s &lt;<a href="%s">%s</a>&gt;',
                        watch.bugtracker.title, url, url[7:]).escapedtext
        else:
            title = structured(
                '%s <a href="%s">#%s</a>',
                watch.bugtracker.title, watch.url,
                watch.remotebug).escapedtext

        # title is already HTML-escaped.
        return SimpleTerm(watch, watch.id, title)
    def _validate(self, value):
        # import here to avoid circular import
        from lp.services.webapp import canonical_url
        from lazr.uri import URI

        super(DistroMirrorURIField, self)._validate(value)
        uri = URI(self.normalize(value))

        # This field is also used when creating new mirrors and in that case
        # self.context is not an IDistributionMirror so it doesn't make sense
        # to try to get the existing value of the attribute.
        if IDistributionMirror.providedBy(self.context):
            orig_value = self.get(self.context)
            if orig_value is not None and URI(orig_value) == uri:
                return  # url was not changed

        mirror = self.getMirrorByURI(str(uri))
        if mirror is not None:
            message = _(
                'The distribution mirror <a href="${url}">${mirror}</a> '
                'is already registered with this URL.',
                mapping={
                    'url': html_escape(canonical_url(mirror)),
                    'mirror': html_escape(mirror.title)
                })
            raise LaunchpadValidationError(structured(message))
Example #5
0
 def test_composeNameAndChangesLink_escapes_nonlinked_display_name(self):
     filename = 'name"&name'
     upload = self.factory.makeCustomPackageUpload(filename=filename)
     # Stop nameAndChangesLink from producing a link.
     upload.changesfile = None
     complete_upload = self.makeCompletePackageUpload(upload)
     self.assertIn(
         html_escape(filename),
         html_escape(complete_upload.composeNameAndChangesLink()))
Example #6
0
def _check_email_availability(email):
    email_address = getUtility(IEmailAddressSet).getByEmail(email)
    if email_address is not None:
        person = email_address.person
        message = _('${email} is already registered in Launchpad and is '
                    'associated with <a href="${url}">${person}</a>.',
                    mapping={'email': html_escape(email),
                            'url': html_escape(canonical_url(person)),
                            'person': html_escape(person.displayname)})
        raise LaunchpadValidationError(structured(message))
 def _renderItem(self, index, text, value, name, cssClass, checked=False):
     """Render a checkbox and text without without label."""
     kw = {}
     if checked:
         kw['checked'] = 'checked'
     value = html_escape(value)
     text = html_escape(text)
     id = '%s.%s' % (name, index)
     element = renderElement(
         u'input', value=value, name=name, id=id,
         cssClass=cssClass, type='checkbox', **kw)
     return self._joinButtonToMessageTemplate % (element, text)
    def test_attachments(self):
        # The attachment comment has no content and it does not notify.
        token = self.process_extra_data("""\
            MIME-Version: 1.0
            Content-type: multipart/mixed; boundary=boundary

            --boundary
            Content-disposition: attachment; filename='attachment1'
            Content-type: text/plain; charset=utf-8

            This is an attachment.

            --boundary
            Content-disposition: attachment; filename='attachment2'
            Content-description: Attachment description.
            Content-type: text/plain; charset=ISO-8859-1

            This is another attachment, with a description.

            --boundary--
            """)
        view = self.create_initialized_view()
        view.publishTraverse(view.request, token)
        with EventRecorder() as recorder:
            view.submit_bug_action.success(self.get_form())
            # Subscribers are only notified about the new bug event;
            # The extra comment for the attchments was silent.
            self.assertEqual(1, len(recorder.events))
            self.assertEqual(view.added_bug, recorder.events[0].object)
        transaction.commit()
        bug = view.added_bug
        attachments = [at for at in bug.attachments_unpopulated]
        self.assertEqual(2, len(attachments))
        attachment = attachments[0]
        self.assertEqual('attachment1', attachment.title)
        self.assertEqual('attachment1', attachment.libraryfile.filename)
        self.assertEqual('text/plain; charset=utf-8',
                         attachment.libraryfile.mimetype)
        self.assertEqual('This is an attachment.\n\n',
                         attachment.libraryfile.read())
        self.assertEqual(2, bug.messages.count())
        self.assertEqual(2, len(bug.messages[1].bugattachments))
        notifications = [
            no.message for no in view.request.response.notifications
        ]
        self.assertContentEqual([
            '<p class="last">Thank you for your bug report.</p>',
            html_escape(
                'The file "attachment1" was attached to the bug report.'),
            html_escape(
                'The file "attachment2" was attached to the bug report.')
        ], notifications)
Example #9
0
def _check_email_availability(email):
    email_address = getUtility(IEmailAddressSet).getByEmail(email)
    if email_address is not None:
        person = email_address.person
        message = _(
            '${email} is already registered in Launchpad and is '
            'associated with <a href="${url}">${person}</a>.',
            mapping={
                'email': html_escape(email),
                'url': html_escape(canonical_url(person)),
                'person': html_escape(person.displayname)
            })
        raise LaunchpadValidationError(structured(message))
    def test_attachments(self):
        # The attachment comment has no content and it does not notify.
        token = self.process_extra_data("""\
            MIME-Version: 1.0
            Content-type: multipart/mixed; boundary=boundary

            --boundary
            Content-disposition: attachment; filename='attachment1'
            Content-type: text/plain; charset=utf-8

            This is an attachment.

            --boundary
            Content-disposition: attachment; filename='attachment2'
            Content-description: Attachment description.
            Content-type: text/plain; charset=ISO-8859-1

            This is another attachment, with a description.

            --boundary--
            """)
        view = self.create_initialized_view()
        view.publishTraverse(view.request, token)
        with EventRecorder() as recorder:
            view.submit_bug_action.success(self.get_form())
            # Subscribers are only notified about the new bug event;
            # The extra comment for the attchments was silent.
            self.assertEqual(1, len(recorder.events))
            self.assertEqual(view.added_bug, recorder.events[0].object)
        transaction.commit()
        bug = view.added_bug
        attachments = [at for at in bug.attachments_unpopulated]
        self.assertEqual(2, len(attachments))
        attachment = attachments[0]
        self.assertEqual('attachment1', attachment.title)
        self.assertEqual('attachment1', attachment.libraryfile.filename)
        self.assertEqual(
            'text/plain; charset=utf-8', attachment.libraryfile.mimetype)
        self.assertEqual(
            'This is an attachment.\n\n', attachment.libraryfile.read())
        self.assertEqual(2, bug.messages.count())
        self.assertEqual(2, len(bug.messages[1].bugattachments))
        notifications = [
            no.message for no in view.request.response.notifications]
        self.assertContentEqual(
            ['<p class="last">Thank you for your bug report.</p>',
             html_escape(
                 'The file "attachment1" was attached to the bug report.'),
             html_escape(
                 'The file "attachment2" was attached to the bug report.')],
            notifications)
Example #11
0
def text_to_html(text,
                 flags,
                 space=TranslationConstants.SPACE_CHAR,
                 newline=TranslationConstants.NEWLINE_CHAR):
    """Convert a unicode text to a HTML representation."""
    if text is None:
        return None

    markup_lines = []
    # Replace leading and trailing spaces on each line with special markup.
    if u'\r\n' in text:
        newline_chars = u'\r\n'
    elif u'\r' in text:
        newline_chars = u'\r'
    else:
        newline_chars = u'\n'
    for line in text.split(newline_chars):
        # Pattern:
        # - group 1: zero or more spaces: leading whitespace
        # - group 2: zero or more groups of (zero or
        #   more spaces followed by one or more non-spaces): maximal string
        #   which doesn't begin or end with whitespace
        # - group 3: zero or more spaces: trailing whitespace
        match = re.match(u'^( *)((?: *[^ ]+)*)( *)$', line)

        if match:
            format_segments = None
            if 'c-format' in flags:
                try:
                    format_segments = parse_cformat_string(match.group(2))
                except UnrecognisedCFormatString:
                    pass
            if format_segments is not None:
                markup = ''
                for segment in format_segments:
                    type, content = segment

                    if type == 'interpolation':
                        markup += (u'<code>%s</code>' % html_escape(content))
                    elif type == 'string':
                        markup += html_escape(content)
            else:
                markup = html_escape(match.group(2))
            markup_lines.append(space * len(match.group(1)) + markup +
                                space * len(match.group(3)))
        else:
            raise AssertionError(
                "A regular expression that should always match didn't.")

    return expand_rosetta_escapes(newline.join(markup_lines))
Example #12
0
 def _renderSuggestionLabel(self, branch, index):
     """Render a label for the option based on a branch."""
     # To aid usability there needs to be some text connected with the
     # radio buttons that is not a hyperlink in order to select the radio
     # button.  It was decided not to have the entire text as a link, but
     # instead to have a separate link to the branch details.
     text = '%s (<a href="%s">branch details</a>)' % (html_escape(
         branch.displayname), html_escape(canonical_url(branch)))
     # If the branch is the development focus, say so.
     if branch == self.context.context.target.default_merge_target:
         text = text + "&ndash; <em>development focus</em>"
     label = u'<label for="%s" style="font-weight: normal">%s</label>' % (
         self._optionId(index), text)
     return structured(label)
Example #13
0
 def _renderSuggestionLabel(self, branch, index):
     """Render a label for the option based on a branch."""
     # To aid usability there needs to be some text connected with the
     # radio buttons that is not a hyperlink in order to select the radio
     # button.  It was decided not to have the entire text as a link, but
     # instead to have a separate link to the branch details.
     text = '%s (<a href="%s">branch details</a>)' % (
         html_escape(branch.displayname),
         html_escape(canonical_url(branch)))
     # If the branch is the development focus, say so.
     if branch == self.context.context.target.default_merge_target:
         text = text + "&ndash; <em>development focus</em>"
     label = u'<label for="%s" style="font-weight: normal">%s</label>' % (
         self._optionId(index), text)
     return structured(label)
    def test_existing_team_error(self):
        """ Do not allow a new team with the same name as an existing team.

        The ObjectReassignmentView displays radio buttons that give you the
        option to create a team as opposed to using an existing team. If the
        user tries to create a new team with the same name as an existing
        team, an error is displayed.
        """
        a_team, b_team, c_team, owner = self._makeTeams()
        view = create_initialized_view(
            c_team, '+reassign', principal=owner)
        self.assertEqual(
            ['field.owner', 'field.existing'],
            list(w.name for w in view.widgets))

        form = {
            'field.owner': 'a-team',
            'field.existing': 'new',
            'field.actions.change': 'Change',
            }
        view = create_initialized_view(
            a_team, '+reassign', form=form, principal=owner)
        self.assertEqual(
            [html_escape(
                u"There's already a person/team with the name 'a-team' in "
                "Launchpad. Please choose a different name or select the "
                "option to make that person/team the new owner, if that's "
                "what you want.")],
            view.errors)
 def test_too_short_branch_name(self):
     # error notification if the thing following +branch is a unique name
     # that's too short to be a real unique name.
     owner = self.factory.makePerson()
     requiredMessage = html_escape(
         u"Cannot understand namespace name: '%s'" % owner.name)
     self.assertDisplaysError('~%s' % owner.name, requiredMessage)
Example #16
0
 def test_composeIcon_title_defaults_to_alt_text(self):
     alt = self.factory.getUniqueString()
     icon = self.factory.getUniqueString() + ".png"
     html_text = html_escape(
         self.makeCompletePackageUpload().composeIcon(alt, icon))
     img = html.fromstring(html_text)
     self.assertEqual(alt, img.get("title"))
    def test_existing_team_error(self):
        """ Do not allow a new team with the same name as an existing team.

        The ObjectReassignmentView displays radio buttons that give you the
        option to create a team as opposed to using an existing team. If the
        user tries to create a new team with the same name as an existing
        team, an error is displayed.
        """
        a_team, b_team, c_team, owner = self._makeTeams()
        view = create_initialized_view(c_team, '+reassign', principal=owner)
        self.assertEqual(['field.owner', 'field.existing'],
                         list(w.name for w in view.widgets))

        form = {
            'field.owner': 'a-team',
            'field.existing': 'new',
            'field.actions.change': 'Change',
        }
        view = create_initialized_view(a_team,
                                       '+reassign',
                                       form=form,
                                       principal=owner)
        self.assertEqual([
            html_escape(
                u"There's already a person/team with the name 'a-team' in "
                "Launchpad. Please choose a different name or select the "
                "option to make that person/team the new owner, if that's "
                "what you want.")
        ], view.errors)
Example #18
0
 def _renderItem(self, index, text, value, name, cssClass, checked=False):
     """Render a checkbox and text without without label."""
     kw = {}
     if checked:
         kw['checked'] = 'checked'
     value = html_escape(value)
     text = html_escape(text)
     id = '%s.%s' % (name, index)
     element = renderElement(u'input',
                             value=value,
                             name=name,
                             id=id,
                             cssClass=cssClass,
                             type='checkbox',
                             **kw)
     return self._joinButtonToMessageTemplate % (element, text)
Example #19
0
def linkify_changelog(user, changelog, preloaded_person_data=None):
    """Linkify the changelog.

    This obfuscates email addresses to anonymous users, linkifies
    them for non-anonymous and links to the bug page for any bug
    numbers mentioned.
    """
    if changelog is None:
        return ''

    # Remove any email addresses if the user is not logged in.
    changelog = obfuscate_email(user, changelog)

    # CGI Escape the changelog here before further replacements
    # insert HTML. Email obfuscation does not insert HTML but can insert
    # characters that must be escaped.
    changelog = html_escape(changelog)

    # Any email addresses remaining in the changelog were not obfuscated,
    # so we linkify them here.
    changelog = linkify_email(changelog, preloaded_person_data)

    # Ensure any bug numbers are linkified to the bug page.
    changelog = linkify_bug_numbers(changelog)

    return changelog
Example #20
0
    def snippet(self):
        """Convert a widget input error to an html snippet

        If the error implements provides a snippet() method, just return it.
        Otherwise return the error message.

        >>> from zope.formlib.interfaces import WidgetInputError
        >>> from lp.services.webapp.escaping import structured
        >>> bold_error = LaunchpadValidationError(structured("<b>Foo</b>"))
        >>> err = WidgetInputError("foo", "Foo", bold_error)
        >>> view = WidgetInputErrorView(err, None)
        >>> view.snippet()
        u'<b>Foo</b>'

        >>> class TooSmallError(object):
        ...     def doc(self):
        ...         return "Foo input < 1"
        >>> err = WidgetInputError("foo", "Foo", TooSmallError())
        >>> view = WidgetInputErrorView(err, None)
        >>> view.snippet()
        u'Foo input &lt; 1'
        """
        if (hasattr(self.context, 'errors') and
                ILaunchpadValidationError.providedBy(self.context.errors)):
            return self.context.errors.snippet()
        return html_escape(self.context.doc())
Example #21
0
 def test_too_short_branch_name(self):
     # error notification if the thing following +branch is a unique name
     # that's too short to be a real unique name.
     owner = self.factory.makePerson()
     requiredMessage = html_escape(
         u"Cannot understand namespace name: '%s'" % owner.name)
     self.assertDisplaysError('~%s' % owner.name, requiredMessage)
Example #22
0
def channels_validator(channels):
    """Return True if the channels in a list are valid, or raise a
    LaunchpadValidationError.
    """
    tracks = set()
    branches = set()
    for name in channels:
        try:
            track, risk, branch = split_channel_name(name)
        except ValueError:
            message = _(
                "Invalid channel name '${name}'. Channel names must be of the "
                "form 'track/risk/branch', 'track/risk', 'risk/branch', or "
                "'risk'.",
                mapping={'name': html_escape(name)})
            raise LaunchpadValidationError(structured(message))
        tracks.add(track)
        branches.add(branch)

    # XXX cjwatson 2018-05-08: These are slightly arbitrary restrictions,
    # but they make the UI much simpler.

    if len(tracks) != 1:
        message = _("Channels must belong to the same track.")
        raise LaunchpadValidationError(structured(message))

    if len(branches) != 1:
        message = _("Channels must belong to the same branch.")
        raise LaunchpadValidationError(structured(message))

    return True
Example #23
0
    def snippet(self):
        """Convert a widget input error to an html snippet

        If the error implements provides a snippet() method, just return it.
        Otherwise return the error message.

        >>> from zope.formlib.interfaces import WidgetInputError
        >>> from lp.services.webapp.escaping import structured
        >>> bold_error = LaunchpadValidationError(structured("<b>Foo</b>"))
        >>> err = WidgetInputError("foo", "Foo", bold_error)
        >>> view = WidgetInputErrorView(err, None)
        >>> view.snippet()
        u'<b>Foo</b>'

        >>> class TooSmallError(object):
        ...     def doc(self):
        ...         return "Foo input < 1"
        >>> err = WidgetInputError("foo", "Foo", TooSmallError())
        >>> view = WidgetInputErrorView(err, None)
        >>> view.snippet()
        u'Foo input &lt; 1'
        """
        if (hasattr(self.context, 'errors') and
                ILaunchpadValidationError.providedBy(self.context.errors)):
            return self.context.errors.snippet()
        return html_escape(self.context.doc())
 def test_no_such_unique_name(self):
     # Traversing to /+branch/<unique_name> where 'unique_name' is for a
     # branch that doesn't exist will display an error message.
     branch = self.factory.makeAnyBranch()
     bad_name = branch.unique_name + 'wibble'
     required_message = html_escape(
         "No such branch: '%s'." % (branch.name + "wibble"))
     self.assertDisplaysError(bad_name, required_message)
 def test_cannot_merge_person_with_itself(self):
     # A IPerson cannot be merged with itself.
     login_person(self.target)
     form = self.getForm(dupe_name=self.target.name)
     view = create_initialized_view(
         self.person_set, '+requestmerge', form=form)
     self.assertEqual(
         [html_escape("You can't merge target into itself.")], view.errors)
Example #26
0
 def test_no_such_unique_name(self):
     # Traversing to /+branch/<unique_name> where 'unique_name' is for a
     # branch that doesn't exist will display an error message.
     branch = self.factory.makeAnyBranch()
     bad_name = branch.unique_name + 'wibble'
     required_message = html_escape("No such branch: '%s'." %
                                    (branch.name + "wibble"))
     self.assertDisplaysError(bad_name, required_message)
Example #27
0
 def _renderItem(self, index, text, value, name, cssClass, checked=False):
     """Render a checkbox and text in a label with a style attribute."""
     kw = {}
     if checked:
         kw['checked'] = 'checked'
     value = html_escape(value)
     text = html_escape(text)
     id = '%s.%s' % (name, index)
     elem = renderElement(u'input',
                          value=value,
                          name=name,
                          id=id,
                          cssClass=cssClass,
                          type='checkbox',
                          **kw)
     option_id = '%s.%s' % (self.name, index)
     return self._joinButtonToMessageTemplate % (option_id, elem, text)
Example #28
0
 def test_composeNameAndChangesLink_escapes_name_in_link(self):
     filename = 'name"&name'
     upload = self.factory.makeCustomPackageUpload(filename=filename)
     complete_upload = self.makeCompletePackageUpload(upload)
     link = html.fromstring(
         html_escape(complete_upload.composeNameAndChangesLink()))
     self.assertIn(filename, link.get("title"))
     self.assertEqual(filename, link.text)
Example #29
0
 def test_composeNameAndChangesLink_links_to_changes_file(self):
     complete_upload = self.makeCompletePackageUpload()
     link = html.fromstring(
         html_escape(complete_upload.composeNameAndChangesLink()))
     self.assertEqual(
         ProxiedLibraryFileAlias(
             complete_upload.changesfile, complete_upload.context).http_url,
         link.get("href"))
 def _renderItem(self, index, text, value, name, cssClass, checked=False):
     """Render a checkbox and text in a label with a style attribute."""
     kw = {}
     if checked:
         kw['checked'] = 'checked'
     value = html_escape(value)
     text = html_escape(text)
     id = '%s.%s' % (name, index)
     elem = renderElement(u'input',
                          value=value,
                          name=name,
                          id=id,
                          cssClass=cssClass,
                          type='checkbox',
                          **kw)
     option_id = '%s.%s' % (self.name, index)
     return self._joinButtonToMessageTemplate % (option_id, elem, text)
 def test_private_branch(self):
     # If an attempt is made to access a private branch, display an error.
     branch = self.factory.makeProductBranch(
         information_type=InformationType.USERDATA)
     branch_unique_name = removeSecurityProxy(branch).unique_name
     login(ANONYMOUS)
     required_message = html_escape(
         "No such branch: '%s'." % branch_unique_name)
     self.assertDisplaysError(branch_unique_name, required_message)
 def renderExtraHint(self):
     extra_hint_html = ''
     extra_hint_class = ''
     if self.extra_hint_class:
         extra_hint_class = ' class="%s"' % self.extra_hint_class
     if self.extra_hint:
         extra_hint_html = ('<div%s>%s</div>'
             % (extra_hint_class, html_escape(self.extra_hint)))
     return extra_hint_html
 def test_cannot_merge_person_with_itself(self):
     # A IPerson cannot be merged with itself.
     login_person(self.target)
     form = self.getForm(dupe_name=self.target.name)
     view = create_initialized_view(self.person_set,
                                    '+requestmerge',
                                    form=form)
     self.assertEqual([html_escape("You can't merge target into itself.")],
                      view.errors)
Example #34
0
 def test_private_branch(self):
     # If an attempt is made to access a private branch, display an error.
     branch = self.factory.makeProductBranch(
         information_type=InformationType.USERDATA)
     branch_unique_name = removeSecurityProxy(branch).unique_name
     login(ANONYMOUS)
     required_message = html_escape("No such branch: '%s'." %
                                    branch_unique_name)
     self.assertDisplaysError(branch_unique_name, required_message)
Example #35
0
 def test_composeIcon_escapes_alt_and_title(self):
     alt = 'alt"&'
     icon = self.factory.getUniqueString() + ".png"
     title = 'title"&'
     html_text = html_escape(
         self.makeCompletePackageUpload().composeIcon(alt, icon, title))
     img = html.fromstring(html_text)
     self.assertEqual("[%s]" % alt, img.get("alt"))
     self.assertEqual(title, img.get("title"))
 def test_error_on_duplicate_to_duplicate(self):
     # Test that a bug cannot be marked a duplicate of
     # a bug that is already itself a duplicate.
     msg = dedent(u"""
         Bug %s is already a duplicate of bug %s. You
         can only mark a bug report as duplicate of one that
         isn't a duplicate itself.
         """ % (self.dupe_bug.id, self.dupe_bug.duplicateof.id))
     self.assertDuplicateError(self.possible_dupe, self.dupe_bug,
                               html_escape(msg))
 def test_getInputValue_package_invalid(self):
     # An error is raised when the package is not published in the distro.
     form = self.form
     form['field.target.package'] = 'non-existent'
     self.widget.request = LaunchpadTestRequest(form=form)
     message = (
         "There is no package named 'non-existent' published in Fnord.")
     e = self.assertRaises(WidgetInputError, self.widget.getInputValue)
     self.assertEqual(LaunchpadValidationError(message), e.errors)
     self.assertEqual(html_escape(message), self.widget.error())
Example #38
0
 def test_add_empty_team_fail(self):
     empty_team = self.factory.makeTeam(owner=self.team.teamowner)
     self.team.teamowner.leave(empty_team)
     form = self.getForm(empty_team)
     view = create_initialized_view(self.team, "+addmember", form=form)
     self.assertEqual(1, len(view.errors))
     self.assertEqual(
         html_escape(
             "You can't add a team that doesn't have any active members."),
         view.errors[0])
Example #39
0
 def __call__(self):
     time_zone = getUtility(ILaunchBag).time_zone
     if self._renderedValueSet():
         value = self._data
     else:
         value = self.context.default
     if value == self.context.missing_value:
         return u""
     value = value.astimezone(time_zone)
     return html_escape(value.strftime("%Y-%m-%d %H:%M:%S %Z"))
    def addError(self, message):
        """Add a form wide error.

        The 'message' parameter is CGI-escaped in accordance with the
        `INotificationResponse.addNotification()` API.  Please see it
        for details re: internationalized and markup text.
        """
        cleanmsg = html_escape(message)
        self.form_wide_errors.append(cleanmsg)
        self.errors.append(cleanmsg)
Example #41
0
 def renderExtraHint(self):
     extra_hint_html = ''
     extra_hint_class = ''
     if self.extra_hint_class:
         extra_hint_class = ' class="%s"' % self.extra_hint_class
     if self.extra_hint:
         extra_hint_html = (
             '<div%s>%s</div>' %
             (extra_hint_class, html_escape(self.extra_hint)))
     return extra_hint_html
Example #42
0
    def addError(self, message):
        """Add a form wide error.

        The 'message' parameter is CGI-escaped in accordance with the
        `INotificationResponse.addNotification()` API.  Please see it
        for details re: internationalized and markup text.
        """
        cleanmsg = html_escape(message)
        self.form_wide_errors.append(cleanmsg)
        self.errors.append(cleanmsg)
Example #43
0
 def test_getInputValue_package_invalid(self):
     # An error is raised when the package is not published in the distro.
     form = self.form
     form['field.target.package'] = 'non-existent'
     self.widget.request = LaunchpadTestRequest(form=form)
     message = (
         "There is no package named 'non-existent' published in Fnord.")
     e = self.assertRaises(WidgetInputError, self.widget.getInputValue)
     self.assertEqual(LaunchpadValidationError(message), e.errors)
     self.assertEqual(html_escape(message), self.widget.error())
Example #44
0
 def test_add_empty_team_fail(self):
     empty_team = self.factory.makeTeam(owner=self.team.teamowner)
     self.team.teamowner.leave(empty_team)
     form = self.getForm(empty_team)
     view = create_initialized_view(self.team, "+addmember", form=form)
     self.assertEqual(1, len(view.errors))
     self.assertEqual(
         html_escape(
             "You can't add a team that doesn't have any active members."),
         view.errors[0])
def text_to_html(text, flags, space=TranslationConstants.SPACE_CHAR,
               newline=TranslationConstants.NEWLINE_CHAR):
    """Convert a unicode text to a HTML representation."""
    if text is None:
        return None

    lines = []
    # Replace leading and trailing spaces on each line with special markup.
    if u'\r\n' in text:
        newline_chars = u'\r\n'
    elif u'\r' in text:
        newline_chars = u'\r'
    else:
        newline_chars = u'\n'
    for line in html_escape(text).split(newline_chars):
        # Pattern:
        # - group 1: zero or more spaces: leading whitespace
        # - group 2: zero or more groups of (zero or
        #   more spaces followed by one or more non-spaces): maximal string
        #   which doesn't begin or end with whitespace
        # - group 3: zero or more spaces: trailing whitespace
        match = re.match(u'^( *)((?: *[^ ]+)*)( *)$', line)

        if match:
            lines.append(
                space * len(match.group(1)) +
                match.group(2) +
                space * len(match.group(3)))
        else:
            raise AssertionError(
                "A regular expression that should always match didn't.")

    if 'c-format' in flags:
        # Replace c-format sequences with marked-up versions. If there is a
        # problem parsing the c-format sequences on a particular line, that
        # line is left unformatted.
        for i in range(len(lines)):
            formatted_line = ''

            try:
                segments = parse_cformat_string(lines[i])
            except UnrecognisedCFormatString:
                continue

            for segment in segments:
                type, content = segment

                if type == 'interpolation':
                    formatted_line += (u'<code>%s</code>' % content)
                elif type == 'string':
                    formatted_line += content

            lines[i] = formatted_line

    return expand_rosetta_escapes(newline.join(lines))
 def renderItem(self, index, text, value, name, cssClass):
     """Render an item of the list."""
     text = html_escape(text)
     id = '%s.%s' % (name, index)
     elem = renderElement(u'input',
                          value=value,
                          name=name,
                          id=id,
                          cssClass=cssClass,
                          type='radio')
     return self._renderRow(text, value, id, elem)
Example #47
0
 def renderItem(self, index, text, value, name, cssClass):
     """Render an item of the list."""
     text = html_escape(text)
     id = '%s.%s' % (name, index)
     elem = renderElement(u'input',
                          value=value,
                          name=name,
                          id=id,
                          cssClass=cssClass,
                          type='radio')
     return self._renderRow(text, value, id, elem)
 def test_cannot_merge_person_with_ppa(self):
     # A person with a PPA cannot be merged.
     login_celebrity('admin')
     self.dupe_person.createPPA()
     view = self.getView()
     self.assertEqual(
         [html_escape(
             u"dupe-person has a PPA that must be deleted before it can "
             "be merged. It may take ten minutes to remove the deleted "
             "PPA's files.")],
         view.errors)
Example #49
0
def validate_new_person_email(email):
    """Check that the given email is valid and not registered to
    another launchpad account.

    This validator is supposed to be used only when creating a new profile
    using the /people/+newperson page, as the message will say clearly to the
    user that the profile he's trying to create already exists, so there's no
    need to create another one.
    """
    from lp.services.webapp.publisher import canonical_url
    from lp.registry.interfaces.person import IPersonSet
    _validate_email(email)
    owner = getUtility(IPersonSet).getByEmail(email)
    if owner is not None:
        message = _("The profile you're trying to create already exists: "
                    '<a href="${url}">${owner}</a>.',
                    mapping={'url': html_escape(canonical_url(owner)),
                             'owner': html_escape(owner.displayname)})
        raise LaunchpadValidationError(structured(message))
    return True
Example #50
0
    def _renderTemplateLink(self, template, url):
        """Render a link to `template`.

        :param template: The target `POTemplate`.
        :param url: The cached URL for `template`.
        :return: HTML for a link to `template`.
        """
        text = '<a href="%s">%s</a>' % (url, html_escape(template.name))
        if not template.iscurrent:
            text += ' (inactive)'
        return text
 def test_error_on_duplicate_to_duplicate(self):
     # Test that a bug cannot be marked a duplicate of
     # a bug that is already itself a duplicate.
     msg = dedent(u"""
         Bug %s is already a duplicate of bug %s. You
         can only mark a bug report as duplicate of one that
         isn't a duplicate itself.
         """ % (
             self.dupe_bug.id, self.dupe_bug.duplicateof.id))
     self.assertDuplicateError(
         self.possible_dupe, self.dupe_bug, html_escape(msg))
Example #52
0
 def test_composeIcon_produces_image_tag(self):
     alt = self.factory.getUniqueString()
     icon = self.factory.getUniqueString() + ".png"
     title = self.factory.getUniqueString()
     html_text = html_escape(
         self.makeCompletePackageUpload().composeIcon(alt, icon, title))
     img = html.fromstring(html_text)
     self.assertEqual("img", img.tag)
     self.assertEqual("[%s]" % alt, img.get("alt"))
     self.assertEqual("/@@/" + icon, img.get("src"))
     self.assertEqual(title, img.get("title"))