Esempio n. 1
0
    def lookup_xml_id(self, url):
        """A helper method for locating a part of a WADL document.

        :param url: The URL (with anchor) of the desired part of the
        WADL document.
        :return: The XML ID corresponding to the anchor.
        """
        markup_uri = URI(self.markup_url).ensureNoSlash()
        markup_uri.fragment = None

        if url.startswith('http'):
            # It's an absolute URI.
            this_uri = URI(url).ensureNoSlash()
        else:
            # It's a relative URI.
            this_uri = markup_uri.resolve(url)
        possible_xml_id = this_uri.fragment
        this_uri.fragment = None

        if this_uri == markup_uri:
            # The URL pointed elsewhere within the same WADL document.
            # Return its fragment.
            return possible_xml_id

        # XXX leonardr 2008-05-28:
        # This needs to be implemented eventually for Launchpad so
        # that a script using this client can navigate from a WADL
        # representation of a non-root resource to its definition at
        # the server root.
        raise NotImplementedError("Can't look up definition in another "
                                  "url (%s)" % url)
Esempio n. 2
0
    def lookup_xml_id(self, url):
        """A helper method for locating a part of a WADL document.

        :param url: The URL (with anchor) of the desired part of the
        WADL document.
        :return: The XML ID corresponding to the anchor.
        """
        markup_uri = URI(self.markup_url).ensureNoSlash()
        markup_uri.fragment = None

        if url.startswith('http'):
            # It's an absolute URI.
            this_uri = URI(url).ensureNoSlash()
        else:
            # It's a relative URI.
            this_uri = markup_uri.resolve(url)
        possible_xml_id = this_uri.fragment
        this_uri.fragment = None

        if this_uri == markup_uri:
            # The URL pointed elsewhere within the same WADL document.
            # Return its fragment.
            return possible_xml_id

        # XXX leonardr 2008-05-28:
        # This needs to be implemented eventually for Launchpad so
        # that a script using this client can navigate from a WADL
        # representation of a non-root resource to its definition at
        # the server root.
        raise NotImplementedError("Can't look up definition in another "
                                  "url (%s)" % url)
Esempio n. 3
0
    def list(self, dirname):
        """Download the HTML index at subdir and scrape for URLs.

        Returns a list of directory names (links ending with /, or
        that result in redirects to themselves ending in /) and
        filenames (everything else) that reside underneath the path.
        """
        self.log.info("Listing %s" % dirname)
        try:
            response = self.request("GET", dirname)
            try:
                soup = BeautifulSoup(response.read())
            finally:
                response.close()
        except (IOError, socket.error) as exc:
            raise HTTPWalkerError(str(exc))

        base = URI(self.base).resolve(dirname)

        # Collect set of URLs that are below the base URL
        urls = set()
        for anchor in soup("a"):
            href = anchor.get("href")
            if href is None:
                continue
            try:
                url = base.resolve(href)
            except InvalidURIError:
                continue
            # Only add the URL if it is strictly inside the base URL.
            if base.contains(url) and not url.contains(base):
                urls.add(url)

        dirnames = set()
        filenames = set()
        for url in urls:
            if url.path.endswith(';type=a') or url.path.endswith(';type=i'):
                # these links come from Squid's FTP dir listing to
                # force either ASCII or binary download and can be
                # ignored.
                continue

            filename = subdir(base.path, url.path)
            if self.isDirectory(url.path):
                dirnames.add(as_dir(filename))
            else:
                filenames.add(filename)

        return (sorted(dirnames), sorted(filenames))
Esempio n. 4
0
    def list(self, dirname):
        """Download the HTML index at subdir and scrape for URLs.

        Returns a list of directory names (links ending with /, or
        that result in redirects to themselves ending in /) and
        filenames (everything else) that reside underneath the path.
        """
        self.log.info("Listing %s" % dirname)
        try:
            response = self.request("GET", dirname)
            try:
                soup = BeautifulSoup(response.read())
            finally:
                response.close()
        except (IOError, socket.error) as exc:
            raise HTTPWalkerError(str(exc))

        base = URI(self.base).resolve(dirname)

        # Collect set of URLs that are below the base URL
        urls = set()
        for anchor in soup("a"):
            href = anchor.get("href")
            if href is None:
                continue
            try:
                url = base.resolve(href)
            except InvalidURIError:
                continue
            # Only add the URL if it is strictly inside the base URL.
            if base.contains(url) and not url.contains(base):
                urls.add(url)

        dirnames = set()
        filenames = set()
        for url in urls:
            if url.path.endswith(';type=a') or url.path.endswith(';type=i'):
                # these links come from Squid's FTP dir listing to
                # force either ASCII or binary download and can be
                # ignored.
                continue

            filename = subdir(base.path, url.path)
            if self.isDirectory(url.path):
                dirnames.add(as_dir(filename))
            else:
                filenames.add(filename)

        return (sorted(dirnames), sorted(filenames))
