~launchpad-pqm/launchpad/devel

8687.15.17 by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/.
1
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
6141.1.5 by Julian Edwards
Add content class & interface for ArchivePermission.
3
4
"""Database class for table ArchivePermission."""
5
6
__metaclass__ = type
7
6141.1.6 by Julian Edwards
Add utility class and zcml.
8
__all__ = [
9
    'ArchivePermission',
10
    'ArchivePermissionSet',
11
    ]
6141.1.5 by Julian Edwards
Add content class & interface for ArchivePermission.
12
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
13
from sqlobject import (
14
    BoolCol,
15
    ForeignKey,
16
    )
7675.166.301 by Stuart Bishop
Replace In(col, i) with col.is_in(u) to work around Bug #670906 and delint
17
from storm.expr import SQL
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
18
from storm.locals import (
19
    Int,
20
    Reference,
21
    )
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
22
from storm.store import Store
6141.1.11 by Julian Edwards
Fix lint
23
from zope.component import getUtility
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
24
from zope.interface import (
25
    alsoProvides,
26
    implements,
27
    )
6141.1.5 by Julian Edwards
Add content class & interface for ArchivePermission.
28
29
from canonical.database.constants import UTC_NOW
30
from canonical.database.datetimecol import UtcDateTimeCol
31
from canonical.database.enumcol import EnumCol
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
32
from canonical.database.sqlbase import (
33
    SQLBase,
34
    sqlvalues,
35
    )
36
from canonical.launchpad.interfaces.lpstorm import (
37
    IMasterStore,
38
    IStore,
39
    )
40
from canonical.launchpad.webapp.interfaces import (
41
    DEFAULT_FLAVOR,
42
    IStoreSelector,
43
    MAIN_STORE,
44
    )
11270.1.3 by Tim Penhey
Changed NotFoundError imports - gee there were a lot of them.
45
from lp.app.errors import NotFoundError
7675.361.3 by Muharem Hrnjadovic
If a package set *name* is used in conjunction with archive permissions the respective package set in the current distro series will be used.
46
from lp.registry.interfaces.distribution import IDistributionSet
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
47
from lp.registry.interfaces.sourcepackagename import (
48
    ISourcePackageName,
49
    ISourcePackageNameSet,
50
    )
51
from lp.soyuz.interfaces.archive import (
52
    ComponentNotFound,
53
    IArchive,
54
    )
11411.6.4 by Julian Edwards
move ArchivePermissionType
55
from lp.soyuz.enums import ArchivePermissionType
8294.6.1 by Julian Edwards
First stab at code-reorg. Still got a discrepancy on stuff I assigned to registry but not migrated yet.
56
from lp.soyuz.interfaces.archivepermission import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
57
    IArchivePermission,
58
    IArchivePermissionSet,
59
    IArchiveQueueAdmin,
60
    IArchiveUploader,
61
    )
62
from lp.soyuz.interfaces.component import (
63
    IComponent,
64
    IComponentSet,
65
    )
66
from lp.soyuz.interfaces.packageset import IPackageset
8303.14.19 by Julian Edwards
Migrate the packageset-related files.
67
from lp.soyuz.model.packageset import Packageset
7118.2.18 by Julian Edwards
bac's review comments.
68
6141.1.5 by Julian Edwards
Add content class & interface for ArchivePermission.
69
7675.134.6 by Muharem Hrnjadovic
Brad's review comments
70
def _extract_type_name(value):
71
    """Extract the type name of the given value."""
72
    return str(type(value)).split("'")[-2]
73
74
6141.1.5 by Julian Edwards
Add content class & interface for ArchivePermission.
75
class ArchivePermission(SQLBase):
6141.1.8 by Julian Edwards
Add doc test.
76
    """See `IArchivePermission`."""
6141.1.5 by Julian Edwards
Add content class & interface for ArchivePermission.
77
    implements(IArchivePermission)
78
    _table = 'ArchivePermission'
79
    _defaultOrder = 'id'
80
81
    date_created = UtcDateTimeCol(
82
        dbName='date_created', notNull=True, default=UTC_NOW)
83
84
    archive = ForeignKey(foreignKey='Archive', dbName='archive', notNull=True)
85
86
    permission = EnumCol(
87
        dbName='permission', unique=False, notNull=True,
88
        schema=ArchivePermissionType)
89
90
    person = ForeignKey(foreignKey='Person', dbName='person', notNull=True)
91
92
    component = ForeignKey(
93
        foreignKey='Component', dbName='component', notNull=False)
