~launchpad-pqm/launchpad/devel

14186.6.3 by William Grant
Add basic model and interfaces.
1
# Copyright 2011 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
4
"""Model classes for pillar and artifact access policies."""
5
6
__metaclass__ = type
7
__all__ = [
8
    'AccessPolicy',
9
    'AccessPolicyArtifact',
14186.6.20 by William Grant
Fix tests by renaming AccessPolicyPermission to AccessPolicyGrant.
10
    'AccessPolicyGrant',
14186.6.3 by William Grant
Add basic model and interfaces.
11
    ]
12
14186.6.28 by William Grant
Fix stuff.
13
from storm.properties import (
14
    Int,
15
    DateTime,
16
    )
14186.6.35 by William Grant
Drop AP.grants for now.
17
from storm.references import Reference
18
from zope.interface import implements
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
19
14186.6.24 by William Grant
AccessPolicy model updated, replacing name/displayname with type.
20
from canonical.database.enumcol import DBEnum
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
21
from canonical.launchpad.interfaces.lpstorm import IStore
22
from lp.registry.interfaces.accesspolicy import (
14186.6.24 by William Grant
AccessPolicy model updated, replacing name/displayname with type.
23
    AccessPolicyType,
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
24
    IAccessPolicy,
25
    IAccessPolicyArtifact,
14186.6.20 by William Grant
Fix tests by renaming AccessPolicyPermission to AccessPolicyGrant.
26
    IAccessPolicyGrant,
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
27
    )
14186.6.3 by William Grant
Add basic model and interfaces.
28
from lp.services.database.stormbase import StormBase
29
30
31
class AccessPolicy(StormBase):
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
32
    implements(IAccessPolicy)
33
14186.6.3 by William Grant
Add basic model and interfaces.
34
    __storm_table__ = 'AccessPolicy'
35
36
    id = Int(primary=True)
37
    product_id = Int(name='product')
38
    product = Reference(product_id, 'Product.id')
39
    distribution_id = Int(name='distribution')
40
    distribution = Reference(distribution_id, 'Distribution.id')
14186.6.24 by William Grant
AccessPolicy model updated, replacing name/displayname with type.
41
    type = DBEnum(allow_none=True, enum=AccessPolicyType)
14186.6.3 by William Grant
Add basic model and interfaces.
42
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
43
    @property
44
    def pillar(self):
45
        return self.product or self.distribution
46
47
    @classmethod
14186.6.24 by William Grant
AccessPolicy model updated, replacing name/displayname with type.
48
    def create(cls, pillar, type):
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
49
        from lp.registry.interfaces.distribution import IDistribution
50
        from lp.registry.interfaces.product import IProduct
51
        obj = cls()
52
        if IProduct.providedBy(pillar):
53
            obj.product = pillar
54
        elif IDistribution.providedBy(pillar):
55
            obj.distribution = pillar
14186.6.36 by William Grant
Die if creating an AP for a non-pillar.
56
        else:
14186.6.43 by William Grant
AssertionError->ValueError by review
57
            raise ValueError("%r is not a supported pillar" % pillar)
14186.6.24 by William Grant
AccessPolicy model updated, replacing name/displayname with type.
58
        obj.type = type
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
59
        IStore(cls).add(obj)
60
        return obj
61
62
    @classmethod
63
    def _constraintForPillar(cls, pillar):
64
        from lp.registry.interfaces.distribution import IDistribution
65
        from lp.registry.interfaces.product import IProduct
66
        if IProduct.providedBy(pillar):
67
            col = cls.product
68
        elif IDistribution.providedBy(pillar):
69
            col = cls.distribution
70
        else:
14186.6.43 by William Grant
AssertionError->ValueError by review
71
            raise ValueError("%r is not a supported pillar" % pillar)
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
72
        return col == pillar
73
74
    @classmethod
75
    def getByID(cls, id):
76
        """See `IAccessPolicySource`."""
77
        return IStore(cls).get(cls, id)
78
79
    @classmethod