Esempio n. 5
0
class MenuBase(UserAttributeCache):
    """Base class for facets and menus."""

    implements(IMenuBase)

    links = None
    extra_attributes = None
    enable_only = ALL_LINKS
    _baseclassname = 'MenuBase'
    _initialized = False
    _forbiddenlinknames = set([
        'user', 'initialize', 'links', 'enable_only', 'iterlinks', 'initLink',
        'updateLink', 'extra_attributes'
    ])

    def __init__(self, context):
        # The attribute self.context is defined in IMenuBase.
        self.context = context
        self.request = None

    def initialize(self):
        """Override this in subclasses to do initialization."""
        pass

    def _check_links(self):
        assert self.links is not None, (
            'Subclasses of %s must provide self.links' % self._baseclassname)
        assert isinstance(
            self.links, (tuple, list)), ("self.links must be a tuple or list.")

    def _buildLink(self, name):
        method = getattr(self, name, None)
        # Since Zope traversals hides the root cause of an AttributeError,
        # an AssertionError is raised explaining what went wrong.
        if method is None:
            raise AssertionError('%r does not define %r method.' %
                                 (self, name))
        linkdata = method()
        # The link need only provide ILinkData.  We need an ILink so that
        # we can set attributes on it like 'name' and 'url' and 'linked'.
        return ILink(linkdata)

    def _get_link(self, name):
        request = get_current_browser_request()
        if request is not None:
            # We must not use a weak ref here because if we do so and
            # templates do stuff like "context/menu:bugs/foo", then there
            # would be no reference to the Link object, which would allow it
            # to be garbage collected during the course of the request.
            cache = request.annotations.setdefault(MENU_ANNOTATION_KEY, {})
            key = (self.__class__, self.context, name)
            link = cache.get(key)
            if link is None:
                link = self._buildLink(name)
                cache[key] = link
            return link
        return self._buildLink(name)

    def _rootUrlForSite(self, site):
        """Return the root URL for the given site."""
        try:
            return URI(allvhosts.configs[site].rooturl)
        except KeyError:
            raise AssertionError('unknown site', site)

    def _init_link_data(self):
        if self._initialized:
            return
        self._initialized = True
        self.initialize()
        self._check_links()
        links_set = set(self.links)
        assert not links_set.intersection(self._forbiddenlinknames), (
            "The following names may not be links: %s" %
            ', '.join(self._forbiddenlinknames))

        if isinstance(self.context, LaunchpadView):
            # It's a navigation menu for a view instead of a db object. Views
            # don't have a canonical URL, they use the db object one used as
            # the context for that view.
            context = self.context.context
        else:
            context = self.context

        self._contexturlobj = URI(canonical_url(context))

        if self.enable_only is ALL_LINKS:
            self._enable_only_set = links_set
        else:
            self._enable_only_set = set(self.enable_only)

        unknown_links = self._enable_only_set - links_set
        if len(unknown_links) > 0:
            # There are links named in enable_only that do not exist in
            # self.links.
            raise AssertionError(
                "Links in 'enable_only' not found in 'links': %s" %
                ', '.join(sorted(unknown_links)))

    def initLink(self, linkname, request_url=None):
        self._init_link_data()
        link = self._get_link(linkname)
        link.name = linkname

        # Set the .enabled attribute of the link to False if it is not
        # in enable_only.
        if linkname not in self._enable_only_set:
            link.enabled = False

        # Set the .url attribute of the link, using the menu's context.
        if link.site is None:
            rootsite = self._contexturlobj.resolve('/')
        else:
            rootsite = self._rootUrlForSite(link.site)
        # Is the target a full URI already?
        try:
            link.url = URI(link.target)
        except InvalidURIError:
            if link.target.startswith('/'):
                link.url = rootsite.resolve(link.target)
            else:
                link.url = rootsite.resolve(self._contexturlobj.path).append(
                    link.target)

        # Make the link unlinked if it is a link to the current page.
        if request_url is not None:
            if request_url.ensureSlash() == link.url.ensureSlash():
                link.linked = False

        idx = self.links.index(linkname)
        link.sort_key = idx
        return link

    def updateLink(self, link, request_url, **kwargs):
        """Called each time a link is rendered.

        Override to update the link state as required for the given request.
        """
        pass

    def iterlinks(self, request_url=None, **kwargs):
        """See IMenu."""
        self._check_links()
        for linkname in self.links:
            link = self.initLink(linkname, request_url)
            self.updateLink(link, request_url, **kwargs)
            yield link