94
95
    sourcepackagename = ForeignKey(
6141.1.8 by Julian Edwards
Add doc test.
96
        foreignKey='SourcePackageName', dbName='sourcepackagename',
6141.1.5 by Julian Edwards
Add content class & interface for ArchivePermission.
97
        notNull=False)
98
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
99
    packageset_id = Int(name='packageset', allow_none=True)
100
    packageset = Reference(packageset_id, 'Packageset.id')
101
102
    explicit = BoolCol(dbName='explicit', notNull=True, default=False)
103
7026.5.2 by Julian Edwards
First version of a URL schema for archive permissions.
104
    def _init(self, *args, **kw):
105
        """Provide the right interface for URL traversal."""
106
        SQLBase._init(self, *args, **kw)
107
108
        # Provide the additional marker interface depending on what type
109
        # of archive this is.  See also the browser:url declarations in
110
        # zcml/archivepermission.zcml.
111
        if self.permission == ArchivePermissionType.UPLOAD:
7026.5.3 by Julian Edwards
Add export of IArchivePermission
112
            alsoProvides(self, IArchiveUploader)
7026.5.2 by Julian Edwards
First version of a URL schema for archive permissions.
113
        elif self.permission == ArchivePermissionType.QUEUE_ADMIN:
7026.5.3 by Julian Edwards
Add export of IArchivePermission
114
            alsoProvides(self, IArchiveQueueAdmin)
7026.5.2 by Julian Edwards
First version of a URL schema for archive permissions.
115
        else:
7675.166.301 by Stuart Bishop
Replace In(col, i) with col.is_in(u) to work around Bug #670906 and delint
116
            raise AssertionError(
7026.5.2 by Julian Edwards
First version of a URL schema for archive permissions.
117
                "Unknown permission type %s" % self.permission)
118
7026.5.3 by Julian Edwards
Add export of IArchivePermission
119
    @property
120
    def component_name(self):
121
        """See `IArchivePermission`"""
122
        if self.component:
10427.18.5 by Michael Nelson
Ensure that an iterable of archives can be used for componentsForQueueAdmin().
123
            return self.component.name
7026.5.3 by Julian Edwards
Add export of IArchivePermission
124
        else:
125
            return None
126
127
    @property
128
    def source_package_name(self):
129
        """See `IArchivePermission`"""
130
        if self.sourcepackagename:
131
            return self.sourcepackagename.name
132
        else:
133
            return None
134
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
135
    @property
136
    def package_set_name(self):
137
        """See `IArchivePermission`"""
138
        if self.packageset:
139
            return self.packageset.name
140
        else:
141
            return None
142
7675.373.1 by Muharem Hrnjadovic
Bug #472929 fixed.
143
    @property
144
    def distro_series_name(self):
145
        """See `IArchivePermission`"""
146
        if self.packageset:
147
            return self.packageset.distroseries.name
148
        else:
149
            return None
150
6141.1.6 by Julian Edwards
Add utility class and zcml.
151
152
class ArchivePermissionSet:
153
    """See `IArchivePermissionSet`."""
154
    implements(IArchivePermissionSet)
155
7131.2.5 by Julian Edwards
salgado's review comments
156
    def checkAuthenticated(self, person, archive, permission, item):
6141.1.6 by Julian Edwards
Add utility class and zcml.
157
        """See `IArchivePermissionSet`."""
6236.1.1 by Julian Edwards
Make IArchivePermissionSet.checkAuthenticated take into account the team
158
        clauses = ["""
159
            ArchivePermission.archive = %s AND
160
            ArchivePermission.permission = %s AND
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
161
            ArchivePermission.person = TeamParticipation.team AND
162
            TeamParticipation.person = %s
7675.166.301 by Stuart Bishop
Replace In(col, i) with col.is_in(u) to work around Bug #670906 and delint
163
            """ % sqlvalues(archive, permission, person)]
6236.1.1 by Julian Edwards
Make IArchivePermissionSet.checkAuthenticated take into account the team
164
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
165
        prejoins = []
166
6141.1.6 by Julian Edwards
Add utility class and zcml.
167
        if IComponent.providedBy(item):
6236.1.1 by Julian Edwards
Make IArchivePermissionSet.checkAuthenticated take into account the team
168
            clauses.append(
169
                "ArchivePermission.component = %s" % sqlvalues(item))
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
170
            prejoins.append("component")
6141.1.6 by Julian Edwards
Add utility class and zcml.
171
        elif ISourcePackageName.providedBy(item):
6236.1.1 by Julian Edwards
Make IArchivePermissionSet.checkAuthenticated take into account the team
172
            clauses.append(
173
                "ArchivePermission.sourcepackagename = %s" % sqlvalues(item))
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
174
            prejoins.append("sourcepackagename")