80
    def findByPillar(cls, pillar):
81
        """See `IAccessPolicySource`."""
82
        return IStore(cls).find(cls, cls._constraintForPillar(pillar))
83
84
    @classmethod
14186.6.24 by William Grant
AccessPolicy model updated, replacing name/displayname with type.
85
    def getByPillarAndType(cls, pillar, type):
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
86
        """See `IAccessPolicySource`."""
14186.6.24 by William Grant
AccessPolicy model updated, replacing name/displayname with type.
87
        return cls.findByPillar(pillar).find(type=type).one()
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
88
14186.6.3 by William Grant
Add basic model and interfaces.
89
90
class AccessPolicyArtifact(StormBase):
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
91
    implements(IAccessPolicyArtifact)
92
14186.6.3 by William Grant
Add basic model and interfaces.
93
    __storm_table__ = 'AccessPolicyArtifact'
94
95
    id = Int(primary=True)
96
    bug_id = Int(name='bug')
97
    bug = Reference(bug_id, 'Bug.id')
98
    branch_id = Int(name='branch')
99
    branch = Reference(branch_id, 'Branch.id')
14186.6.30 by William Grant
APA.policy
100
    policy_id = Int(name='policy')
101
    policy = Reference(policy_id, 'AccessPolicy.id')
14186.6.3 by William Grant
Add basic model and interfaces.
102
103
    @property
104
    def concrete_artifact(self):
105
        artifact = self.bug or self.branch
106
        assert artifact is not None
107
        return artifact
108
14186.6.9 by William Grant
ensure() now returns an existing object if it exists.
109
    @staticmethod
110
    def _getConcreteAttribute(concrete_artifact):
14186.6.7 by William Grant
Initial IAccessPolicyArtifactSource implementation.
111
        from lp.bugs.interfaces.bug import IBug
112
        from lp.code.interfaces.branch import IBranch
113
        if IBug.providedBy(concrete_artifact):
14186.6.9 by William Grant
ensure() now returns an existing object if it exists.
114
            return 'bug'
14186.6.7 by William Grant
Initial IAccessPolicyArtifactSource implementation.
115
        elif IBranch.providedBy(concrete_artifact):
14186.6.9 by William Grant
ensure() now returns an existing object if it exists.
116
            return 'branch'
14186.6.8 by William Grant
Break if the artifact is invalid.
117
        else:
14186.6.43 by William Grant
AssertionError->ValueError by review
118
            raise ValueError(
14186.6.8 by William Grant
Break if the artifact is invalid.
119
                "%r is not a valid artifact" % concrete_artifact)
14186.6.9 by William Grant
ensure() now returns an existing object if it exists.
120
121
    @classmethod
14186.6.38 by William Grant
APAS.get.
122
    def get(cls, concrete_artifact):
14186.6.9 by William Grant
ensure() now returns an existing object if it exists.
123
        """See `IAccessPolicyArtifactSource`."""
124
        constraints = {
125
            cls._getConcreteAttribute(concrete_artifact): concrete_artifact}
14186.6.38 by William Grant
APAS.get.
126
        return IStore(cls).find(cls, **constraints).one()
127
128
    @classmethod
129
    def ensure(cls, concrete_artifact):
130
        """See `IAccessPolicyArtifactSource`."""
131
        existing = cls.get(concrete_artifact)
14186.6.9 by William Grant
ensure() now returns an existing object if it exists.
132
        if existing is not None:
133
            return existing
134
        # No existing object. Create a new one.
135
        obj = cls()
136
        setattr(
137
            obj, cls._getConcreteAttribute(concrete_artifact),
138
            concrete_artifact)
14186.6.7 by William Grant
Initial IAccessPolicyArtifactSource implementation.
139
        IStore(cls).add(obj)
140
        return obj
141
14186.6.37 by William Grant
APA/APG deletion.
142
    @classmethod
143
    def delete(cls, concrete_artifact):
144
        """See `IAccessPolicyArtifactSource`."""