Esempio n. 6
0
class MenuBase(UserAttributeCache):
    """Base class for facets and menus."""

    implements(IMenuBase)

    links = None
    extra_attributes = None
    enable_only = ALL_LINKS
    _baseclassname = 'MenuBase'
    _initialized = False
    _forbiddenlinknames = set(
        ['user', 'initialize', 'links', 'enable_only', 'iterlinks',
         'initLink', 'updateLink', 'extra_attributes'])

    def __init__(self, context):
        # The attribute self.context is defined in IMenuBase.
        self.context = context
        self.request = None

    def initialize(self):
        """Override this in subclasses to do initialization."""
        pass

    def _check_links(self):
        assert self.links is not None, (
            'Subclasses of %s must provide self.links' % self._baseclassname)
        assert isinstance(self.links, (tuple, list)), (
            "self.links must be a tuple or list.")

    def _buildLink(self, name):
        method = getattr(self, name, None)
        # Since Zope traversals hides the root cause of an AttributeError,
        # an AssertionError is raised explaining what went wrong.
        if method is None:
            raise AssertionError(
                '%r does not define %r method.' % (self, name))
        linkdata = method()
        # The link need only provide ILinkData.  We need an ILink so that
        # we can set attributes on it like 'name' and 'url' and 'linked'.
        return ILink(linkdata)

    def _get_link(self, name):
        request = get_current_browser_request()
        if request is not None:
            # We must not use a weak ref here because if we do so and
            # templates do stuff like "context/menu:bugs/foo", then there
            # would be no reference to the Link object, which would allow it
            # to be garbage collected during the course of the request.
            cache = request.annotations.setdefault(MENU_ANNOTATION_KEY, {})
            key = (self.__class__, self.context, name)
            link = cache.get(key)
            if link is None:
                link = self._buildLink(name)
                cache[key] = link
            return link
        return self._buildLink(name)

    def _rootUrlForSite(self, site):
        """Return the root URL for the given site."""
        try:
            return URI(allvhosts.configs[site].rooturl)
        except KeyError:
            raise AssertionError('unknown site', site)

    def _init_link_data(self):
        if self._initialized:
            return
        self._initialized = True
        self.initialize()
        self._check_links()
        links_set = set(self.links)
        assert not links_set.intersection(self._forbiddenlinknames), (
            "The following names may not be links: %s" %
            ', '.join(self._forbiddenlinknames))

        if isinstance(self.context, LaunchpadView):
            # It's a navigation menu for a view instead of a db object. Views
            # don't have a canonical URL, they use the db object one used as
            # the context for that view.
            context = self.context.context
        else:
            context = self.context

        self._contexturlobj = URI(canonical_url(context))

        if self.enable_only is ALL_LINKS:
            self._enable_only_set = links_set
        else:
            self._enable_only_set = set(self.enable_only)

        unknown_links = self._enable_only_set - links_set
        if len(unknown_links) > 0:
            # There are links named in enable_only that do not exist in
            # self.links.
            raise AssertionError(
                "Links in 'enable_only' not found in 'links': %s" %
                ', '.join(sorted(unknown_links)))

    def initLink(self, linkname, request_url=None):
        self._init_link_data()
        link = self._get_link(linkname)
        link.name = linkname

        # Set the .enabled attribute of the link to False if it is not
        # in enable_only.
        if linkname not in self._enable_only_set:
            link.enabled = False

        # Set the .url attribute of the link, using the menu's context.
        if link.site is None:
            rootsite = self._contexturlobj.resolve('/')
        else:
            rootsite = self._rootUrlForSite(link.site)
        # Is the target a full URI already?
        try:
            link.url = URI(link.target)
        except InvalidURIError:
            if link.target.startswith('/'):
                link.url = rootsite.resolve(link.target)
            else:
                link.url = rootsite.resolve(self._contexturlobj.path).append(
                    link.target)

        # Make the link unlinked if it is a link to the current page.
        if request_url is not None:
            if request_url.ensureSlash() == link.url.ensureSlash():
                link.linked = False

        idx = self.links.index(linkname)
        link.sort_key = idx
        return link

    def updateLink(self, link, request_url, **kwargs):
        """Called each time a link is rendered.

        Override to update the link state as required for the given request.
        """
        pass

    def iterlinks(self, request_url=None, **kwargs):
        """See IMenu."""
        self._check_links()
        for linkname in self.links:
            link = self.initLink(linkname, request_url)
            self.updateLink(link, request_url, **kwargs)
            yield link