7675.145.1 by Muharem Hrnjadovic
import from the psapi-365894 branch
175
        elif IPackageset.providedBy(item):
176
            clauses.append(
177
                "ArchivePermission.packageset = %s" % sqlvalues(item.id))
178
            prejoins.append("packageset")
6141.1.6 by Julian Edwards
Add utility class and zcml.
179
        else:
7675.145.4 by Muharem Hrnjadovic
Barry's review comments
180
            raise AssertionError(
10156.2.11 by Jelmer Vernooij
rename
181
                "'item' %r is not an IComponent, IPackageset or an "
182
                "ISourcePackageName" % item)
6141.1.6 by Julian Edwards
Add utility class and zcml.
183
6236.1.1 by Julian Edwards
Make IArchivePermissionSet.checkAuthenticated take into account the team
184
        query = " AND ".join(clauses)
185
        auth = ArchivePermission.select(
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
186
            query, clauseTables=["TeamParticipation"],
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
187
            prejoins=prejoins)
6236.1.1 by Julian Edwards
Make IArchivePermissionSet.checkAuthenticated take into account the team
188
6141.1.6 by Julian Edwards
Add utility class and zcml.
189
        return auth
190
7118.2.11 by Julian Edwards
Fix merge bustage
191
    def _nameToComponent(self, component):
192
        """Helper to convert a possible string component to IComponent"""
7285.4.1 by Julian Edwards
Make the archivepermission API throw webservice-friendly exceptions.
193
        try:
194
            if isinstance(component, basestring):
195
                component = getUtility(IComponentSet)[component]
196
            return component
13228.3.13 by Francis J. Lacoste
Lint blows but hoover sucks
197
        except NotFoundError:
13228.3.7 by Francis J. Lacoste
Made ComponentNotFound as subclass of NameLookupFailed.
198
            raise ComponentNotFound(component)
7118.2.11 by Julian Edwards
Fix merge bustage
199
200
    def _nameToSourcePackageName(self, sourcepackagename):
201
        """Helper to convert a possible string name to ISourcePackageName."""
8971.5.1 by Celso Providelo
Cleaning up API IPackageSets.
202
        if isinstance(sourcepackagename, basestring):
203
            sourcepackagename = getUtility(
204
                ISourcePackageNameSet)[sourcepackagename]
205
        return sourcepackagename
7118.2.11 by Julian Edwards
Fix merge bustage
206
7118.2.10 by Julian Edwards
merge trunk
207
    def permissionsForPerson(self, archive, person):
7118.2.2 by Julian Edwards
Add exported getPermissionsForUser on IArchive
208
        """See `IArchivePermissionSet`."""
7118.2.18 by Julian Edwards
bac's review comments.
209
        store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
210
        return store.find(
211
            ArchivePermission, """
7118.2.2 by Julian Edwards
Add exported getPermissionsForUser on IArchive
212
            ArchivePermission.archive = %s AND
213
            EXISTS (SELECT TeamParticipation.person
214
                    FROM TeamParticipation
215
                    WHERE TeamParticipation.person = %s AND
216
                          TeamParticipation.team = ArchivePermission.person)
7118.2.11 by Julian Edwards
Fix merge bustage
217
            """ % sqlvalues(archive, person))
7118.2.2 by Julian Edwards
Add exported getPermissionsForUser on IArchive
218
10427.18.5 by Michael Nelson
Ensure that an iterable of archives can be used for componentsForQueueAdmin().
219
    def _componentsFor(self, archives, person, permission_type):
6269.6.1 by Julian Edwards
Switch upload rights checking to ArchivePermission.
220
        """Helper function to get ArchivePermission objects."""
10427.18.5 by Michael Nelson
Ensure that an iterable of archives can be used for componentsForQueueAdmin().
221
        if IArchive.providedBy(archives):
222
            archive_ids = [archives.id]
223
        else:
224
            archive_ids = [archive.id for archive in archives]
225
6269.6.1 by Julian Edwards
Switch upload rights checking to ArchivePermission.
226
        return ArchivePermission.select("""
10427.18.5 by Michael Nelson
Ensure that an iterable of archives can be used for componentsForQueueAdmin().
227
            ArchivePermission.archive IN %s AND
6269.6.1 by Julian Edwards
Switch upload rights checking to ArchivePermission.
228
            ArchivePermission.permission = %s AND
229
            ArchivePermission.component IS NOT NULL AND
230
            EXISTS (SELECT TeamParticipation.person
231
                    FROM TeamParticipation
232
                    WHERE TeamParticipation.person = %s AND
233
                          TeamParticipation.team = ArchivePermission.person)
10427.18.5 by Michael Nelson
Ensure that an iterable of archives can be used for componentsForQueueAdmin().
234
            """ % sqlvalues(archive_ids, permission_type, person),
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
235
            prejoins=["component"])
