1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
|
= Entitlements =
Entitlements are a means of recording features and privileges
Launchpad users have been assigned. The business model for these
assignments is not important, but it could be through a commercial
arrangement or through a grant that applies to everyone.
>>> from datetime import datetime
>>> import pytz
>>> from canonical.database.sqlbase import flush_database_updates
>>> from canonical.launchpad.ftests import login
>>> from canonical.launchpad.webapp.testing import verifyObject
>>> from lp.registry.interfaces.entitlement import (
... EntitlementQuota,
... EntitlementState,
... EntitlementType,
... IEntitlement,
... IEntitlementSet,
... )
>>> from lp.registry.interfaces.person import IPersonSet
The logged in user must be an admin in order to change the quota.
>>> from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
>>> login("foo.bar@canonical.com")
>>> foobar = getUtility(ILaunchBag).user
>>> lp_admins = getUtility(ILaunchpadCelebrities).admin
>>> foobar.inTeam(lp_admins)
True
>>> entitlements = getUtility(IEntitlementSet)
>>> entitlements_in_sample_data = entitlements.count()
Find a team with an entitlement.
>>> personset = getUtility(IPersonSet)
>>> ubuntu_team = personset.getByName('ubuntu-team')
An entitlement grants privilege to use a restricted feature. The
'quota' is the number of instances being granted and the
entitlement_type is the feature being enabled. The 'person' is the
person or team being granted the right. The state for a granted
entitlement is ACTIVE and the expiration and start dates can be specified.
>>> UTC = pytz.timezone('UTC')
>>> entitlement = getUtility(IEntitlementSet).new(
... quota=5,
... entitlement_type=EntitlementType.PRIVATE_BUGS,
... person=ubuntu_team,
... state=EntitlementState.ACTIVE,
... date_expires=datetime(2038, 6, 11, tzinfo=UTC),
... amount_used=0)
>>> verifyObject(IEntitlement, entitlement)
True
The person can be accessed and shown to be correct.
>>> print entitlement.person.name
ubuntu-team
If the current date is after the start date (if not None) or before
the expiration date (if not None) then the in_date_range test will
pass.
>>> entitlement.in_date_range
True
== Quota checking ==
If the amount used is less than the quota value the exceeded_quota
test will be false.
>>> entitlement.quota = 100
>>> entitlement.amount_used = 0
>>> entitlement.exceeded_quota
False
The quota is not exceeded, the date is in range, and the state is
ACTIVE, so the entitlement is valid.
>>> entitlement.is_valid
True
If the amount used is equal to the quota 'exceeded_quota' should still
be false and 'is_valid' is still true.
>>> entitlement.quota = 100
>>> entitlement.amount_used = 100
>>> entitlement.exceeded_quota
False
>>> entitlement.is_valid
True
However if the amount_used to exceeds the quota, the exceeded quota is
true and the entitlement is no longer valid.
>>> entitlement.quota = 100
>>> entitlement.amount_used = 101
>>> entitlement.exceeded_quota
True
>>> entitlement.is_valid
False
If the quota is UNLIMITED the exceeded quota test is false even when
using a really large value for amount used. The entitlement remains
valid.
We use math.pow here, since __builtin__.pow is overridden by twisted.conch.
>>> import math
>>> entitlement.quota = EntitlementQuota.UNLIMITED
>>> entitlement.amount_used = math.pow(10,9)
>>> entitlement.exceeded_quota
False
>>> entitlement.is_valid
True
Calling incrementAmountUsed increases the value by one.
>>> entitlement.quota = 10
>>> entitlement.amount_used = 9
>>> entitlement.incrementAmountUsed()
>>> entitlement.amount_used
10
Attempting to increment past the quota will cause an error.
>>> entitlement.incrementAmountUsed()
Traceback (most recent call last):
...
EntitlementQuotaExceededError: ...
If the entitlement is invalid for any reason, attempting to increment
the amount used will cause an error.
>>> entitlement.state = EntitlementState.INACTIVE
>>> entitlement.quota = 50
>>> entitlement.incrementAmountUsed()
Traceback (most recent call last):
...
EntitlementInvalidError: ...
== Date range checking ==
The 'in_date_range' attribute can be used to tell whether the
entitlement is valid with respect to the start date and expires date.
When the current date is out of range the entitlement is considered
invalid.
When the entitlement does not have a start date or an expiration date
then those values are not checked. If no start date is given the
expiration date is still used, and vice versa. If both start date and
expiration date are None then no date range checking is performed and
the entitlement is valid with respect to dates.
Remove the start and expiration dates and the date range will be
valid.
>>> entitlement.state = EntitlementState.ACTIVE
>>> entitlement.date_starts = None
>>> entitlement.date_expires = None
>>> entitlement.in_date_range
True
>>> entitlement.is_valid
True
>>> from datetime import datetime, timedelta
>>> from pytz import UTC
>>> now = datetime.now(UTC)
>>> yesterday = now - timedelta(days = 1)
>>> tomorrow = now + timedelta(days = 1)
If the start date is in the past and the expiration date is not set
this condition is considered an open-ended entitlement and we are
still in its range.
>>> entitlement.date_starts = yesterday
>>> entitlement.in_date_range
True
>>> entitlement.is_valid
True
If the start date is in the future the date is not in range and the
entitlement is invalid.
>>> entitlement.date_starts = tomorrow
>>> entitlement.in_date_range
False
>>> entitlement.is_valid
False
If the expires date is in the past, we are not in its date range and
the entitlement is not valid.
>>> entitlement.date_starts = None
>>> entitlement.date_expires = yesterday
>>> entitlement.in_date_range
False
>>> entitlement.is_valid
False
If the expiration date is in the future the date range is satisfied
and the entitlement is valid.
>>> entitlement.date_expires = tomorrow
>>> entitlement.in_date_range
True
>>> entitlement.is_valid
True
If the start date is in the past and the expires date is in the future
the date range is again satisfied and the entitlement is valid.
>>> entitlement.date_starts = yesterday
>>> entitlement.date_expires = tomorrow
>>> entitlement.in_date_range
True
>>> entitlement.is_valid
True
== Security ==
Viewing the entitlement's attributes is restricted to the
entitlement's owner, the entitlement's registrant (or to a member of
these teams), and to Launchpad administrators.
If logged in as an anonymous user the entitlement values cannot be
viewed. A security-wrapped entitlement must be used to exercise the
security adapters.
>>> entitlement = ubuntu_team.entitlements[0]
>>> entitlement.quota = 50
>>> logout()
>>> login(ANONYMOUS)
>>> entitlement.quota
Traceback (most recent call last):
...
Unauthorized: (<Entitlement..., 'quota', 'launchpad.View')
>>> entitlement.quota=10
Traceback (most recent call last):
...
Unauthorized: (<Entitlement..., 'quota', 'launchpad.Admin')
>>> logout()
Authenticated Launchpad users who are not the owner or team member are
similarly restricted.
>>> login('no-priv@canonical.com')
>>> entitlement.quota
Traceback (most recent call last):
...
Unauthorized: (<Entitlement..., 'quota', 'launchpad.View')
>>> entitlement.quota=10
Traceback (most recent call last):
...
Unauthorized: (<Entitlement..., 'quota', 'launchpad.Admin')
Add the current user to the team and the user can now access
attributes. Since ubuntu-team is restricted, an administrator must be
listed as a reviewer for the membership to go through.
>>> from lp.registry.interfaces.teammembership import TeamMembershipStatus
>>> nopriv = getUtility(ILaunchBag).user
>>> mark = personset.getByName('mark')
>>> nopriv.join(ubuntu_team)
# Login as the team's owner in order to be able to change its memberships.
>>> login(ubuntu_team.teamowner.preferredemail.email)
>>> ubuntu_team.setMembershipData(nopriv, TeamMembershipStatus.APPROVED, mark)
>>> login('no-priv@canonical.com')
>>> flush_database_updates()
>>> nopriv in ubuntu_team.activemembers
True
>>> nopriv.inTeam(ubuntu_team)
True
>>> entitlement.quota
50
>>> entitlement.quota=10
Traceback (most recent call last):
...
Unauthorized: (<Entitlement..., 'quota', 'launchpad.Admin')
= EntitlementSet =
All of the entitlements can be obtained using IEntitlementSet.
>>> login("foo.bar@canonical.com")
>>> entitlements = getUtility(IEntitlementSet)
One entitlement was created in the previous examples.
>>> entitlements.count() - entitlements_in_sample_data
1
To look up an entitlement from the set, simply use the 'get' with the id.
>>> entitlement2 = entitlements.get(entitlement.id)
>>> entitlement2.id == entitlement.id
True
Get all of the valid entitlements for ubuntu_team.
>>> valid_list = getUtility(IEntitlementSet).getValidForPerson(ubuntu_team)
>>> len(valid_list)
1
A new entitlement for the ubuntu_team can be created, increasing the
number of valid entitlements.
>>> entitlement = getUtility(IEntitlementSet).new(
... quota=50,
... entitlement_type=EntitlementType.PRIVATE_BRANCHES,
... person=ubuntu_team,
... state=EntitlementState.ACTIVE,
... date_expires=datetime(2038, 6, 11, tzinfo=UTC),
... amount_used=0)
>>> valid_list = getUtility(IEntitlementSet).getValidForPerson(ubuntu_team)
>>> len(valid_list)
2
Setting the original entitlement to INACTIVE will now reduce the
number of valid entitlements.
>>> entitlement.state = EntitlementState.INACTIVE
>>> valid_list = getUtility(IEntitlementSet).getValidForPerson(ubuntu_team)
>>> len(valid_list)
1
|