~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/browser/archive.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-06-10 19:46:57 UTC
  • mfrom: (13137.1.21 ppa-api)
  • Revision ID: launchpad@pqm.canonical.com-20110610194657-qpovv3hj69uyqpw8
[r=gmb][bug=776444,
 776449] Provide PPA dependency controls via the web service.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
    datetime,
34
34
    timedelta,
35
35
    )
36
 
from urlparse import urlparse
37
36
 
38
37
import pytz
39
38
from sqlobject import SQLObjectNotFound
138
137
    PackagePublishingStatus,
139
138
    )
140
139
from lp.soyuz.interfaces.archive import (
 
140
    ArchiveDependencyError,
141
141
    CannotCopy,
142
142
    IArchive,
143
143
    IArchiveEditDependenciesForm,
144
144
    IArchiveSet,
145
145
    NoSuchPPA,
 
146
    validate_external_dependencies,
146
147
    )
147
148
from lp.soyuz.interfaces.archivepermission import IArchivePermissionSet
148
149
from lp.soyuz.interfaces.archivesubscriber import IArchiveSubscriberSet
1864
1865
        self._messages.append(structured(
1865
1866
            '<p>Primary dependency added: %s</p>', primary_dependency.title))
1866
1867
 
1867
 
    def validate(self, data):
1868
 
        """Validate dependency configuration changes.
1869
 
 
1870
 
        Skip checks if no dependency candidate was sent in the form.
1871
 
 
1872
 
        Validate if the requested PPA dependency is sane (different than
1873
 
        the context PPA and not yet registered).
1874
 
 
1875
 
        Also check if the dependency candidate is private, if so, it can
1876
 
        only be set if the user has 'launchpad.View' permission on it and
1877
 
        the context PPA is also private (this way P3A credentials will be
1878
 
        sanitized from buildlogs).
1879
 
        """
1880
 
        dependency_candidate = data.get('dependency_candidate')
1881
 
 
1882
 
        if dependency_candidate is None:
1883
 
            return
1884
 
 
1885
 
        if dependency_candidate == self.context:
1886
 
            self.setFieldError('dependency_candidate',
1887
 
                               "An archive should not depend on itself.")
1888
 
            return
1889
 
 
1890
 
        if self.context.getArchiveDependency(dependency_candidate):
1891
 
            self.setFieldError('dependency_candidate',
1892
 
                               "This dependency is already registered.")
1893
 
            return
1894
 
 
1895
 
        if not check_permission('launchpad.View', dependency_candidate):
1896
 
            self.setFieldError(
1897
 
                'dependency_candidate',
1898
 
                "You don't have permission to use this dependency.")
1899
 
            return
1900
 
 
1901
 
        if dependency_candidate.private and not self.context.private:
1902
 
            self.setFieldError(
1903
 
                'dependency_candidate',
1904
 
                "Public PPAs cannot depend on private ones.")
1905
 
 
1906
1868
    @action(_("Save"), name="save")
1907
1869
    def save_action(self, action, data):
1908
1870
        """Save dependency configuration changes.
1914
1876
        refreshing. And render a page notification with the summary of the
1915
1877
        changes made.
1916
1878
        """
1917
 
        # Redirect after POST.
1918
 
        self.next_url = self.request.URL
1919
 
 
1920
1879
        # Process the form.
1921
1880
        self._add_primary_dependencies(data)
1922
 
        self._add_ppa_dependencies(data)
 
1881
        try:
 
1882
            self._add_ppa_dependencies(data)
 
1883
        except ArchiveDependencyError as e:
 
1884
            self.setFieldError('dependency_candidate', str(e))
 
1885
            return
1923
1886
        self._remove_dependencies(data)
1924
1887
 
1925
1888
        # Issue a notification if anything was changed.
1926
1889
        if len(self.messages) > 0:
1927
1890
            self.request.response.addNotification(
1928
1891
                structured(self.messages))
 
1892
        # Redirect after POST.
 
1893
        self.next_url = self.request.URL
1929
1894
 
1930
1895
 
1931
1896
class ArchiveActivateView(LaunchpadFormView):
2128
2093
        # Check the external_dependencies field.
2129
2094
        ext_deps = data.get('external_dependencies')
2130
2095
        if ext_deps is not None:
2131
 
            errors = self.validate_external_dependencies(ext_deps)
 
2096
            errors = validate_external_dependencies(ext_deps)
2132
2097
            if len(errors) != 0:
2133
2098
                error_text = "\n".join(errors)
2134
2099
                self.setFieldError('external_dependencies', error_text)
2138
2103
                'commercial',
2139
2104
                'Can only set commericial for private archives.')
2140
2105
 
2141
 
    def validate_external_dependencies(self, ext_deps):
2142
 
        """Validate the external_dependencies field.
2143
 
 
2144
 
        :param ext_deps: The dependencies form field to check.
2145
 
        """
2146
 
        errors = []
2147
 
        # The field can consist of multiple entries separated by
2148
 
        # newlines, so process each in turn.
2149
 
        for dep in ext_deps.splitlines():
2150
 
            try:
2151
 
                deb, url, suite, components = dep.split(" ", 3)
2152
 
            except ValueError:
2153
 
                errors.append(
2154
 
                    "'%s' is not a complete and valid sources.list entry"
2155
 
                        % dep)
2156
 
                continue
2157
 
 
2158
 
            if deb != "deb":
2159
 
                errors.append("%s: Must start with 'deb'" % dep)
2160
 
            url_components = urlparse(url)
2161
 
            if not url_components[0] or not url_components[1]:
2162
 
                errors.append("%s: Invalid URL" % dep)
2163
 
 
2164
 
        return errors
2165
 
 
2166
2106
    @property
2167
2107
    def owner_is_private_team(self):
2168
2108
        """Is the owner a private team?