6269.6.1 by Julian Edwards
Switch upload rights checking to ArchivePermission.
236
7131.2.5 by Julian Edwards
salgado's review comments
237
    def componentsForUploader(self, archive, person):
6236.2.3 by Julian Edwards
Upload permission checking is now done via the ArchivePermission table.
238
        """See `IArchivePermissionSet`,"""
6269.6.1 by Julian Edwards
Switch upload rights checking to ArchivePermission.
239
        return self._componentsFor(
7131.2.5 by Julian Edwards
salgado's review comments
240
            archive, person, ArchivePermissionType.UPLOAD)
6236.2.3 by Julian Edwards
Upload permission checking is now done via the ArchivePermission table.
241
6141.1.6 by Julian Edwards
Add utility class and zcml.
242
    def uploadersForComponent(self, archive, component=None):
243
        "See `IArchivePermissionSet`."""
6236.2.9 by Julian Edwards
Curtis' review comments.
244
        clauses = ["""
245
            ArchivePermission.archive = %s AND
246
            ArchivePermission.permission = %s
7675.166.301 by Stuart Bishop
Replace In(col, i) with col.is_in(u) to work around Bug #670906 and delint
247
            """ % sqlvalues(archive, ArchivePermissionType.UPLOAD)]
6236.2.9 by Julian Edwards
Curtis' review comments.
248
6236.2.3 by Julian Edwards
Upload permission checking is now done via the ArchivePermission table.
249
        if component is not None:
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
250
            component = self._nameToComponent(component)
6236.2.9 by Julian Edwards
Curtis' review comments.
251
            clauses.append(
252
                "ArchivePermission.component = %s" % sqlvalues(component))
6236.2.3 by Julian Edwards
Upload permission checking is now done via the ArchivePermission table.
253
        else:
6236.2.9 by Julian Edwards
Curtis' review comments.
254
            clauses.append("ArchivePermission.component IS NOT NULL")
255
256
        query = " AND ".join(clauses)
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
257
        return ArchivePermission.select(query, prejoins=["component"])
6141.1.6 by Julian Edwards
Add utility class and zcml.
258
7131.2.5 by Julian Edwards
salgado's review comments
259
    def packagesForUploader(self, archive, person):
7118.2.2 by Julian Edwards
Add exported getPermissionsForUser on IArchive
260
        """See `IArchive`."""
261
        return ArchivePermission.select("""
262
            ArchivePermission.archive = %s AND
263
            ArchivePermission.permission = %s AND
264
            ArchivePermission.sourcepackagename IS NOT NULL AND
265
            EXISTS (SELECT TeamParticipation.person
266
                    FROM TeamParticipation
267
                    WHERE TeamParticipation.person = %s AND
268
                    TeamParticipation.team = ArchivePermission.person)
7131.2.5 by Julian Edwards
salgado's review comments
269
            """ % sqlvalues(archive, ArchivePermissionType.UPLOAD, person),
7118.2.2 by Julian Edwards
Add exported getPermissionsForUser on IArchive
270
            prejoins=["sourcepackagename"])
271
6141.1.6 by Julian Edwards
Add utility class and zcml.
272
    def uploadersForPackage(self, archive, sourcepackagename):
273
        "See `IArchivePermissionSet`."""
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
274
        sourcepackagename = self._nameToSourcePackageName(sourcepackagename)
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
275
        results = ArchivePermission.selectBy(
6141.1.6 by Julian Edwards
Add utility class and zcml.
276
            archive=archive, permission=ArchivePermissionType.UPLOAD,
277
            sourcepackagename=sourcepackagename)
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
278
        return results.prejoin(["sourcepackagename"])
6141.1.6 by Julian Edwards
Add utility class and zcml.
279
280
    def queueAdminsForComponent(self, archive, component):
281
        "See `IArchivePermissionSet`."""
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
282
        component = self._nameToComponent(component)
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
283
        results = ArchivePermission.selectBy(
6141.1.6 by Julian Edwards
Add utility class and zcml.
284
            archive=archive, permission=ArchivePermissionType.QUEUE_ADMIN,
285
            component=component)
6269.1.1 by Julian Edwards
Remove DistroComponentUploader.
286
        return results.prejoin(["component"])
6269.6.1 by Julian Edwards
Switch upload rights checking to ArchivePermission.
287
7131.2.5 by Julian Edwards
salgado's review comments
288
    def componentsForQueueAdmin(self, archive, person):
