Merge ~pappacena/launchpad:snap-pillar-subscribe-removal-job into launchpad:master
- Git
- lp:~pappacena/launchpad
- snap-pillar-subscribe-removal-job
- Merge into master
Status: | Superseded | ||||
---|---|---|---|---|---|
Proposed branch: | ~pappacena/launchpad:snap-pillar-subscribe-removal-job | ||||
Merge into: | launchpad:master | ||||
Prerequisite: | ~pappacena/launchpad:snap-pillar-subscribe | ||||
Diff against target: |
890 lines (+199/-85) 16 files modified
database/schema/security.cfg (+2/-0) lib/lp/blueprints/model/specification.py (+2/-2) lib/lp/blueprints/tests/test_specification.py (+4/-4) lib/lp/bugs/model/bug.py (+3/-3) lib/lp/code/browser/branchsubscription.py (+2/-2) lib/lp/code/browser/gitsubscription.py (+2/-2) lib/lp/code/model/branch.py (+2/-2) lib/lp/code/model/gitrepository.py (+1/-1) lib/lp/code/model/tests/test_branchsubscription.py (+3/-3) lib/lp/registry/model/sharingjob.py (+36/-1) lib/lp/registry/services/sharingservice.py (+15/-12) lib/lp/registry/services/tests/test_sharingservice.py (+11/-7) lib/lp/registry/tests/test_sharingjob.py (+56/-10) lib/lp/snappy/interfaces/snap.py (+4/-0) lib/lp/snappy/model/snap.py (+36/-12) lib/lp/snappy/tests/test_snap.py (+20/-24) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Review via email: mp+398318@code.launchpad.net |
This proposal has been superseded by a proposal from 2021-03-11.
Commit message
Remove dangling SnapSubscription when changing Snap pillar's sharing policy
Description of the change
Thiago F. Pappacena (pappacena) : | # |
Colin Watson (cjwatson) : | # |
- 6ead4b4... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job - 96846ab... by Thiago F. Pappacena
-
Fixing snap privacy filter usage
- be29706... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job - 0efaed4... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job - d256e68... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job
Colin Watson (cjwatson) : | # |
- 76b720d... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job - e857291... by Thiago F. Pappacena
-
Refactoring and setting proper db permission for job
Thiago F. Pappacena (pappacena) wrote : | # |
Colin Watson (cjwatson) : | # |
- 920b88c... by Thiago F. Pappacena
-
Not granting commercial admin view permisson on every snap
Thiago F. Pappacena (pappacena) wrote : | # |
Pushed the changes for admin visibility after talking to wgrant and cjwatson.
Colin Watson (cjwatson) : | # |
- df76888... by Thiago F. Pappacena
-
Merge branch 'master' into snap-pillar-
subscribe- removal- job - 5f729ee... by Thiago F. Pappacena
-
Removing unecessary shortcut for admin permission on snaps
Thiago F. Pappacena (pappacena) : | # |
Unmerged commits
- 5f729ee... by Thiago F. Pappacena
-
Removing unecessary shortcut for admin permission on snaps
- df76888... by Thiago F. Pappacena
-
Merge branch 'master' into snap-pillar-
subscribe- removal- job - 920b88c... by Thiago F. Pappacena
-
Not granting commercial admin view permisson on every snap
- e857291... by Thiago F. Pappacena
-
Refactoring and setting proper db permission for job
- 76b720d... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job - d256e68... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job - 0efaed4... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job - be29706... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job - 96846ab... by Thiago F. Pappacena
-
Fixing snap privacy filter usage
- 6ead4b4... by Thiago F. Pappacena
-
Merge branch 'snap-pillar-
subscribe' into snap-pillar- subscribe- removal- job
Preview Diff
1 | diff --git a/database/schema/security.cfg b/database/schema/security.cfg | |||
2 | index e9dcc62..2f4ffdf 100644 | |||
3 | --- a/database/schema/security.cfg | |||
4 | +++ b/database/schema/security.cfg | |||
5 | @@ -2111,6 +2111,8 @@ public.job = SELECT, INSERT, UPDATE | |||
6 | 2111 | public.person = SELECT | 2111 | public.person = SELECT |
7 | 2112 | public.product = SELECT | 2112 | public.product = SELECT |
8 | 2113 | public.sharingjob = SELECT, INSERT, UPDATE | 2113 | public.sharingjob = SELECT, INSERT, UPDATE |
9 | 2114 | public.snap = SELECT | ||
10 | 2115 | public.snapsubscription = SELECT, UPDATE, DELETE | ||
11 | 2114 | public.specification = SELECT | 2116 | public.specification = SELECT |
12 | 2115 | public.specificationsubscription = SELECT, DELETE | 2117 | public.specificationsubscription = SELECT, DELETE |
13 | 2116 | public.teamparticipation = SELECT | 2118 | public.teamparticipation = SELECT |
14 | diff --git a/lib/lp/blueprints/model/specification.py b/lib/lp/blueprints/model/specification.py | |||
15 | index e0d4001..55ce9d5 100644 | |||
16 | --- a/lib/lp/blueprints/model/specification.py | |||
17 | +++ b/lib/lp/blueprints/model/specification.py | |||
18 | @@ -1,4 +1,4 @@ | |||
20 | 1 | # Copyright 2009-2020 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
21 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
22 | 3 | 3 | ||
23 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
24 | @@ -755,7 +755,7 @@ class Specification(SQLBase, BugLinkTargetMixin, InformationTypeMixin): | |||
25 | 755 | # Grant the subscriber access if they can't see the | 755 | # Grant the subscriber access if they can't see the |
26 | 756 | # specification. | 756 | # specification. |
27 | 757 | service = getUtility(IService, 'sharing') | 757 | service = getUtility(IService, 'sharing') |
29 | 758 | _, _, _, shared_specs = service.getVisibleArtifacts( | 758 | _, _, _, _, shared_specs = service.getVisibleArtifacts( |
30 | 759 | person, specifications=[self], ignore_permissions=True) | 759 | person, specifications=[self], ignore_permissions=True) |
31 | 760 | if not shared_specs: | 760 | if not shared_specs: |
32 | 761 | service.ensureAccessGrants( | 761 | service.ensureAccessGrants( |
33 | diff --git a/lib/lp/blueprints/tests/test_specification.py b/lib/lp/blueprints/tests/test_specification.py | |||
34 | index 8de08c9..86c4e4a 100644 | |||
35 | --- a/lib/lp/blueprints/tests/test_specification.py | |||
36 | +++ b/lib/lp/blueprints/tests/test_specification.py | |||
37 | @@ -1,4 +1,4 @@ | |||
39 | 1 | # Copyright 2010-2015 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2010-2021 Canonical Ltd. This software is licensed under the |
40 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
41 | 3 | 3 | ||
42 | 4 | """Unit tests for Specification.""" | 4 | """Unit tests for Specification.""" |
43 | @@ -492,7 +492,7 @@ class SpecificationTests(TestCaseWithFactory): | |||
44 | 492 | product=product, information_type=InformationType.PROPRIETARY) | 492 | product=product, information_type=InformationType.PROPRIETARY) |
45 | 493 | spec.subscribe(user, subscribed_by=owner) | 493 | spec.subscribe(user, subscribed_by=owner) |
46 | 494 | service = getUtility(IService, 'sharing') | 494 | service = getUtility(IService, 'sharing') |
48 | 495 | _, _, _, shared_specs = service.getVisibleArtifacts( | 495 | _, _, _, _, shared_specs = service.getVisibleArtifacts( |
49 | 496 | user, specifications=[spec]) | 496 | user, specifications=[spec]) |
50 | 497 | self.assertEqual([spec], shared_specs) | 497 | self.assertEqual([spec], shared_specs) |
51 | 498 | # The spec is also returned by getSharedSpecifications(), | 498 | # The spec is also returned by getSharedSpecifications(), |
52 | @@ -509,7 +509,7 @@ class SpecificationTests(TestCaseWithFactory): | |||
53 | 509 | service.sharePillarInformation( | 509 | service.sharePillarInformation( |
54 | 510 | product, user_2, owner, permissions) | 510 | product, user_2, owner, permissions) |
55 | 511 | spec.subscribe(user_2, subscribed_by=owner) | 511 | spec.subscribe(user_2, subscribed_by=owner) |
57 | 512 | _, _, _, shared_specs = service.getVisibleArtifacts( | 512 | _, _, _, _, shared_specs = service.getVisibleArtifacts( |
58 | 513 | user_2, specifications=[spec]) | 513 | user_2, specifications=[spec]) |
59 | 514 | self.assertEqual([spec], shared_specs) | 514 | self.assertEqual([spec], shared_specs) |
60 | 515 | self.assertEqual( | 515 | self.assertEqual( |
61 | @@ -529,7 +529,7 @@ class SpecificationTests(TestCaseWithFactory): | |||
62 | 529 | spec.subscribe(user, subscribed_by=owner) | 529 | spec.subscribe(user, subscribed_by=owner) |
63 | 530 | spec.unsubscribe(user, unsubscribed_by=owner) | 530 | spec.unsubscribe(user, unsubscribed_by=owner) |
64 | 531 | service = getUtility(IService, 'sharing') | 531 | service = getUtility(IService, 'sharing') |
66 | 532 | _, _, _, shared_specs = service.getVisibleArtifacts( | 532 | _, _, _, _, shared_specs = service.getVisibleArtifacts( |
67 | 533 | user, specifications=[spec]) | 533 | user, specifications=[spec]) |
68 | 534 | self.assertEqual([], shared_specs) | 534 | self.assertEqual([], shared_specs) |
69 | 535 | 535 | ||
70 | diff --git a/lib/lp/bugs/model/bug.py b/lib/lp/bugs/model/bug.py | |||
71 | index a9b177c..f7ebc86 100644 | |||
72 | --- a/lib/lp/bugs/model/bug.py | |||
73 | +++ b/lib/lp/bugs/model/bug.py | |||
74 | @@ -1,4 +1,4 @@ | |||
76 | 1 | # Copyright 2009-2020 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
77 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
78 | 3 | 3 | ||
79 | 4 | """Launchpad bug-related database table classes.""" | 4 | """Launchpad bug-related database table classes.""" |
80 | @@ -875,7 +875,7 @@ class Bug(SQLBase, InformationTypeMixin): | |||
81 | 875 | # there is at least one bugtask for which access can be checked. | 875 | # there is at least one bugtask for which access can be checked. |
82 | 876 | if self.default_bugtask: | 876 | if self.default_bugtask: |
83 | 877 | service = getUtility(IService, 'sharing') | 877 | service = getUtility(IService, 'sharing') |
85 | 878 | bugs, _, _, _ = service.getVisibleArtifacts( | 878 | bugs, _, _, _, _ = service.getVisibleArtifacts( |
86 | 879 | person, bugs=[self], ignore_permissions=True) | 879 | person, bugs=[self], ignore_permissions=True) |
87 | 880 | if not bugs: | 880 | if not bugs: |
88 | 881 | service.ensureAccessGrants( | 881 | service.ensureAccessGrants( |
89 | @@ -1819,7 +1819,7 @@ class Bug(SQLBase, InformationTypeMixin): | |||
90 | 1819 | if information_type in PRIVATE_INFORMATION_TYPES: | 1819 | if information_type in PRIVATE_INFORMATION_TYPES: |
91 | 1820 | service = getUtility(IService, 'sharing') | 1820 | service = getUtility(IService, 'sharing') |
92 | 1821 | for person in (who, self.owner): | 1821 | for person in (who, self.owner): |
94 | 1822 | bugs, _, _, _ = service.getVisibleArtifacts( | 1822 | bugs, _, _, _, _ = service.getVisibleArtifacts( |
95 | 1823 | person, bugs=[self], ignore_permissions=True) | 1823 | person, bugs=[self], ignore_permissions=True) |
96 | 1824 | if not bugs: | 1824 | if not bugs: |
97 | 1825 | # subscribe() isn't sufficient if a subscription | 1825 | # subscribe() isn't sufficient if a subscription |
98 | diff --git a/lib/lp/code/browser/branchsubscription.py b/lib/lp/code/browser/branchsubscription.py | |||
99 | index fbd98bc..cee4504 100644 | |||
100 | --- a/lib/lp/code/browser/branchsubscription.py | |||
101 | +++ b/lib/lp/code/browser/branchsubscription.py | |||
102 | @@ -1,4 +1,4 @@ | |||
104 | 1 | # Copyright 2009-2020 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
105 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
106 | 3 | 3 | ||
107 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
108 | @@ -276,7 +276,7 @@ class BranchSubscriptionEditView(LaunchpadEditFormView): | |||
109 | 276 | url = canonical_url(self.branch) | 276 | url = canonical_url(self.branch) |
110 | 277 | # If the subscriber can no longer see the branch, redirect them away. | 277 | # If the subscriber can no longer see the branch, redirect them away. |
111 | 278 | service = getUtility(IService, 'sharing') | 278 | service = getUtility(IService, 'sharing') |
113 | 279 | _, branches, _, _ = service.getVisibleArtifacts( | 279 | _, branches, _, _, _ = service.getVisibleArtifacts( |
114 | 280 | self.person, branches=[self.branch], ignore_permissions=True) | 280 | self.person, branches=[self.branch], ignore_permissions=True) |
115 | 281 | if not branches: | 281 | if not branches: |
116 | 282 | url = canonical_url(self.branch.target) | 282 | url = canonical_url(self.branch.target) |
117 | diff --git a/lib/lp/code/browser/gitsubscription.py b/lib/lp/code/browser/gitsubscription.py | |||
118 | index 3eda78c..a18d593 100644 | |||
119 | --- a/lib/lp/code/browser/gitsubscription.py | |||
120 | +++ b/lib/lp/code/browser/gitsubscription.py | |||
121 | @@ -1,4 +1,4 @@ | |||
123 | 1 | # Copyright 2015-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2021 Canonical Ltd. This software is licensed under the |
124 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
125 | 3 | 3 | ||
126 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
127 | @@ -280,7 +280,7 @@ class GitSubscriptionEditView(LaunchpadEditFormView): | |||
128 | 280 | # If the subscriber can no longer see the repository, redirect them | 280 | # If the subscriber can no longer see the repository, redirect them |
129 | 281 | # away. | 281 | # away. |
130 | 282 | service = getUtility(IService, "sharing") | 282 | service = getUtility(IService, "sharing") |
132 | 283 | _, _, repositories, _ = service.getVisibleArtifacts( | 283 | _, _, repositories, _, _ = service.getVisibleArtifacts( |
133 | 284 | self.person, gitrepositories=[self.repository], | 284 | self.person, gitrepositories=[self.repository], |
134 | 285 | ignore_permissions=True) | 285 | ignore_permissions=True) |
135 | 286 | if not repositories: | 286 | if not repositories: |
136 | diff --git a/lib/lp/code/model/branch.py b/lib/lp/code/model/branch.py | |||
137 | index 947aaf1..278db40 100644 | |||
138 | --- a/lib/lp/code/model/branch.py | |||
139 | +++ b/lib/lp/code/model/branch.py | |||
140 | @@ -1,4 +1,4 @@ | |||
142 | 1 | # Copyright 2009-2020 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
143 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
144 | 3 | 3 | ||
145 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
146 | @@ -1041,7 +1041,7 @@ class Branch(SQLBase, WebhookTargetMixin, BzrIdentityMixin): | |||
147 | 1041 | subscription.review_level = code_review_level | 1041 | subscription.review_level = code_review_level |
148 | 1042 | # Grant the subscriber access if they can't see the branch. | 1042 | # Grant the subscriber access if they can't see the branch. |
149 | 1043 | service = getUtility(IService, 'sharing') | 1043 | service = getUtility(IService, 'sharing') |
151 | 1044 | _, branches, _, _ = service.getVisibleArtifacts( | 1044 | _, branches, _, _, _ = service.getVisibleArtifacts( |
152 | 1045 | person, branches=[self], ignore_permissions=True) | 1045 | person, branches=[self], ignore_permissions=True) |
153 | 1046 | if not branches: | 1046 | if not branches: |
154 | 1047 | service.ensureAccessGrants( | 1047 | service.ensureAccessGrants( |
155 | diff --git a/lib/lp/code/model/gitrepository.py b/lib/lp/code/model/gitrepository.py | |||
156 | index 74d94ec..589dcbf 100644 | |||
157 | --- a/lib/lp/code/model/gitrepository.py | |||
158 | +++ b/lib/lp/code/model/gitrepository.py | |||
159 | @@ -1002,7 +1002,7 @@ class GitRepository(StormBase, WebhookTargetMixin, GitIdentityMixin): | |||
160 | 1002 | subscription.review_level = code_review_level | 1002 | subscription.review_level = code_review_level |
161 | 1003 | # Grant the subscriber access if they can't see the repository. | 1003 | # Grant the subscriber access if they can't see the repository. |
162 | 1004 | service = getUtility(IService, "sharing") | 1004 | service = getUtility(IService, "sharing") |
164 | 1005 | _, _, repositories, _ = service.getVisibleArtifacts( | 1005 | _, _, repositories, _, _ = service.getVisibleArtifacts( |
165 | 1006 | person, gitrepositories=[self], ignore_permissions=True) | 1006 | person, gitrepositories=[self], ignore_permissions=True) |
166 | 1007 | if not repositories: | 1007 | if not repositories: |
167 | 1008 | service.ensureAccessGrants( | 1008 | service.ensureAccessGrants( |
168 | diff --git a/lib/lp/code/model/tests/test_branchsubscription.py b/lib/lp/code/model/tests/test_branchsubscription.py | |||
169 | index 6a15cd0..b5b234e 100644 | |||
170 | --- a/lib/lp/code/model/tests/test_branchsubscription.py | |||
171 | +++ b/lib/lp/code/model/tests/test_branchsubscription.py | |||
172 | @@ -1,4 +1,4 @@ | |||
174 | 1 | # Copyright 2010-2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2010-2021 Canonical Ltd. This software is licensed under the |
175 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
176 | 3 | 3 | ||
177 | 4 | """Tests for the BranchSubscription model object.""" | 4 | """Tests for the BranchSubscription model object.""" |
178 | @@ -134,7 +134,7 @@ class TestBranchSubscriptions(TestCaseWithFactory): | |||
179 | 134 | None, CodeReviewNotificationLevel.NOEMAIL, owner) | 134 | None, CodeReviewNotificationLevel.NOEMAIL, owner) |
180 | 135 | # The stacked on branch should be visible. | 135 | # The stacked on branch should be visible. |
181 | 136 | service = getUtility(IService, 'sharing') | 136 | service = getUtility(IService, 'sharing') |
183 | 137 | _, visible_branches, _, _ = service.getVisibleArtifacts( | 137 | _, visible_branches, _, _, _ = service.getVisibleArtifacts( |
184 | 138 | grantee, branches=[private_stacked_on_branch]) | 138 | grantee, branches=[private_stacked_on_branch]) |
185 | 139 | self.assertContentEqual( | 139 | self.assertContentEqual( |
186 | 140 | [private_stacked_on_branch], visible_branches) | 140 | [private_stacked_on_branch], visible_branches) |
187 | @@ -162,7 +162,7 @@ class TestBranchSubscriptions(TestCaseWithFactory): | |||
188 | 162 | grantee, BranchSubscriptionNotificationLevel.NOEMAIL, | 162 | grantee, BranchSubscriptionNotificationLevel.NOEMAIL, |
189 | 163 | None, CodeReviewNotificationLevel.NOEMAIL, owner) | 163 | None, CodeReviewNotificationLevel.NOEMAIL, owner) |
190 | 164 | # The stacked on branch should not be visible. | 164 | # The stacked on branch should not be visible. |
192 | 165 | _, visible_branches, _, _ = service.getVisibleArtifacts( | 165 | _, visible_branches, _, _, _ = service.getVisibleArtifacts( |
193 | 166 | grantee, branches=[private_stacked_on_branch]) | 166 | grantee, branches=[private_stacked_on_branch]) |
194 | 167 | self.assertContentEqual([], visible_branches) | 167 | self.assertContentEqual([], visible_branches) |
195 | 168 | self.assertIn( | 168 | self.assertIn( |
196 | diff --git a/lib/lp/registry/model/sharingjob.py b/lib/lp/registry/model/sharingjob.py | |||
197 | index 7d10fa9..81e6a9e 100644 | |||
198 | --- a/lib/lp/registry/model/sharingjob.py | |||
199 | +++ b/lib/lp/registry/model/sharingjob.py | |||
200 | @@ -1,4 +1,4 @@ | |||
202 | 1 | # Copyright 2012-2020 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2012-2021 Canonical Ltd. This software is licensed under the |
203 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
204 | 3 | 3 | ||
205 | 4 | """Job classes related to the sharing feature are in here.""" | 4 | """Job classes related to the sharing feature are in here.""" |
206 | @@ -91,6 +91,12 @@ from lp.services.job.model.job import ( | |||
207 | 91 | ) | 91 | ) |
208 | 92 | from lp.services.job.runner import BaseRunnableJob | 92 | from lp.services.job.runner import BaseRunnableJob |
209 | 93 | from lp.services.mail.sendmail import format_address_for_person | 93 | from lp.services.mail.sendmail import format_address_for_person |
210 | 94 | from lp.snappy.interfaces.snap import ISnap | ||
211 | 95 | from lp.snappy.model.snap import ( | ||
212 | 96 | get_snap_privacy_filter, | ||
213 | 97 | Snap, | ||
214 | 98 | ) | ||
215 | 99 | from lp.snappy.model.snapsubscription import SnapSubscription | ||
216 | 94 | 100 | ||
217 | 95 | 101 | ||
218 | 96 | class SharingJobType(DBEnumeratedType): | 102 | class SharingJobType(DBEnumeratedType): |
219 | @@ -263,6 +269,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
220 | 263 | bug_ids = [] | 269 | bug_ids = [] |
221 | 264 | branch_ids = [] | 270 | branch_ids = [] |
222 | 265 | gitrepository_ids = [] | 271 | gitrepository_ids = [] |
223 | 272 | snap_ids = [] | ||
224 | 266 | specification_ids = [] | 273 | specification_ids = [] |
225 | 267 | if artifacts: | 274 | if artifacts: |
226 | 268 | for artifact in artifacts: | 275 | for artifact in artifacts: |
227 | @@ -272,6 +279,8 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
228 | 272 | branch_ids.append(artifact.id) | 279 | branch_ids.append(artifact.id) |
229 | 273 | elif IGitRepository.providedBy(artifact): | 280 | elif IGitRepository.providedBy(artifact): |
230 | 274 | gitrepository_ids.append(artifact.id) | 281 | gitrepository_ids.append(artifact.id) |
231 | 282 | elif ISnap.providedBy(artifact): | ||
232 | 283 | snap_ids.append(artifact.id) | ||
233 | 275 | elif ISpecification.providedBy(artifact): | 284 | elif ISpecification.providedBy(artifact): |
234 | 276 | specification_ids.append(artifact.id) | 285 | specification_ids.append(artifact.id) |
235 | 277 | else: | 286 | else: |
236 | @@ -284,6 +293,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
237 | 284 | 'bug_ids': bug_ids, | 293 | 'bug_ids': bug_ids, |
238 | 285 | 'branch_ids': branch_ids, | 294 | 'branch_ids': branch_ids, |
239 | 286 | 'gitrepository_ids': gitrepository_ids, | 295 | 'gitrepository_ids': gitrepository_ids, |
240 | 296 | 'snap_ids': snap_ids, | ||
241 | 287 | 'specification_ids': specification_ids, | 297 | 'specification_ids': specification_ids, |
242 | 288 | 'information_types': information_types, | 298 | 'information_types': information_types, |
243 | 289 | 'requestor.id': requestor.id | 299 | 'requestor.id': requestor.id |
244 | @@ -320,6 +330,10 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
245 | 320 | return self.metadata.get('gitrepository_ids', []) | 330 | return self.metadata.get('gitrepository_ids', []) |
246 | 321 | 331 | ||
247 | 322 | @property | 332 | @property |
248 | 333 | def snap_ids(self): | ||
249 | 334 | return self.metadata.get('snap_ids', []) | ||
250 | 335 | |||
251 | 336 | @property | ||
252 | 323 | def specification_ids(self): | 337 | def specification_ids(self): |
253 | 324 | return self.metadata.get('specification_ids', []) | 338 | return self.metadata.get('specification_ids', []) |
254 | 325 | 339 | ||
255 | @@ -349,6 +363,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
256 | 349 | 'bug_ids': self.bug_ids, | 363 | 'bug_ids': self.bug_ids, |
257 | 350 | 'branch_ids': self.branch_ids, | 364 | 'branch_ids': self.branch_ids, |
258 | 351 | 'gitrepository_ids': self.gitrepository_ids, | 365 | 'gitrepository_ids': self.gitrepository_ids, |
259 | 366 | 'snap_ids': self.snap_ids, | ||
260 | 352 | 'specification_ids': self.specification_ids, | 367 | 'specification_ids': self.specification_ids, |
261 | 353 | 'pillar': getattr(self.pillar, 'name', None), | 368 | 'pillar': getattr(self.pillar, 'name', None), |
262 | 354 | 'grantee': getattr(self.grantee, 'name', None) | 369 | 'grantee': getattr(self.grantee, 'name', None) |
263 | @@ -365,6 +380,7 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
264 | 365 | bug_filters = [] | 380 | bug_filters = [] |
265 | 366 | branch_filters = [] | 381 | branch_filters = [] |
266 | 367 | gitrepository_filters = [] | 382 | gitrepository_filters = [] |
267 | 383 | snap_filters = [] | ||
268 | 368 | specification_filters = [] | 384 | specification_filters = [] |
269 | 369 | 385 | ||
270 | 370 | if self.branch_ids: | 386 | if self.branch_ids: |
271 | @@ -372,6 +388,8 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
272 | 372 | if self.gitrepository_ids: | 388 | if self.gitrepository_ids: |
273 | 373 | gitrepository_filters.append(GitRepository.id.is_in( | 389 | gitrepository_filters.append(GitRepository.id.is_in( |
274 | 374 | self.gitrepository_ids)) | 390 | self.gitrepository_ids)) |
275 | 391 | if self.snap_ids: | ||
276 | 392 | snap_filters.append(Snap.id.is_in(self.snap_ids)) | ||
277 | 375 | if self.specification_ids: | 393 | if self.specification_ids: |
278 | 376 | specification_filters.append(Specification.id.is_in( | 394 | specification_filters.append(Specification.id.is_in( |
279 | 377 | self.specification_ids)) | 395 | self.specification_ids)) |
280 | @@ -387,6 +405,8 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
281 | 387 | gitrepository_filters.append( | 405 | gitrepository_filters.append( |
282 | 388 | GitRepository.information_type.is_in( | 406 | GitRepository.information_type.is_in( |
283 | 389 | self.information_types)) | 407 | self.information_types)) |
284 | 408 | snap_filters.append(Snap._information_type.is_in( | ||
285 | 409 | self.information_types)) | ||
286 | 390 | specification_filters.append( | 410 | specification_filters.append( |
287 | 391 | Specification.information_type.is_in( | 411 | Specification.information_type.is_in( |
288 | 392 | self.information_types)) | 412 | self.information_types)) |
289 | @@ -423,6 +443,11 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
290 | 423 | Select( | 443 | Select( |
291 | 424 | TeamParticipation.personID, | 444 | TeamParticipation.personID, |
292 | 425 | where=TeamParticipation.team == self.grantee))) | 445 | where=TeamParticipation.team == self.grantee))) |
293 | 446 | snap_filters.append( | ||
294 | 447 | In(SnapSubscription.person_id, | ||
295 | 448 | Select( | ||
296 | 449 | TeamParticipation.personID, | ||
297 | 450 | where=TeamParticipation.team == self.grantee))) | ||
298 | 426 | specification_filters.append( | 451 | specification_filters.append( |
299 | 427 | In(SpecificationSubscription.person_id, | 452 | In(SpecificationSubscription.person_id, |
300 | 428 | Select( | 453 | Select( |
301 | @@ -466,6 +491,16 @@ class RemoveArtifactSubscriptionsJob(SharingJobDerived): | |||
302 | 466 | for sub in gitrepository_subscriptions: | 491 | for sub in gitrepository_subscriptions: |
303 | 467 | sub.repository.unsubscribe( | 492 | sub.repository.unsubscribe( |
304 | 468 | sub.person, self.requestor, ignore_permissions=True) | 493 | sub.person, self.requestor, ignore_permissions=True) |
305 | 494 | if snap_filters: | ||
306 | 495 | snap_filters.append( | ||
307 | 496 | Not(get_snap_privacy_filter(SnapSubscription.person_id))) | ||
308 | 497 | snap_subscriptions = IStore(SnapSubscription).using( | ||
309 | 498 | SnapSubscription, | ||
310 | 499 | Join(Snap, Snap.id == SnapSubscription.snap_id) | ||
311 | 500 | ).find(SnapSubscription, *snap_filters).config(distinct=True) | ||
312 | 501 | for sub in snap_subscriptions: | ||
313 | 502 | sub.snap.unsubscribe( | ||
314 | 503 | sub.person, self.requestor, ignore_permissions=True) | ||
315 | 469 | if specification_filters: | 504 | if specification_filters: |
316 | 470 | specification_filters.append(Not(*get_specification_privacy_filter( | 505 | specification_filters.append(Not(*get_specification_privacy_filter( |
317 | 471 | SpecificationSubscription.person_id))) | 506 | SpecificationSubscription.person_id))) |
318 | diff --git a/lib/lp/registry/services/sharingservice.py b/lib/lp/registry/services/sharingservice.py | |||
319 | index 01e90da..4909604 100644 | |||
320 | --- a/lib/lp/registry/services/sharingservice.py | |||
321 | +++ b/lib/lp/registry/services/sharingservice.py | |||
322 | @@ -81,10 +81,7 @@ from lp.services.webapp.authorization import ( | |||
323 | 81 | available_with_permission, | 81 | available_with_permission, |
324 | 82 | check_permission, | 82 | check_permission, |
325 | 83 | ) | 83 | ) |
330 | 84 | from lp.snappy.interfaces.snap import ( | 84 | from lp.snappy.interfaces.snap import ISnapSet |
327 | 85 | ISnap, | ||
328 | 86 | ISnapSet, | ||
329 | 87 | ) | ||
331 | 88 | 85 | ||
332 | 89 | 86 | ||
333 | 90 | @implementer(ISharingService) | 87 | @implementer(ISharingService) |
334 | @@ -332,6 +329,7 @@ class SharingService: | |||
335 | 332 | bug_ids = [] | 329 | bug_ids = [] |
336 | 333 | branch_ids = [] | 330 | branch_ids = [] |
337 | 334 | gitrepository_ids = [] | 331 | gitrepository_ids = [] |
338 | 332 | snap_ids = [] | ||
339 | 335 | for bug in bugs or []: | 333 | for bug in bugs or []: |
340 | 336 | if (not ignore_permissions | 334 | if (not ignore_permissions |
341 | 337 | and not check_permission('launchpad.View', bug)): | 335 | and not check_permission('launchpad.View', bug)): |
342 | @@ -344,9 +342,14 @@ class SharingService: | |||
343 | 344 | branch_ids.append(branch.id) | 342 | branch_ids.append(branch.id) |
344 | 345 | for gitrepository in gitrepositories or []: | 343 | for gitrepository in gitrepositories or []: |
345 | 346 | if (not ignore_permissions | 344 | if (not ignore_permissions |
347 | 347 | and not check_permission('launchpad.View', gitrepository)): | 345 | and not check_permission('launchpad.View', gitrepository)): |
348 | 348 | raise Unauthorized | 346 | raise Unauthorized |
349 | 349 | gitrepository_ids.append(gitrepository.id) | 347 | gitrepository_ids.append(gitrepository.id) |
350 | 348 | for snap in snaps or []: | ||
351 | 349 | if (not ignore_permissions | ||
352 | 350 | and not check_permission('launchpad.View', snap)): | ||
353 | 351 | raise Unauthorized | ||
354 | 352 | snap_ids.append(snap.id) | ||
355 | 350 | for spec in specifications or []: | 353 | for spec in specifications or []: |
356 | 351 | if (not ignore_permissions | 354 | if (not ignore_permissions |
357 | 352 | and not check_permission('launchpad.View', spec)): | 355 | and not check_permission('launchpad.View', spec)): |
358 | @@ -376,6 +379,12 @@ class SharingService: | |||
359 | 376 | visible_gitrepositories = list( | 379 | visible_gitrepositories = list( |
360 | 377 | wanted_gitrepositories.getRepositories()) | 380 | wanted_gitrepositories.getRepositories()) |
361 | 378 | 381 | ||
362 | 382 | # Load the Snaps. | ||
363 | 383 | visible_snaps = [] | ||
364 | 384 | if snap_ids: | ||
365 | 385 | visible_snaps = list(getUtility(ISnapSet).findByIds( | ||
366 | 386 | snap_ids, visible_by_user=person)) | ||
367 | 387 | |||
368 | 379 | # Load the specifications. | 388 | # Load the specifications. |
369 | 380 | visible_specs = [] | 389 | visible_specs = [] |
370 | 381 | if specifications: | 390 | if specifications: |
371 | @@ -387,7 +396,7 @@ class SharingService: | |||
372 | 387 | 396 | ||
373 | 388 | return ( | 397 | return ( |
374 | 389 | visible_bugs, visible_branches, visible_gitrepositories, | 398 | visible_bugs, visible_branches, visible_gitrepositories, |
376 | 390 | visible_specs) | 399 | visible_snaps, visible_specs) |
377 | 391 | 400 | ||
378 | 392 | def getInvisibleArtifacts(self, person, bugs=None, branches=None, | 401 | def getInvisibleArtifacts(self, person, bugs=None, branches=None, |
379 | 393 | gitrepositories=None): | 402 | gitrepositories=None): |
380 | @@ -800,12 +809,6 @@ class SharingService: | |||
381 | 800 | getUtility(IAccessArtifactGrantSource).revokeByArtifact( | 809 | getUtility(IAccessArtifactGrantSource).revokeByArtifact( |
382 | 801 | artifacts_to_delete, [grantee]) | 810 | artifacts_to_delete, [grantee]) |
383 | 802 | 811 | ||
384 | 803 | # XXX: Pappacena 2021-02-05: snaps should not trigger this job, | ||
385 | 804 | # since we do not have a "SnapSubscription" yet. | ||
386 | 805 | artifacts = [i for i in artifacts if not ISnap.providedBy(i)] | ||
387 | 806 | if not artifacts: | ||
388 | 807 | return | ||
389 | 808 | |||
390 | 809 | # Create a job to remove subscriptions for artifacts the grantee can no | 812 | # Create a job to remove subscriptions for artifacts the grantee can no |
391 | 810 | # longer see. | 813 | # longer see. |
392 | 811 | return getUtility(IRemoveArtifactSubscriptionsJobSource).create( | 814 | return getUtility(IRemoveArtifactSubscriptionsJobSource).create( |
393 | diff --git a/lib/lp/registry/services/tests/test_sharingservice.py b/lib/lp/registry/services/tests/test_sharingservice.py | |||
394 | index 9d0e07c..8d94723 100644 | |||
395 | --- a/lib/lp/registry/services/tests/test_sharingservice.py | |||
396 | +++ b/lib/lp/registry/services/tests/test_sharingservice.py | |||
397 | @@ -1,4 +1,4 @@ | |||
399 | 1 | # Copyright 2012-2015 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2012-2021 Canonical Ltd. This software is licensed under the |
400 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
401 | 3 | 3 | ||
402 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
403 | @@ -1101,7 +1101,7 @@ class TestSharingService(TestCaseWithFactory): | |||
404 | 1101 | # Check that grantees have expected access grants and subscriptions. | 1101 | # Check that grantees have expected access grants and subscriptions. |
405 | 1102 | for person in [team_grantee, person_grantee]: | 1102 | for person in [team_grantee, person_grantee]: |
406 | 1103 | (visible_bugs, visible_branches, visible_gitrepositories, | 1103 | (visible_bugs, visible_branches, visible_gitrepositories, |
408 | 1104 | visible_specs) = ( | 1104 | visible_snaps, visible_specs) = ( |
409 | 1105 | self.service.getVisibleArtifacts( | 1105 | self.service.getVisibleArtifacts( |
410 | 1106 | person, bugs=bugs, branches=branches, | 1106 | person, bugs=bugs, branches=branches, |
411 | 1107 | gitrepositories=gitrepositories, | 1107 | gitrepositories=gitrepositories, |
412 | @@ -1133,7 +1133,7 @@ class TestSharingService(TestCaseWithFactory): | |||
413 | 1133 | for bug in bugs or []: | 1133 | for bug in bugs or []: |
414 | 1134 | self.assertNotIn(person, bug.getDirectSubscribers()) | 1134 | self.assertNotIn(person, bug.getDirectSubscribers()) |
415 | 1135 | (visible_bugs, visible_branches, visible_gitrepositories, | 1135 | (visible_bugs, visible_branches, visible_gitrepositories, |
417 | 1136 | visible_specs) = ( | 1136 | visible_snaps, visible_specs) = ( |
418 | 1137 | self.service.getVisibleArtifacts( | 1137 | self.service.getVisibleArtifacts( |
419 | 1138 | person, bugs=bugs, branches=branches, | 1138 | person, bugs=bugs, branches=branches, |
420 | 1139 | gitrepositories=gitrepositories)) | 1139 | gitrepositories=gitrepositories)) |
421 | @@ -1783,7 +1783,8 @@ class TestSharingService(TestCaseWithFactory): | |||
422 | 1783 | grantee, ignore, bugs, branches, gitrepositories, specs = ( | 1783 | grantee, ignore, bugs, branches, gitrepositories, specs = ( |
423 | 1784 | self._make_Artifacts()) | 1784 | self._make_Artifacts()) |
424 | 1785 | # Check the results. | 1785 | # Check the results. |
426 | 1786 | shared_bugs, shared_branches, shared_gitrepositories, shared_specs = ( | 1786 | (shared_bugs, shared_branches, shared_gitrepositories, |
427 | 1787 | shared_snaps, shared_specs) = ( | ||
428 | 1787 | self.service.getVisibleArtifacts( | 1788 | self.service.getVisibleArtifacts( |
429 | 1788 | grantee, bugs=bugs, branches=branches, | 1789 | grantee, bugs=bugs, branches=branches, |
430 | 1789 | gitrepositories=gitrepositories, specifications=specs)) | 1790 | gitrepositories=gitrepositories, specifications=specs)) |
431 | @@ -1797,7 +1798,8 @@ class TestSharingService(TestCaseWithFactory): | |||
432 | 1797 | # user has a policy grant for the pillar of the specification. | 1798 | # user has a policy grant for the pillar of the specification. |
433 | 1798 | _, owner, bugs, branches, gitrepositories, specs = ( | 1799 | _, owner, bugs, branches, gitrepositories, specs = ( |
434 | 1799 | self._make_Artifacts()) | 1800 | self._make_Artifacts()) |
436 | 1800 | shared_bugs, shared_branches, shared_gitrepositories, shared_specs = ( | 1801 | (shared_bugs, shared_branches, shared_gitrepositories, |
437 | 1802 | shared_snaps, shared_specs) = ( | ||
438 | 1801 | self.service.getVisibleArtifacts( | 1803 | self.service.getVisibleArtifacts( |
439 | 1802 | owner, bugs=bugs, branches=branches, | 1804 | owner, bugs=bugs, branches=branches, |
440 | 1803 | gitrepositories=gitrepositories, specifications=specs)) | 1805 | gitrepositories=gitrepositories, specifications=specs)) |
441 | @@ -1840,7 +1842,8 @@ class TestSharingService(TestCaseWithFactory): | |||
442 | 1840 | information_type=InformationType.USERDATA) | 1842 | information_type=InformationType.USERDATA) |
443 | 1841 | bugs.append(bug) | 1843 | bugs.append(bug) |
444 | 1842 | 1844 | ||
446 | 1843 | shared_bugs, shared_branches, shared_gitrepositories, shared_specs = ( | 1845 | (shared_bugs, shared_branches, shared_gitrepositories, |
447 | 1846 | visible_snaps, shared_specs) = ( | ||
448 | 1844 | self.service.getVisibleArtifacts(grantee, bugs=bugs)) | 1847 | self.service.getVisibleArtifacts(grantee, bugs=bugs)) |
449 | 1845 | self.assertContentEqual(bugs, shared_bugs) | 1848 | self.assertContentEqual(bugs, shared_bugs) |
450 | 1846 | 1849 | ||
451 | @@ -1848,7 +1851,8 @@ class TestSharingService(TestCaseWithFactory): | |||
452 | 1848 | for x in range(0, 5): | 1851 | for x in range(0, 5): |
453 | 1849 | change_callback(bugs[x], owner) | 1852 | change_callback(bugs[x], owner) |
454 | 1850 | # Check the results. | 1853 | # Check the results. |
456 | 1851 | shared_bugs, shared_branches, shared_gitrepositories, shared_specs = ( | 1854 | (shared_bugs, shared_branches, shared_gitrepositories, |
457 | 1855 | visible_snaps, shared_specs) = ( | ||
458 | 1852 | self.service.getVisibleArtifacts(grantee, bugs=bugs)) | 1856 | self.service.getVisibleArtifacts(grantee, bugs=bugs)) |
459 | 1853 | self.assertContentEqual(bugs[5:], shared_bugs) | 1857 | self.assertContentEqual(bugs[5:], shared_bugs) |
460 | 1854 | 1858 | ||
461 | diff --git a/lib/lp/registry/tests/test_sharingjob.py b/lib/lp/registry/tests/test_sharingjob.py | |||
462 | index 58fa5c1..32aec0f 100644 | |||
463 | --- a/lib/lp/registry/tests/test_sharingjob.py | |||
464 | +++ b/lib/lp/registry/tests/test_sharingjob.py | |||
465 | @@ -1,4 +1,4 @@ | |||
467 | 1 | # Copyright 2012-2015 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2012-2021 Canonical Ltd. This software is licensed under the |
468 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
469 | 3 | 3 | ||
470 | 4 | """Tests for SharingJobs.""" | 4 | """Tests for SharingJobs.""" |
471 | @@ -39,6 +39,7 @@ from lp.services.features.testing import FeatureFixture | |||
472 | 39 | from lp.services.job.interfaces.job import JobStatus | 39 | from lp.services.job.interfaces.job import JobStatus |
473 | 40 | from lp.services.job.tests import block_on_job | 40 | from lp.services.job.tests import block_on_job |
474 | 41 | from lp.services.mail.sendmail import format_address_for_person | 41 | from lp.services.mail.sendmail import format_address_for_person |
475 | 42 | from lp.snappy.interfaces.snap import SNAP_TESTING_FLAGS | ||
476 | 42 | from lp.testing import ( | 43 | from lp.testing import ( |
477 | 43 | login_person, | 44 | login_person, |
478 | 44 | person_logged_in, | 45 | person_logged_in, |
479 | @@ -127,6 +128,16 @@ class SharingJobDerivedTestCase(TestCaseWithFactory): | |||
480 | 127 | 'for gitrepository_ids=[%d], requestor=%s>' | 128 | 'for gitrepository_ids=[%d], requestor=%s>' |
481 | 128 | % (gitrepository.id, requestor.name), repr(job)) | 129 | % (gitrepository.id, requestor.name), repr(job)) |
482 | 129 | 130 | ||
483 | 131 | def test_repr_snaps(self): | ||
484 | 132 | requestor = self.factory.makePerson() | ||
485 | 133 | snap = self.factory.makeSnap() | ||
486 | 134 | job = getUtility(IRemoveArtifactSubscriptionsJobSource).create( | ||
487 | 135 | requestor, artifacts=[snap]) | ||
488 | 136 | self.assertEqual( | ||
489 | 137 | '<REMOVE_ARTIFACT_SUBSCRIPTIONS job reconciling subscriptions ' | ||
490 | 138 | 'for requestor=%s, snap_ids=[%d]>' | ||
491 | 139 | % (requestor.name, snap.id), repr(job)) | ||
492 | 140 | |||
493 | 130 | def test_repr_specifications(self): | 141 | def test_repr_specifications(self): |
494 | 131 | requestor = self.factory.makePerson() | 142 | requestor = self.factory.makePerson() |
495 | 132 | specification = self.factory.makeSpecification() | 143 | specification = self.factory.makeSpecification() |
496 | @@ -241,9 +252,11 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
497 | 241 | layer = CeleryJobLayer | 252 | layer = CeleryJobLayer |
498 | 242 | 253 | ||
499 | 243 | def setUp(self): | 254 | def setUp(self): |
501 | 244 | self.useFixture(FeatureFixture({ | 255 | features = { |
502 | 245 | 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob', | 256 | 'jobs.celery.enabled_classes': 'RemoveArtifactSubscriptionsJob', |
504 | 246 | })) | 257 | } |
505 | 258 | features.update(SNAP_TESTING_FLAGS) | ||
506 | 259 | self.useFixture(FeatureFixture(features)) | ||
507 | 247 | super(RemoveArtifactSubscriptionsJobTestCase, self).setUp() | 260 | super(RemoveArtifactSubscriptionsJobTestCase, self).setUp() |
508 | 248 | 261 | ||
509 | 249 | def test_create(self): | 262 | def test_create(self): |
510 | @@ -315,6 +328,9 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
511 | 315 | gitrepository = self.factory.makeGitRepository( | 328 | gitrepository = self.factory.makeGitRepository( |
512 | 316 | owner=owner, target=product, | 329 | owner=owner, target=product, |
513 | 317 | information_type=InformationType.USERDATA) | 330 | information_type=InformationType.USERDATA) |
514 | 331 | snap = self.factory.makeSnap( | ||
515 | 332 | owner=owner, registrant=owner, project=product, | ||
516 | 333 | information_type=InformationType.USERDATA) | ||
517 | 318 | specification = self.factory.makeSpecification( | 334 | specification = self.factory.makeSpecification( |
518 | 319 | owner=owner, product=product, | 335 | owner=owner, product=product, |
519 | 320 | information_type=InformationType.PROPRIETARY) | 336 | information_type=InformationType.PROPRIETARY) |
520 | @@ -332,6 +348,7 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
521 | 332 | gitrepository.subscribe(artifact_indirect_grantee, | 348 | gitrepository.subscribe(artifact_indirect_grantee, |
522 | 333 | BranchSubscriptionNotificationLevel.NOEMAIL, None, | 349 | BranchSubscriptionNotificationLevel.NOEMAIL, None, |
523 | 334 | CodeReviewNotificationLevel.NOEMAIL, owner) | 350 | CodeReviewNotificationLevel.NOEMAIL, owner) |
524 | 351 | snap.subscribe(artifact_indirect_grantee, owner) | ||
525 | 335 | # Subscribing somebody to a specification does not automatically | 352 | # Subscribing somebody to a specification does not automatically |
526 | 336 | # create an artifact grant. | 353 | # create an artifact grant. |
527 | 337 | spec_artifact = self.factory.makeAccessArtifact(specification) | 354 | spec_artifact = self.factory.makeAccessArtifact(specification) |
528 | @@ -341,10 +358,11 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
529 | 341 | specification.subscribe(artifact_indirect_grantee, owner) | 358 | specification.subscribe(artifact_indirect_grantee, owner) |
530 | 342 | 359 | ||
531 | 343 | # pick one of the concrete artifacts (bug, branch, Git repository, | 360 | # pick one of the concrete artifacts (bug, branch, Git repository, |
533 | 344 | # or spec) and subscribe the teams and persons. | 361 | # snap, or spec) and subscribe the teams and persons. |
534 | 345 | concrete_artifact, get_pillars, get_subscribers = configure_test( | 362 | concrete_artifact, get_pillars, get_subscribers = configure_test( |
537 | 346 | bug, branch, gitrepository, specification, policy_team_grantee, | 363 | bug, branch, gitrepository, snap, specification, |
538 | 347 | policy_indirect_grantee, artifact_team_grantee, owner) | 364 | policy_team_grantee, policy_indirect_grantee, |
539 | 365 | artifact_team_grantee, owner) | ||
540 | 348 | 366 | ||
541 | 349 | # Subscribing policy_team_grantee has created an artifact grant so we | 367 | # Subscribing policy_team_grantee has created an artifact grant so we |
542 | 350 | # need to revoke that to test the job. | 368 | # need to revoke that to test the job. |
543 | @@ -377,6 +395,7 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
544 | 377 | self.assertIn(artifact_indirect_grantee, bug.getDirectSubscribers()) | 395 | self.assertIn(artifact_indirect_grantee, bug.getDirectSubscribers()) |
545 | 378 | self.assertIn(artifact_indirect_grantee, branch.subscribers) | 396 | self.assertIn(artifact_indirect_grantee, branch.subscribers) |
546 | 379 | self.assertIn(artifact_indirect_grantee, gitrepository.subscribers) | 397 | self.assertIn(artifact_indirect_grantee, gitrepository.subscribers) |
547 | 398 | self.assertIn(artifact_indirect_grantee, snap.subscribers) | ||
548 | 380 | self.assertIn(artifact_indirect_grantee, | 399 | self.assertIn(artifact_indirect_grantee, |
549 | 381 | removeSecurityProxy(specification).subscribers) | 400 | removeSecurityProxy(specification).subscribers) |
550 | 382 | 401 | ||
551 | @@ -389,7 +408,7 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
552 | 389 | return removeSecurityProxy( | 408 | return removeSecurityProxy( |
553 | 390 | concrete_artifact).getDirectSubscribers() | 409 | concrete_artifact).getDirectSubscribers() |
554 | 391 | 410 | ||
556 | 392 | def configure_test(bug, branch, gitrepository, specification, | 411 | def configure_test(bug, branch, gitrepository, snap, specification, |
557 | 393 | policy_team_grantee, policy_indirect_grantee, | 412 | policy_team_grantee, policy_indirect_grantee, |
558 | 394 | artifact_team_grantee, owner): | 413 | artifact_team_grantee, owner): |
559 | 395 | concrete_artifact = bug | 414 | concrete_artifact = bug |
560 | @@ -409,7 +428,7 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
561 | 409 | def get_subscribers(concrete_artifact): | 428 | def get_subscribers(concrete_artifact): |
562 | 410 | return concrete_artifact.subscribers | 429 | return concrete_artifact.subscribers |
563 | 411 | 430 | ||
565 | 412 | def configure_test(bug, branch, gitrepository, specification, | 431 | def configure_test(bug, branch, gitrepository, snap, specification, |
566 | 413 | policy_team_grantee, policy_indirect_grantee, | 432 | policy_team_grantee, policy_indirect_grantee, |
567 | 414 | artifact_team_grantee, owner): | 433 | artifact_team_grantee, owner): |
568 | 415 | concrete_artifact = branch | 434 | concrete_artifact = branch |
569 | @@ -438,7 +457,7 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
570 | 438 | def get_subscribers(concrete_artifact): | 457 | def get_subscribers(concrete_artifact): |
571 | 439 | return concrete_artifact.subscribers | 458 | return concrete_artifact.subscribers |
572 | 440 | 459 | ||
574 | 441 | def configure_test(bug, branch, gitrepository, specification, | 460 | def configure_test(bug, branch, gitrepository, snap, specification, |
575 | 442 | policy_team_grantee, policy_indirect_grantee, | 461 | policy_team_grantee, policy_indirect_grantee, |
576 | 443 | artifact_team_grantee, owner): | 462 | artifact_team_grantee, owner): |
577 | 444 | concrete_artifact = gitrepository | 463 | concrete_artifact = gitrepository |
578 | @@ -459,6 +478,26 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
579 | 459 | self._assert_artifact_change_unsubscribes( | 478 | self._assert_artifact_change_unsubscribes( |
580 | 460 | change_callback, configure_test) | 479 | change_callback, configure_test) |
581 | 461 | 480 | ||
582 | 481 | def _assert_snap_change_unsubscribes(self, change_callback): | ||
583 | 482 | |||
584 | 483 | def get_pillars(concrete_artifact): | ||
585 | 484 | return [concrete_artifact.project] | ||
586 | 485 | |||
587 | 486 | def get_subscribers(concrete_artifact): | ||
588 | 487 | return concrete_artifact.subscribers | ||
589 | 488 | |||
590 | 489 | def configure_test(bug, branch, gitrepository, snap, specification, | ||
591 | 490 | policy_team_grantee, policy_indirect_grantee, | ||
592 | 491 | artifact_team_grantee, owner): | ||
593 | 492 | concrete_artifact = snap | ||
594 | 493 | snap.subscribe(policy_team_grantee, owner) | ||
595 | 494 | snap.subscribe(policy_indirect_grantee, owner) | ||
596 | 495 | snap.subscribe(artifact_team_grantee, owner) | ||
597 | 496 | return concrete_artifact, get_pillars, get_subscribers | ||
598 | 497 | |||
599 | 498 | self._assert_artifact_change_unsubscribes( | ||
600 | 499 | change_callback, configure_test) | ||
601 | 500 | |||
602 | 462 | def _assert_specification_change_unsubscribes(self, change_callback): | 501 | def _assert_specification_change_unsubscribes(self, change_callback): |
603 | 463 | 502 | ||
604 | 464 | def get_pillars(concrete_artifact): | 503 | def get_pillars(concrete_artifact): |
605 | @@ -467,7 +506,7 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
606 | 467 | def get_subscribers(concrete_artifact): | 506 | def get_subscribers(concrete_artifact): |
607 | 468 | return concrete_artifact.subscribers | 507 | return concrete_artifact.subscribers |
608 | 469 | 508 | ||
610 | 470 | def configure_test(bug, branch, gitrepository, specification, | 509 | def configure_test(bug, branch, gitrepository, snap, specification, |
611 | 471 | policy_team_grantee, policy_indirect_grantee, | 510 | policy_team_grantee, policy_indirect_grantee, |
612 | 472 | artifact_team_grantee, owner): | 511 | artifact_team_grantee, owner): |
613 | 473 | naked_spec = removeSecurityProxy(specification) | 512 | naked_spec = removeSecurityProxy(specification) |
614 | @@ -496,6 +535,13 @@ class RemoveArtifactSubscriptionsJobTestCase(TestCaseWithFactory): | |||
615 | 496 | 535 | ||
616 | 497 | self._assert_gitrepository_change_unsubscribes(change_information_type) | 536 | self._assert_gitrepository_change_unsubscribes(change_information_type) |
617 | 498 | 537 | ||
618 | 538 | def test_change_information_type_snap(self): | ||
619 | 539 | def change_information_type(snap): | ||
620 | 540 | removeSecurityProxy(snap).information_type = ( | ||
621 | 541 | InformationType.PRIVATESECURITY) | ||
622 | 542 | |||
623 | 543 | self._assert_snap_change_unsubscribes(change_information_type) | ||
624 | 544 | |||
625 | 499 | def test_change_information_type_specification(self): | 545 | def test_change_information_type_specification(self): |
626 | 500 | def change_information_type(specification): | 546 | def change_information_type(specification): |
627 | 501 | removeSecurityProxy(specification).information_type = ( | 547 | removeSecurityProxy(specification).information_type = ( |
628 | diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py | |||
629 | index 31708c3..71f534b 100644 | |||
630 | --- a/lib/lp/snappy/interfaces/snap.py | |||
631 | +++ b/lib/lp/snappy/interfaces/snap.py | |||
632 | @@ -571,6 +571,10 @@ class ISnapView(Interface): | |||
633 | 571 | # Really ISnapBuild, patched in lp.snappy.interfaces.webservice. | 571 | # Really ISnapBuild, patched in lp.snappy.interfaces.webservice. |
634 | 572 | value_type=Reference(schema=Interface), readonly=True))) | 572 | value_type=Reference(schema=Interface), readonly=True))) |
635 | 573 | 573 | ||
636 | 574 | subscribers = CollectionField( | ||
637 | 575 | title=_("Persons subscribed to this snap recipe."), | ||
638 | 576 | readonly=True, value_type=Reference(IPerson)) | ||
639 | 577 | |||
640 | 574 | def visibleByUser(user): | 578 | def visibleByUser(user): |
641 | 575 | """Can the specified user see this snap recipe?""" | 579 | """Can the specified user see this snap recipe?""" |
642 | 576 | 580 | ||
643 | diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py | |||
644 | index 141f27a..ba89613 100644 | |||
645 | --- a/lib/lp/snappy/model/snap.py | |||
646 | +++ b/lib/lp/snappy/model/snap.py | |||
647 | @@ -5,6 +5,7 @@ from __future__ import absolute_import, print_function, unicode_literals | |||
648 | 5 | 5 | ||
649 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
650 | 7 | __all__ = [ | 7 | __all__ = [ |
651 | 8 | 'get_snap_privacy_filter', | ||
652 | 8 | 'Snap', | 9 | 'Snap', |
653 | 9 | ] | 10 | ] |
654 | 10 | 11 | ||
655 | @@ -26,6 +27,7 @@ from storm.expr import ( | |||
656 | 26 | And, | 27 | And, |
657 | 27 | Coalesce, | 28 | Coalesce, |
658 | 28 | Desc, | 29 | Desc, |
659 | 30 | Exists, | ||
660 | 29 | Join, | 31 | Join, |
661 | 30 | LeftJoin, | 32 | LeftJoin, |
662 | 31 | Not, | 33 | Not, |
663 | @@ -71,6 +73,7 @@ from lp.app.errors import ( | |||
664 | 71 | SubscriptionPrivacyViolation, | 73 | SubscriptionPrivacyViolation, |
665 | 72 | UserCannotUnsubscribePerson, | 74 | UserCannotUnsubscribePerson, |
666 | 73 | ) | 75 | ) |
667 | 76 | from lp.app.interfaces.launchpad import ILaunchpadCelebrities | ||
668 | 74 | from lp.app.interfaces.security import IAuthorization | 77 | from lp.app.interfaces.security import IAuthorization |
669 | 75 | from lp.app.interfaces.services import IService | 78 | from lp.app.interfaces.services import IService |
670 | 76 | from lp.buildmaster.enums import BuildStatus | 79 | from lp.buildmaster.enums import BuildStatus |
671 | @@ -132,6 +135,7 @@ from lp.registry.model.accesspolicy import ( | |||
672 | 132 | reconcile_access_for_artifact, | 135 | reconcile_access_for_artifact, |
673 | 133 | ) | 136 | ) |
674 | 134 | from lp.registry.model.distroseries import DistroSeries | 137 | from lp.registry.model.distroseries import DistroSeries |
675 | 138 | from lp.registry.model.person import Person | ||
676 | 135 | from lp.registry.model.series import ACTIVE_STATUSES | 139 | from lp.registry.model.series import ACTIVE_STATUSES |
677 | 136 | from lp.registry.model.teammembership import TeamParticipation | 140 | from lp.registry.model.teammembership import TeamParticipation |
678 | 137 | from lp.services.config import config | 141 | from lp.services.config import config |
679 | @@ -1165,6 +1169,13 @@ class Snap(Storm, WebhookTargetMixin): | |||
680 | 1165 | person.is_team and | 1169 | person.is_team and |
681 | 1166 | person.anyone_can_join()) | 1170 | person.anyone_can_join()) |
682 | 1167 | 1171 | ||
683 | 1172 | @property | ||
684 | 1173 | def subscribers(self): | ||
685 | 1174 | return Store.of(self).find( | ||
686 | 1175 | Person, | ||
687 | 1176 | SnapSubscription.person_id == Person.id, | ||
688 | 1177 | SnapSubscription.snap == self) | ||
689 | 1178 | |||
690 | 1168 | def subscribe(self, person, subscribed_by, ignore_permissions=False): | 1179 | def subscribe(self, person, subscribed_by, ignore_permissions=False): |
691 | 1169 | """See `ISnap`.""" | 1180 | """See `ISnap`.""" |
692 | 1170 | if not self._userCanBeSubscribed(person): | 1181 | if not self._userCanBeSubscribed(person): |
693 | @@ -1177,9 +1188,12 @@ class Snap(Storm, WebhookTargetMixin): | |||
694 | 1177 | person=person, snap=self, subscribed_by=subscribed_by) | 1188 | person=person, snap=self, subscribed_by=subscribed_by) |
695 | 1178 | Store.of(subscription).flush() | 1189 | Store.of(subscription).flush() |
696 | 1179 | service = getUtility(IService, "sharing") | 1190 | service = getUtility(IService, "sharing") |
700 | 1180 | service.ensureAccessGrants( | 1191 | _, _, _, snaps, _ = service.getVisibleArtifacts( |
701 | 1181 | [person], subscribed_by, snaps=[self], | 1192 | person, snaps=[self], ignore_permissions=True) |
702 | 1182 | ignore_permissions=ignore_permissions) | 1193 | if not snaps: |
703 | 1194 | service.ensureAccessGrants( | ||
704 | 1195 | [person], subscribed_by, snaps=[self], | ||
705 | 1196 | ignore_permissions=ignore_permissions) | ||
706 | 1183 | 1197 | ||
707 | 1184 | def unsubscribe(self, person, unsubscribed_by, ignore_permissions=False): | 1198 | def unsubscribe(self, person, unsubscribed_by, ignore_permissions=False): |
708 | 1185 | """See `ISnap`.""" | 1199 | """See `ISnap`.""" |
709 | @@ -1421,9 +1435,12 @@ class SnapSet: | |||
710 | 1421 | expressions.append(Snap.owner == owner) | 1435 | expressions.append(Snap.owner == owner) |
711 | 1422 | return IStore(Snap).find(Snap, *expressions) | 1436 | return IStore(Snap).find(Snap, *expressions) |
712 | 1423 | 1437 | ||
714 | 1424 | def findByIds(self, snap_ids): | 1438 | def findByIds(self, snap_ids, visible_by_user=None): |
715 | 1425 | """See `ISnapSet`.""" | 1439 | """See `ISnapSet`.""" |
717 | 1426 | return IStore(ISnap).find(Snap, Snap.id.is_in(snap_ids)) | 1440 | clauses = [Snap.id.is_in(snap_ids)] |
718 | 1441 | if visible_by_user is not None: | ||
719 | 1442 | clauses.append(get_snap_privacy_filter(visible_by_user)) | ||
720 | 1443 | return IStore(Snap).find(Snap, *clauses) | ||
721 | 1427 | 1444 | ||
722 | 1428 | def findByOwner(self, owner): | 1445 | def findByOwner(self, owner): |
723 | 1429 | """See `ISnapSet`.""" | 1446 | """See `ISnapSet`.""" |
724 | @@ -1694,9 +1711,11 @@ class SnapStoreSecretsEncryptedContainer(NaClEncryptedContainerBase): | |||
725 | 1694 | 1711 | ||
726 | 1695 | 1712 | ||
727 | 1696 | def get_snap_privacy_filter(user): | 1713 | def get_snap_privacy_filter(user): |
730 | 1697 | """Returns the filter for all private Snaps that the given user is | 1714 | """Returns the filter for all Snaps that the given user has access to, |
731 | 1698 | subscribed to (that is, has access without being directly an owner). | 1715 | including private snaps where the user has proper permission. |
732 | 1699 | 1716 | ||
733 | 1717 | :param user: An IPerson, or a class attribute that references an IPerson | ||
734 | 1718 | in the database. | ||
735 | 1700 | :return: A storm condition. | 1719 | :return: A storm condition. |
736 | 1701 | """ | 1720 | """ |
737 | 1702 | # XXX pappacena 2021-02-12: Once we do the migration to back fill | 1721 | # XXX pappacena 2021-02-12: Once we do the migration to back fill |
738 | @@ -1707,10 +1726,6 @@ def get_snap_privacy_filter(user): | |||
739 | 1707 | if user is None: | 1726 | if user is None: |
740 | 1708 | return private_snap == False | 1727 | return private_snap == False |
741 | 1709 | 1728 | ||
742 | 1710 | roles = IPersonRoles(user) | ||
743 | 1711 | if roles.in_admin or roles.in_commercial_admin: | ||
744 | 1712 | return True | ||
745 | 1713 | |||
746 | 1714 | artifact_grant_query = Coalesce( | 1729 | artifact_grant_query = Coalesce( |
747 | 1715 | ArrayIntersects( | 1730 | ArrayIntersects( |
748 | 1716 | SQL("%s.access_grants" % Snap.__storm_table__), | 1731 | SQL("%s.access_grants" % Snap.__storm_table__), |
749 | @@ -1732,4 +1747,13 @@ def get_snap_privacy_filter(user): | |||
750 | 1732 | where=(TeamParticipation.person == user) | 1747 | where=(TeamParticipation.person == user) |
751 | 1733 | )), False) | 1748 | )), False) |
752 | 1734 | 1749 | ||
754 | 1735 | return Or(private_snap == False, artifact_grant_query, policy_grant_query) | 1750 | admin_team_id = getUtility(ILaunchpadCelebrities).admin.id |
755 | 1751 | user_is_admin = Exists(Select( | ||
756 | 1752 | TeamParticipation.personID, | ||
757 | 1753 | tables=[TeamParticipation], | ||
758 | 1754 | where=And( | ||
759 | 1755 | TeamParticipation.teamID == admin_team_id, | ||
760 | 1756 | TeamParticipation.person == user))) | ||
761 | 1757 | return Or( | ||
762 | 1758 | private_snap == False, artifact_grant_query, policy_grant_query, | ||
763 | 1759 | user_is_admin) | ||
764 | diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py | |||
765 | index 39362b3..04ed945 100644 | |||
766 | --- a/lib/lp/snappy/tests/test_snap.py | |||
767 | +++ b/lib/lp/snappy/tests/test_snap.py | |||
768 | @@ -3102,8 +3102,7 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
769 | 3102 | ws_snaps = [ | 3102 | ws_snaps = [ |
770 | 3103 | self.webservice.getAbsoluteUrl(api_url(snap)) | 3103 | self.webservice.getAbsoluteUrl(api_url(snap)) |
771 | 3104 | for snap in snaps] | 3104 | for snap in snaps] |
774 | 3105 | commercial_admin = ( | 3105 | admin = getUtility(ILaunchpadCelebrities).admin.teamowner |
773 | 3106 | getUtility(ILaunchpadCelebrities).commercial_admin.teamowner) | ||
775 | 3107 | logout() | 3106 | logout() |
776 | 3108 | 3107 | ||
777 | 3109 | # Anonymous requests can only see public snaps. | 3108 | # Anonymous requests can only see public snaps. |
778 | @@ -3141,15 +3140,15 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
779 | 3141 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) | 3140 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
780 | 3142 | 3141 | ||
781 | 3143 | # Admins can see all snaps with this URL. | 3142 | # Admins can see all snaps with this URL. |
785 | 3144 | commercial_admin_webservice = webservice_for_person( | 3143 | admin_webservice = webservice_for_person( |
786 | 3145 | commercial_admin, permission=OAuthPermission.READ_PRIVATE) | 3144 | admin, permission=OAuthPermission.READ_PRIVATE) |
787 | 3146 | response = commercial_admin_webservice.named_get( | 3145 | response = admin_webservice.named_get( |
788 | 3147 | "/+snaps", "findByURL", url=urls[0], api_version="devel") | 3146 | "/+snaps", "findByURL", url=urls[0], api_version="devel") |
789 | 3148 | self.assertEqual(200, response.status) | 3147 | self.assertEqual(200, response.status) |
790 | 3149 | self.assertContentEqual( | 3148 | self.assertContentEqual( |
791 | 3150 | ws_snaps[:4], | 3149 | ws_snaps[:4], |
792 | 3151 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) | 3150 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
794 | 3152 | response = commercial_admin_webservice.named_get( | 3151 | response = admin_webservice.named_get( |
795 | 3153 | "/+snaps", "findByURL", url=urls[0], owner=person_urls[0], | 3152 | "/+snaps", "findByURL", url=urls[0], owner=person_urls[0], |
796 | 3154 | api_version="devel") | 3153 | api_version="devel") |
797 | 3155 | self.assertEqual(200, response.status) | 3154 | self.assertEqual(200, response.status) |
798 | @@ -3180,8 +3179,7 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
799 | 3180 | ws_snaps = [ | 3179 | ws_snaps = [ |
800 | 3181 | self.webservice.getAbsoluteUrl(api_url(snap)) | 3180 | self.webservice.getAbsoluteUrl(api_url(snap)) |
801 | 3182 | for snap in snaps] | 3181 | for snap in snaps] |
804 | 3183 | commercial_admin = ( | 3182 | admin = getUtility(ILaunchpadCelebrities).admin.teamowner |
803 | 3184 | getUtility(ILaunchpadCelebrities).commercial_admin.teamowner) | ||
805 | 3185 | logout() | 3183 | logout() |
806 | 3186 | prefix = "https://git.example.org/foo/" | 3184 | prefix = "https://git.example.org/foo/" |
807 | 3187 | 3185 | ||
808 | @@ -3222,16 +3220,16 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
809 | 3222 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) | 3220 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
810 | 3223 | 3221 | ||
811 | 3224 | # Admins can see all snaps with this URL prefix. | 3222 | # Admins can see all snaps with this URL prefix. |
815 | 3225 | commercial_admin_webservice = webservice_for_person( | 3223 | admin_webservice = webservice_for_person( |
816 | 3226 | commercial_admin, permission=OAuthPermission.READ_PRIVATE) | 3224 | admin, permission=OAuthPermission.READ_PRIVATE) |
817 | 3227 | response = commercial_admin_webservice.named_get( | 3225 | response = admin_webservice.named_get( |
818 | 3228 | "/+snaps", "findByURLPrefix", url_prefix=prefix, | 3226 | "/+snaps", "findByURLPrefix", url_prefix=prefix, |
819 | 3229 | api_version="devel") | 3227 | api_version="devel") |
820 | 3230 | self.assertEqual(200, response.status) | 3228 | self.assertEqual(200, response.status) |
821 | 3231 | self.assertContentEqual( | 3229 | self.assertContentEqual( |
822 | 3232 | ws_snaps[:8], | 3230 | ws_snaps[:8], |
823 | 3233 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) | 3231 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
825 | 3234 | response = commercial_admin_webservice.named_get( | 3232 | response = admin_webservice.named_get( |
826 | 3235 | "/+snaps", "findByURLPrefix", url_prefix=prefix, | 3233 | "/+snaps", "findByURLPrefix", url_prefix=prefix, |
827 | 3236 | owner=person_urls[0], api_version="devel") | 3234 | owner=person_urls[0], api_version="devel") |
828 | 3237 | self.assertEqual(200, response.status) | 3235 | self.assertEqual(200, response.status) |
829 | @@ -3264,8 +3262,7 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
830 | 3264 | ws_snaps = [ | 3262 | ws_snaps = [ |
831 | 3265 | self.webservice.getAbsoluteUrl(api_url(snap)) | 3263 | self.webservice.getAbsoluteUrl(api_url(snap)) |
832 | 3266 | for snap in snaps] | 3264 | for snap in snaps] |
835 | 3267 | commercial_admin = ( | 3265 | admin = getUtility(ILaunchpadCelebrities).admin.teamowner |
834 | 3268 | getUtility(ILaunchpadCelebrities).commercial_admin.teamowner) | ||
836 | 3269 | logout() | 3266 | logout() |
837 | 3270 | prefixes = [ | 3267 | prefixes = [ |
838 | 3271 | "https://git.example.org/foo/", "https://git.example.org/bar/"] | 3268 | "https://git.example.org/foo/", "https://git.example.org/bar/"] |
839 | @@ -3307,16 +3304,16 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
840 | 3307 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) | 3304 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
841 | 3308 | 3305 | ||
842 | 3309 | # Admins can see all snaps with any of these URL prefixes. | 3306 | # Admins can see all snaps with any of these URL prefixes. |
846 | 3310 | commercial_admin_webservice = webservice_for_person( | 3307 | admin_webservice = webservice_for_person( |
847 | 3311 | commercial_admin, permission=OAuthPermission.READ_PRIVATE) | 3308 | admin, permission=OAuthPermission.READ_PRIVATE) |
848 | 3312 | response = commercial_admin_webservice.named_get( | 3309 | response = admin_webservice.named_get( |
849 | 3313 | "/+snaps", "findByURLPrefixes", url_prefixes=prefixes, | 3310 | "/+snaps", "findByURLPrefixes", url_prefixes=prefixes, |
850 | 3314 | api_version="devel") | 3311 | api_version="devel") |
851 | 3315 | self.assertEqual(200, response.status) | 3312 | self.assertEqual(200, response.status) |
852 | 3316 | self.assertContentEqual( | 3313 | self.assertContentEqual( |
853 | 3317 | ws_snaps[:16], | 3314 | ws_snaps[:16], |
854 | 3318 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) | 3315 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
856 | 3319 | response = commercial_admin_webservice.named_get( | 3316 | response = admin_webservice.named_get( |
857 | 3320 | "/+snaps", "findByURLPrefixes", url_prefixes=prefixes, | 3317 | "/+snaps", "findByURLPrefixes", url_prefixes=prefixes, |
858 | 3321 | owner=person_urls[0], api_version="devel") | 3318 | owner=person_urls[0], api_version="devel") |
859 | 3322 | self.assertEqual(200, response.status) | 3319 | self.assertEqual(200, response.status) |
860 | @@ -3341,8 +3338,7 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
861 | 3341 | ws_snaps = [ | 3338 | ws_snaps = [ |
862 | 3342 | self.webservice.getAbsoluteUrl(api_url(snap)) | 3339 | self.webservice.getAbsoluteUrl(api_url(snap)) |
863 | 3343 | for snap in snaps] | 3340 | for snap in snaps] |
866 | 3344 | commercial_admin = ( | 3341 | admin = getUtility(ILaunchpadCelebrities).admin.teamowner |
865 | 3345 | getUtility(ILaunchpadCelebrities).commercial_admin.teamowner) | ||
867 | 3346 | logout() | 3342 | logout() |
868 | 3347 | 3343 | ||
869 | 3348 | # Anonymous requests can only see public snaps. | 3344 | # Anonymous requests can only see public snaps. |
870 | @@ -3382,16 +3378,16 @@ class TestSnapWebservice(TestCaseWithFactory): | |||
871 | 3382 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) | 3378 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
872 | 3383 | 3379 | ||
873 | 3384 | # Admins can see all snaps with this store name. | 3380 | # Admins can see all snaps with this store name. |
877 | 3385 | commercial_admin_webservice = webservice_for_person( | 3381 | admin_webservice = webservice_for_person( |
878 | 3386 | commercial_admin, permission=OAuthPermission.READ_PRIVATE) | 3382 | admin, permission=OAuthPermission.READ_PRIVATE) |
879 | 3387 | response = commercial_admin_webservice.named_get( | 3383 | response = admin_webservice.named_get( |
880 | 3388 | "/+snaps", "findByStoreName", store_name=store_names[0], | 3384 | "/+snaps", "findByStoreName", store_name=store_names[0], |
881 | 3389 | api_version="devel") | 3385 | api_version="devel") |
882 | 3390 | self.assertEqual(200, response.status) | 3386 | self.assertEqual(200, response.status) |
883 | 3391 | self.assertContentEqual( | 3387 | self.assertContentEqual( |
884 | 3392 | ws_snaps[:4], | 3388 | ws_snaps[:4], |
885 | 3393 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) | 3389 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
887 | 3394 | response = commercial_admin_webservice.named_get( | 3390 | response = admin_webservice.named_get( |
888 | 3395 | "/+snaps", "findByStoreName", store_name=store_names[0], | 3391 | "/+snaps", "findByStoreName", store_name=store_names[0], |
889 | 3396 | owner=person_urls[0], api_version="devel") | 3392 | owner=person_urls[0], api_version="devel") |
890 | 3397 | self.assertEqual(200, response.status) | 3393 | self.assertEqual(200, response.status) |
Pushed the requested changes, and added a comment about `get_snap_ privacy_ filter` method.