14186.6.40 by William Grant
APAS.delete() uses get, not ensure.
145
        abstract = cls.get(concrete_artifact)
146
        if abstract is None:
147
            return
14186.6.37 by William Grant
APA/APG deletion.
148
        IStore(abstract).find(
149
            AccessPolicyGrant, abstract_artifact=abstract).remove()
150
        IStore(abstract).find(AccessPolicyArtifact, id=abstract.id).remove()
151
14186.6.3 by William Grant
Add basic model and interfaces.
152
14186.6.20 by William Grant
Fix tests by renaming AccessPolicyPermission to AccessPolicyGrant.
153
class AccessPolicyGrant(StormBase):
154
    implements(IAccessPolicyGrant)
14186.6.6 by William Grant
Implement IAccessPolicySource, add tests, factory stuff too.
155
14186.6.20 by William Grant
Fix tests by renaming AccessPolicyPermission to AccessPolicyGrant.
156
    __storm_table__ = 'AccessPolicyGrant'
14186.6.3 by William Grant
Add basic model and interfaces.
157
158
    id = Int(primary=True)
14186.6.32 by William Grant
Complete the rename.
159
    grantee_id = Int(name='grantee')
160
    grantee = Reference(grantee_id, 'Person.id')
14186.6.3 by William Grant
Add basic model and interfaces.
161
    policy_id = Int(name='policy')
162
    policy = Reference(policy_id, 'AccessPolicy.id')
163
    abstract_artifact_id = Int(name='artifact')
164
    abstract_artifact = Reference(
165
        abstract_artifact_id, 'AccessPolicyArtifact.id')
14186.6.32 by William Grant
Complete the rename.
166
    grantor_id = Int(name='grantor')
167
    grantor = Reference(grantor_id, 'Person.id')
14186.6.28 by William Grant
Fix stuff.
168
    date_created = DateTime()
14186.6.3 by William Grant
Add basic model and interfaces.
169
170
    @property
171
    def concrete_artifact(self):
172
        if self.abstract_artifact is not None:
173
            return self.abstract_artifact.concrete_artifact
14186.6.12 by William Grant
IAccessPolicyPermissionSource, with grant() implemented and various tests.
174
175
    @classmethod
14186.6.28 by William Grant
Fix stuff.
176
    def grant(cls, grantee, grantor, object):
14186.6.20 by William Grant
Fix tests by renaming AccessPolicyPermission to AccessPolicyGrant.
177
        """See `IAccessPolicyGrantSource`."""
14186.6.28 by William Grant
Fix stuff.
178
        grant = cls()
14186.6.32 by William Grant
Complete the rename.
179
        grant.grantee = grantee
180
        grant.grantor = grantor
14186.6.28 by William Grant
Fix stuff.
181
        if IAccessPolicy.providedBy(object):
182
            grant.policy = object
183
        elif IAccessPolicyArtifact.providedBy(object):
184
            grant.abstract_artifact = object
185
        else:
14186.6.43 by William Grant
AssertionError->ValueError by review
186
            raise ValueError("Unsupported object: %r" % object)
14186.6.28 by William Grant
Fix stuff.
187
        IStore(cls).add(grant)
188
        return grant
14186.6.14 by William Grant
getByID.
189
190
    @classmethod
191
    def getByID(cls, id):
14186.6.20 by William Grant
Fix tests by renaming AccessPolicyPermission to AccessPolicyGrant.
192
        """See `IAccessPolicyGrantSource`."""
14186.6.14 by William Grant
getByID.
193
        return IStore(cls).get(cls, id)
14186.6.15 by William Grant
findByPolicy. tests now pass.
194
195
    @classmethod
196
    def findByPolicy(cls, policy):
14186.6.20 by William Grant
Fix tests by renaming AccessPolicyPermission to AccessPolicyGrant.
197
        """See `IAccessPolicyGrantSource`."""
14186.6.15 by William Grant
findByPolicy. tests now pass.
198
        return IStore(cls).find(cls, policy=policy)