6269.6.1 by Julian Edwards
Switch upload rights checking to ArchivePermission.
289
        """See `IArchivePermissionSet`."""
290
        return self._componentsFor(
7131.2.5 by Julian Edwards
salgado's review comments
291
            archive, person, ArchivePermissionType.QUEUE_ADMIN)
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
292
7131.2.5 by Julian Edwards
salgado's review comments
293
    def newPackageUploader(self, archive, person, sourcepackagename):
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
294
        """See `IArchivePermissionSet`."""
295
        sourcepackagename = self._nameToSourcePackageName(sourcepackagename)
7118.2.14 by Julian Edwards
Ensure we can't create duplicate permissions.
296
        existing = self.checkAuthenticated(
297
            person, archive, ArchivePermissionType.UPLOAD, sourcepackagename)
12180.1.5 by Julian Edwards
Fix unnecessary .count()s in model/archivepermission.py
298
        try:
7118.2.14 by Julian Edwards
Ensure we can't create duplicate permissions.
299
            return existing[0]
12180.1.5 by Julian Edwards
Fix unnecessary .count()s in model/archivepermission.py
300
        except IndexError:
301
            return ArchivePermission(
302
                archive=archive, person=person,
303
                sourcepackagename=sourcepackagename,
304
                permission=ArchivePermissionType.UPLOAD)
7131.2.5 by Julian Edwards
salgado's review comments
305
306
    def newComponentUploader(self, archive, person, component):
307
        """See `IArchivePermissionSet`."""
308
        component = self._nameToComponent(component)
7118.2.14 by Julian Edwards
Ensure we can't create duplicate permissions.
309
        existing = self.checkAuthenticated(
310
            person, archive, ArchivePermissionType.UPLOAD, component)
12180.1.5 by Julian Edwards
Fix unnecessary .count()s in model/archivepermission.py
311
        try:
7118.2.14 by Julian Edwards
Ensure we can't create duplicate permissions.
312
            return existing[0]
12180.1.5 by Julian Edwards
Fix unnecessary .count()s in model/archivepermission.py
313
        except IndexError:
314
            return ArchivePermission(
315
                archive=archive, person=person, component=component,
316
                permission=ArchivePermissionType.UPLOAD)
7131.2.5 by Julian Edwards
salgado's review comments
317
318
    def newQueueAdmin(self, archive, person, component):
319
        """See `IArchivePermissionSet`."""
320
        component = self._nameToComponent(component)
7118.2.14 by Julian Edwards
Ensure we can't create duplicate permissions.
321
        existing = self.checkAuthenticated(
322
            person, archive, ArchivePermissionType.QUEUE_ADMIN, component)
12180.1.5 by Julian Edwards
Fix unnecessary .count()s in model/archivepermission.py
323
        try:
7118.2.14 by Julian Edwards
Ensure we can't create duplicate permissions.
324
            return existing[0]
12180.1.5 by Julian Edwards
Fix unnecessary .count()s in model/archivepermission.py
325
        except IndexError:
326
            return ArchivePermission(
327
                archive=archive, person=person, component=component,
328
                permission=ArchivePermissionType.QUEUE_ADMIN)
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
329
13765.2.1 by Benji York
permissions that are already removed can be removed again
330
    @staticmethod
331
    def _remove_permission(permission):
332
        if permission is None:
333
            # The permission has already been removed, so there's nothing more
334
            # to do here.
335
            return
336
        else:
337
            Store.of(permission).remove(permission)
338
7131.2.5 by Julian Edwards
salgado's review comments
339
    def deletePackageUploader(self, archive, person, sourcepackagename):
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
340
        """See `IArchivePermissionSet`."""
341
        sourcepackagename = self._nameToSourcePackageName(sourcepackagename)
342
        permission = ArchivePermission.selectOneBy(
7131.2.5 by Julian Edwards
salgado's review comments
343
            archive=archive, person=person,
344
            sourcepackagename=sourcepackagename,
345
            permission=ArchivePermissionType.UPLOAD)
13765.2.1 by Benji York
permissions that are already removed can be removed again
346
        self._remove_permission(permission)
7131.2.5 by Julian Edwards
salgado's review comments
347
348
    def deleteComponentUploader(self, archive, person, component):
349
        """See `IArchivePermissionSet`."""
350
        component = self._nameToComponent(component)
351
        permission = ArchivePermission.selectOneBy(
352
            archive=archive, person=person, component=component,
353
            permission=ArchivePermissionType.UPLOAD)
13765.2.1 by Benji York
permissions that are already removed can be removed again
354
        self._remove_permission(permission)
7131.2.5 by Julian Edwards
salgado's review comments
355
356
    def deleteQueueAdmin(self, archive, person, component):
357
        """See `IArchivePermissionSet`."""
358
        component = self._nameToComponent(component)
359
        permission = ArchivePermission.selectOneBy(
360
            archive=archive, person=person, component=component,
7118.2.8 by Julian Edwards
Add ArchivePermissionSet methods to add and delete permissions
361
            permission=ArchivePermissionType.QUEUE_ADMIN)
13765.2.1 by Benji York
permissions that are already removed can be removed again
362
        self._remove_permission(permission)
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
363
364
    def _nameToPackageset(self, packageset):
365
        """Helper to convert a possible string name to IPackageset."""
366
        if isinstance(packageset, basestring):
7675.361.3 by Muharem Hrnjadovic
If a package set *name* is used in conjunction with archive permissions the respective package set in the current distro series will be used.
367
            # A package set name was passed, assume the current distro series.
368
            ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
369
            name = packageset
8903.1.2 by Muharem Hrnjadovic
minor fix.
370
            store = IStore(Packageset)
7675.361.3 by Muharem Hrnjadovic
If a package set *name* is used in conjunction with archive permissions the respective package set in the current distro series will be used.
371
            packageset = store.find(
372
                Packageset, name=name,
373
                distroseries=ubuntu.currentseries).one()
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
374
            if packageset is not None:
375
                return packageset
376
            else:
377
                raise NotFoundError("No such package set '%s'" % name)
7675.134.6 by Muharem Hrnjadovic
Brad's review comments
378
        elif IPackageset.providedBy(packageset):
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
379
            return packageset
7675.134.6 by Muharem Hrnjadovic
Brad's review comments
380
        else:
381
            raise ValueError(
382
                'Not a package set: %s' % _extract_type_name(packageset))
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
383
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
384
    def packagesetsForUploader(self, archive, person):
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
385
        """See `IArchivePermissionSet`."""
386
        store = IStore(ArchivePermission)
387
        query = '''
388
            SELECT ap.id
389
            FROM archivepermission ap, teamparticipation tp
390
            WHERE
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
391
                ap.person = tp.team AND tp.person = ?
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
392
                AND ap.archive = ?
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
393
                AND ap.packageset IS NOT NULL
394
        '''
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
395
        query = SQL(query, (person.id, archive.id))
7675.166.301 by Stuart Bishop
Replace In(col, i) with col.is_in(u) to work around Bug #670906 and delint
396
        return store.find(
397
            ArchivePermission, ArchivePermission.id.is_in(query))
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
398
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
399
    def uploadersForPackageset(
400
        self, archive, packageset, direct_permissions=True):
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
401
        """See `IArchivePermissionSet`."""
402
        packageset = self._nameToPackageset(packageset)
403
        store = IStore(ArchivePermission)
7675.134.2 by Muharem Hrnjadovic
added tests for package set based ACL changes.
404
        if direct_permissions == True:
405
            query = '''
406
                SELECT ap.id FROM archivepermission ap WHERE ap.packageset = ?
407
            '''
408
        else:
409
            query = '''
410
                SELECT ap.id
411
                FROM archivepermission ap, flatpackagesetinclusion fpsi
412
                WHERE fpsi.child = ? AND ap.packageset = fpsi.parent
413
            '''
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
414
        query += " AND ap.archive = ?"
415
        query = SQL(query, (packageset.id, archive.id))
7675.166.301 by Stuart Bishop
Replace In(col, i) with col.is_in(u) to work around Bug #670906 and delint
416
        return store.find(
417
            ArchivePermission, ArchivePermission.id.is_in(query))
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
418
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
419
    def newPackagesetUploader(
420
        self, archive, person, packageset, explicit=False):
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
421
        """See `IArchivePermissionSet`."""
422
        packageset = self._nameToPackageset(packageset)
423
        store = IMasterStore(ArchivePermission)
424
425
        # First see whether we have a matching permission in the database
426
        # already.
7675.140.1 by Muharem Hrnjadovic
Made the creation of package set based permissions more robust.
427
        query = '''
428
            SELECT ap.id
429
            FROM archivepermission ap, teamparticipation tp
430
            WHERE
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
431
                ap.person = tp.team AND tp.person = ?
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
432
                AND ap.packageset = ? AND ap.archive = ?
7675.140.1 by Muharem Hrnjadovic
Made the creation of package set based permissions more robust.
433
        '''
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
434
        query = SQL(query, (person.id, packageset.id, archive.id))
7675.140.1 by Muharem Hrnjadovic
Made the creation of package set based permissions more robust.
435
        permissions = list(
7675.166.301 by Stuart Bishop
Replace In(col, i) with col.is_in(u) to work around Bug #670906 and delint
436
            store.find(
437
                ArchivePermission, ArchivePermission.id.is_in(query)))
7675.140.1 by Muharem Hrnjadovic
Made the creation of package set based permissions more robust.
438
        if len(permissions) > 0:
439
            # Found permissions in the database, does the 'explicit' flag
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
440
            # have the requested value?
7675.140.1 by Muharem Hrnjadovic
Made the creation of package set based permissions more robust.
441
            conflicting = [permission for permission in permissions
442
                           if permission.explicit != explicit]
443
            if len(conflicting) > 0:
444
                # At least one permission with conflicting 'explicit' flag
445
                # value exists already.
446
                cperm = conflicting[0]
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
447
                raise ValueError(
7675.140.1 by Muharem Hrnjadovic
Made the creation of package set based permissions more robust.
448
                    "Permission for package set '%s' already exists for %s "
449
                    "but with a different 'explicit' flag value (%s)." %
450
                    (packageset.name, cperm.person.name, cperm.explicit))
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
451
            else:
7675.140.1 by Muharem Hrnjadovic
Made the creation of package set based permissions more robust.
452
                # No conflicts, does the requested permission exist already?
453
                existing = [permission for permission in permissions
454
                            if (permission.explicit == explicit and
455
                                permission.person == person and
456
                                permission.packageset == packageset)]
457
                assert len(existing) <= 1, (
458
                    "Too many permissions for %s and %s" %
459
                    (person.name, packageset.name))
460
                if len(existing) == 1:
461
                    # The existing permission matches, just return it.
462
                    return existing[0]
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
463
464
        # The requested permission does not exist yet. Insert it into the
465
        # database.
466
        permission = ArchivePermission(
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
467
            archive=archive,
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
468
            person=person, packageset=packageset,
469
            permission=ArchivePermissionType.UPLOAD, explicit=explicit)
470
        store.add(permission)
471
472
        return permission
473
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
474
    def deletePackagesetUploader(
475
        self, archive, person, packageset, explicit=False):
7675.134.1 by Muharem Hrnjadovic
"imported" package set based ACL changes.
476
        """See `IArchivePermissionSet`."""
477
        packageset = self._nameToPackageset(packageset)
478
        store = IMasterStore(ArchivePermission)
479
480
        # Do we have the permission the user wants removed in the database?
481
        permission = store.find(
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
482
            ArchivePermission, archive=archive, person=person,
483
            packageset=packageset, permission=ArchivePermissionType.UPLOAD,
484
            explicit=explicit).one()
13765.2.1 by Benji York
permissions that are already removed can be removed again
485
        self._remove_permission(permission)
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
486
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
487
    def packagesetsForSourceUploader(
488
        self, archive, sourcepackagename, person):
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
489
        """See `IArchivePermissionSet`."""
490
        sourcepackagename = self._nameToSourcePackageName(sourcepackagename)
491
        store = IStore(ArchivePermission)
492
        query = '''
493
            SELECT ap.id
494
            FROM
495
                archivepermission ap, teamparticipation tp,
496
                packagesetsources pss, flatpackagesetinclusion fpsi
497
            WHERE
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
498
                ap.person = tp.team AND tp.person = ?
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
499
                AND ap.packageset = fpsi.parent
500
                AND pss.packageset = fpsi.child
501
                AND pss.sourcepackagename = ?
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
502
                AND ap.archive = ?
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
503
        '''
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
504
        query = SQL(
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
505
            query, (person.id, sourcepackagename.id, archive.id))
7675.166.301 by Stuart Bishop
Replace In(col, i) with col.is_in(u) to work around Bug #670906 and delint
506
        return store.find(
507
            ArchivePermission, ArchivePermission.id.is_in(query))
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
508
8903.2.1 by Muharem Hrnjadovic
added packagesetsForSource() method
509
    def packagesetsForSource(
510
        self, archive, sourcepackagename, direct_permissions=True):
511
        """See `IArchivePermissionSet`."""
512
        sourcepackagename = self._nameToSourcePackageName(sourcepackagename)
513
        store = IStore(ArchivePermission)
8903.2.2 by Muharem Hrnjadovic
Edwin's review comments
514
8903.2.1 by Muharem Hrnjadovic
added packagesetsForSource() method
515
        if direct_permissions:
8903.2.2 by Muharem Hrnjadovic
Edwin's review comments
516
            origin = SQL('ArchivePermission, PackagesetSources')
517
            rset = store.using(origin).find(ArchivePermission, SQL('''
518
                ArchivePermission.packageset = PackagesetSources.packageset
519
                AND PackagesetSources.sourcepackagename = ?
520
                AND ArchivePermission.archive = ?
521
                ''', (sourcepackagename.id, archive.id)))
8903.2.1 by Muharem Hrnjadovic
added packagesetsForSource() method
522
        else:
8903.2.2 by Muharem Hrnjadovic
Edwin's review comments
523
            origin = SQL(
524
                'ArchivePermission, PackagesetSources, '
525
                'FlatPackagesetInclusion')
526
            rset = store.using(origin).find(ArchivePermission, SQL('''
527
                ArchivePermission.packageset = FlatPackagesetInclusion.parent
528
                AND PackagesetSources.packageset =
529
                    FlatPackagesetInclusion.child
530
                AND PackagesetSources.sourcepackagename = ?
531
                AND ArchivePermission.archive = ?
532
                ''', (sourcepackagename.id, archive.id)))
533
        return rset
8903.2.1 by Muharem Hrnjadovic
added packagesetsForSource() method
534
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
535
    def isSourceUploadAllowed(
536
        self, archive, sourcepackagename, person, distroseries=None):
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
537
        """See `IArchivePermissionSet`."""
538
        sourcepackagename = self._nameToSourcePackageName(sourcepackagename)
539
        store = IStore(ArchivePermission)
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
540
        if distroseries is None:
541
            ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
542
            distroseries = ubuntu.currentseries
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
543
544
        # Put together the parameters for the query that follows.
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
545
        archive_params = (ArchivePermissionType.UPLOAD, archive.id)
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
546
        permission_params = (sourcepackagename.id, person.id, distroseries.id)
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
547
        query_params = (
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
548
            # Query parameters for the first WHERE clause.
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
549
            (archive.id, distroseries.id, sourcepackagename.id) +
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
550
            # Query parameters for the second WHERE clause.
10427.18.5 by Michael Nelson
Ensure that an iterable of archives can be used for componentsForQueueAdmin().
551
            permission_params + archive_params +
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
552
            # Query parameters for the third WHERE clause.
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
553
            permission_params + archive_params)
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
554
555
        query = '''
556
        SELECT CASE
557
          WHEN (
558
            SELECT COUNT(ap.id)
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
559
            FROM packagesetsources pss, archivepermission ap, packageset ps
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
560
            WHERE
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
561
              ap.archive = %s AND ap.explicit = TRUE
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
562
              AND ap.packageset = ps.id AND ps.distroseries = %s
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
563
              AND pss.sourcepackagename = %s
564
              AND pss.packageset = ap.packageset) > 0
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
565
          THEN (
566
            SELECT COUNT(ap.id)
567
            FROM
10427.18.5 by Michael Nelson
Ensure that an iterable of archives can be used for componentsForQueueAdmin().
568
              packagesetsources pss, archivepermission ap, packageset ps,
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
569
              teamparticipation tp
570
            WHERE
571
              pss.sourcepackagename = %s
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
572
              AND ap.person = tp.team AND tp.person = %s
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
573
              AND ap.packageset = ps.id AND ps.distroseries = %s
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
574
              AND pss.packageset = ap.packageset AND ap.explicit = TRUE
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
575
              AND ap.permission = %s AND ap.archive = %s)
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
576
          ELSE (
577
            SELECT COUNT(ap.id)
578
            FROM
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
579
              packagesetsources pss, archivepermission ap, packageset ps,
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
580
              teamparticipation tp, flatpackagesetinclusion fpsi
581
            WHERE
582
              pss.sourcepackagename = %s
7675.275.1 by Muharem Hrnjadovic
Fixes broken ArchivePermission queries.
583
              AND ap.person = tp.team AND tp.person = %s
7675.366.1 by Muharem Hrnjadovic
Archive permission checks now observe the distro series.
584
              AND ap.packageset = ps.id AND ps.distroseries = %s
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
585
              AND pss.packageset = fpsi.child AND fpsi.parent = ap.packageset
8823.1.1 by Muharem Hrnjadovic
package set related IArchivePermission methods now take an explicit 'archive' parameter as opposed to being hard-coded to the Ubuntu main archive.
586
              AND ap.permission = %s AND ap.archive = %s)
7675.140.3 by Muharem Hrnjadovic
added method that checks upload package set based upload permissions: isSourceUploadAllowed().
587
        END AS number_of_permitted_package_sets;
588
589
        ''' % sqlvalues(*query_params)
590
        return store.execute(query).get_one()[0] > 0