Merge ~pappacena/launchpad:snap-pillar-list-filters into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: 3742242858c44d9b9733e109be0c851afda3ba14
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:snap-pillar-list-filters
Merge into: launchpad:master
Prerequisite: ~pappacena/launchpad:snap-pillar-subscribe-ui
Diff against target: 323 lines (+225/-17)
2 files modified
lib/lp/snappy/browser/tests/test_snaplisting.py (+201/-1)
lib/lp/snappy/model/snap.py (+24/-16)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+398751@code.launchpad.net

Commit message

Filtering for visible snaps on +snaps pages

To post a comment you must log in.
94902ed... by Thiago F. Pappacena

Merge branch 'snap-pillar-subscribe-ui' into snap-pillar-list-filters

3742242... by Thiago F. Pappacena

Merge branch 'snap-pillar-subscribe-ui' into snap-pillar-list-filters

Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/snappy/browser/tests/test_snaplisting.py b/lib/lp/snappy/browser/tests/test_snaplisting.py
index ce229c1..9216c91 100644
--- a/lib/lp/snappy/browser/tests/test_snaplisting.py
+++ b/lib/lp/snappy/browser/tests/test_snaplisting.py
@@ -1,4 +1,4 @@
1# Copyright 2015-2017 Canonical Ltd. This software is licensed under the1# Copyright 2015-2021 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Test snap package listings."""4"""Test snap package listings."""
@@ -27,7 +27,9 @@ from lp.services.database.constants import (
27 SEVEN_DAYS_AGO,27 SEVEN_DAYS_AGO,
28 UTC_NOW,28 UTC_NOW,
29 )29 )
30from lp.services.features.testing import FeatureFixture
30from lp.services.webapp import canonical_url31from lp.services.webapp import canonical_url
32from lp.snappy.interfaces.snap import SNAP_TESTING_FLAGS
31from lp.testing import (33from lp.testing import (
32 ANONYMOUS,34 ANONYMOUS,
33 BrowserTestCase,35 BrowserTestCase,
@@ -154,6 +156,204 @@ class TestSnapListing(BrowserTestCase):
154 snap-name.* Team Name.* ~.*:.* .*156 snap-name.* Team Name.* ~.*:.* .*
155 snap-name.* Team Name.* lp:.* .*""", text)157 snap-name.* Team Name.* lp:.* .*""", text)
156158
159 def test_project_private_snap_listing(self):
160 # Only users with permission can see private snap packages in the list
161 # for a project.
162 self.useFixture(FeatureFixture(SNAP_TESTING_FLAGS))
163 project = self.factory.makeProduct(displayname="Snappable")
164 private_owner = self.factory.makePerson()
165 user_with_permission = self.factory.makePerson()
166 someone_else = self.factory.makePerson()
167 private_snap = self.factory.makeSnap(
168 name="private-snap",
169 private=True, registrant=private_owner, owner=private_owner,
170 branch=self.factory.makeProductBranch(product=project),
171 date_created=ONE_DAY_AGO)
172 with person_logged_in(private_owner):
173 private_snap.subscribe(user_with_permission, private_owner)
174 [ref] = self.factory.makeGitRefs(target=project)
175 self.factory.makeSnap(git_ref=ref, date_created=UTC_NOW)
176
177 full_list = """
178 Snap packages for Snappable
179 Name Owner Source Registered
180 snap-name.* Team Name.* ~.*:.* .*
181 private-snap.* Person-name.* lp:.* .*"""
182
183 public_list = """
184 Snap packages for Snappable
185 Name Owner Source Registered
186 snap-name.* Team Name.* ~.*:.* .*"""
187
188 # private_owner: full_list.
189 self.assertTextMatchesExpressionIgnoreWhitespace(
190 full_list, self.getMainText(project, "+snaps", user=private_owner))
191 # user_with_permission: full_list.
192 self.assertTextMatchesExpressionIgnoreWhitespace(
193 full_list,
194 self.getMainText(project, "+snaps", user=user_with_permission))
195 # someone_else: public_list.
196 self.assertTextMatchesExpressionIgnoreWhitespace(
197 public_list,
198 self.getMainText(project, "+snaps", user=someone_else))
199 # Not logged in: public_list.
200 self.assertTextMatchesExpressionIgnoreWhitespace(
201 public_list, self.getMainText(project, "+snaps", user=None))
202
203 def test_person_private_snap_listing(self):
204 self.useFixture(FeatureFixture(SNAP_TESTING_FLAGS))
205 private_owner = self.factory.makePerson(name="random-user")
206 user_with_permission = self.factory.makePerson()
207 someone_else = self.factory.makePerson()
208 private_snap = self.factory.makeSnap(
209 name="private-snap",
210 private=True, registrant=private_owner, owner=private_owner,
211 date_created=ONE_DAY_AGO)
212 with person_logged_in(private_owner):
213 private_snap.subscribe(user_with_permission, private_owner)
214 [ref] = self.factory.makeGitRefs()
215 self.factory.makeSnap(
216 private=False, registrant=private_owner, owner=private_owner,
217 git_ref=ref, date_created=UTC_NOW)
218
219 full_list = """
220 Snap packages for Random-user
221 Name Source Registered
222 snap-name.* ~.*:.* .*
223 private-snap.* lp:.* .*"""
224
225 public_list = """
226 Snap packages for Random-user
227 Name Source Registered
228 snap-name.* ~.*:.* .*"""
229
230 # private_owner: full_list.
231 self.assertTextMatchesExpressionIgnoreWhitespace(
232 full_list, self.getMainText(private_owner, "+snaps",
233 user=private_owner))
234 # user_with_permission: full_list.
235 self.assertTextMatchesExpressionIgnoreWhitespace(
236 full_list, self.getMainText(private_owner, "+snaps",
237 user=user_with_permission))
238 # someone_else: public_list.
239 self.assertTextMatchesExpressionIgnoreWhitespace(
240 public_list, self.getMainText(private_owner, "+snaps",
241 user=someone_else))
242 # Not logged in: public_list.
243 self.assertTextMatchesExpressionIgnoreWhitespace(
244 public_list, self.getMainText(private_owner, "+snaps", user=None))
245
246 def test_branch_private_snap_listing(self):
247 # Only certain users can see private snaps on branch listing.
248 self.useFixture(FeatureFixture(SNAP_TESTING_FLAGS))
249 private_owner = self.factory.makePerson(name="random-user")
250 user_with_permission = self.factory.makePerson()
251 someone_else = self.factory.makePerson()
252 branch = self.factory.makeAnyBranch()
253 private_snap = self.factory.makeSnap(
254 private=True, name="private-snap",
255 owner=private_owner, registrant=private_owner, branch=branch)
256 with person_logged_in(private_owner):
257 private_snap.subscribe(user_with_permission, private_owner)
258 self.factory.makeSnap(
259 private=False, owner=private_owner, registrant=private_owner,
260 branch=branch)
261 full_list = """
262 Snap packages for lp:.*
263 Name Owner Registered
264 snap-name.* Random-user.* .*
265 private-snap.* Random-user.* .*"""
266 public_list = """
267 Snap packages for lp:.*
268 Name Owner Registered
269 snap-name.* Random-user.* .*"""
270
271 self.assertTextMatchesExpressionIgnoreWhitespace(
272 full_list, self.getMainText(branch, "+snaps", user=private_owner))
273 self.assertTextMatchesExpressionIgnoreWhitespace(
274 full_list, self.getMainText(branch, "+snaps",
275 user=user_with_permission))
276 self.assertTextMatchesExpressionIgnoreWhitespace(
277 public_list, self.getMainText(branch, "+snaps", user=someone_else))
278 self.assertTextMatchesExpressionIgnoreWhitespace(
279 public_list, self.getMainText(branch, "+snaps", user=None))
280
281 def test_git_repository_private_snap_listing(self):
282 # Only certain users can see private snaps on git repo listing.
283 self.useFixture(FeatureFixture(SNAP_TESTING_FLAGS))
284 private_owner = self.factory.makePerson(name="random-user")
285 user_with_permission = self.factory.makePerson()
286 someone_else = self.factory.makePerson()
287 repository = self.factory.makeGitRepository()
288 [ref] = self.factory.makeGitRefs(repository=repository)
289 private_snap = self.factory.makeSnap(
290 private=True, name="private-snap",
291 owner=private_owner, registrant=private_owner, git_ref=ref)
292 with person_logged_in(private_owner):
293 private_snap.subscribe(user_with_permission, private_owner)
294 self.factory.makeSnap(
295 private=False, owner=private_owner, registrant=private_owner,
296 git_ref=ref)
297
298 full_list = """
299 Snap packages for lp:~.*
300 Name Owner Registered
301 snap-name.* Random-user.* .*
302 private-snap.* Random-user.* .*"""
303 public_list = """
304 Snap packages for lp:.*
305 Name Owner Registered
306 snap-name.* Random-user.* .*"""
307
308 self.assertTextMatchesExpressionIgnoreWhitespace(
309 full_list,
310 self.getMainText(repository, "+snaps", user=private_owner))
311 self.assertTextMatchesExpressionIgnoreWhitespace(
312 full_list,
313 self.getMainText(repository, "+snaps", user=user_with_permission))
314 self.assertTextMatchesExpressionIgnoreWhitespace(
315 public_list,
316 self.getMainText(repository, "+snaps", user=someone_else))
317 self.assertTextMatchesExpressionIgnoreWhitespace(
318 public_list, self.getMainText(repository, "+snaps", user=None))
319
320 def test_git_ref_private_snap_listing(self):
321 # Only certain users can see private snaps on git ref listing.
322 self.useFixture(FeatureFixture(SNAP_TESTING_FLAGS))
323 private_owner = self.factory.makePerson(name="random-user")
324 user_with_permission = self.factory.makePerson()
325 someone_else = self.factory.makePerson()
326 repository = self.factory.makeGitRepository()
327 [ref] = self.factory.makeGitRefs(repository=repository)
328 private_snap = self.factory.makeSnap(
329 private=True, name="private-snap",
330 owner=private_owner, registrant=private_owner, git_ref=ref)
331 with person_logged_in(private_owner):
332 private_snap.subscribe(user_with_permission, private_owner)
333 self.factory.makeSnap(
334 private=False, owner=private_owner, registrant=private_owner,
335 git_ref=ref)
336
337 full_list = """
338 Snap packages for ~.*:.*
339 Name Owner Registered
340 snap-name.* Random-user.* .*
341 private-snap.* Random-user.* .*"""
342 public_list = """
343 Snap packages for ~.*:.*
344 Name Owner Registered
345 snap-name.* Random-user.* .*"""
346
347 self.assertTextMatchesExpressionIgnoreWhitespace(
348 full_list, self.getMainText(ref, "+snaps", user=private_owner))
349 self.assertTextMatchesExpressionIgnoreWhitespace(
350 full_list,
351 self.getMainText(ref, "+snaps", user=user_with_permission))
352 self.assertTextMatchesExpressionIgnoreWhitespace(
353 public_list, self.getMainText(ref, "+snaps", user=someone_else))
354 self.assertTextMatchesExpressionIgnoreWhitespace(
355 public_list, self.getMainText(ref, "+snaps", user=None))
356
157 def assertSnapsQueryCount(self, context, item_creator):357 def assertSnapsQueryCount(self, context, item_creator):
158 self.pushConfig("launchpad", default_batch_size=10)358 self.pushConfig("launchpad", default_batch_size=10)
159 recorder1, recorder2 = record_two_runs(359 recorder1, recorder2 = record_two_runs(
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index 287ccc3..b101e18 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -1438,7 +1438,8 @@ class SnapSet:
1438 raise NoSuchSnap(name)1438 raise NoSuchSnap(name)
1439 return snap1439 return snap
14401440
1441 def _getSnapsFromCollection(self, collection, owner=None):1441 def _getSnapsFromCollection(self, collection, owner=None,
1442 visible_by_user=None):
1442 if IBranchCollection.providedBy(collection):1443 if IBranchCollection.providedBy(collection):
1443 id_column = Snap.branch_id1444 id_column = Snap.branch_id
1444 ids = collection.getBranchIds()1445 ids = collection.getBranchIds()
@@ -1448,6 +1449,7 @@ class SnapSet:
1448 expressions = [id_column.is_in(ids._get_select())]1449 expressions = [id_column.is_in(ids._get_select())]
1449 if owner is not None:1450 if owner is not None:
1450 expressions.append(Snap.owner == owner)1451 expressions.append(Snap.owner == owner)
1452 expressions.append(get_snap_privacy_filter(visible_by_user))
1451 return IStore(Snap).find(Snap, *expressions)1453 return IStore(Snap).find(Snap, *expressions)
14521454
1453 def findByIds(self, snap_ids, visible_by_user=None):1455 def findByIds(self, snap_ids, visible_by_user=None):
@@ -1465,8 +1467,10 @@ class SnapSet:
1465 """See `ISnapSet`."""1467 """See `ISnapSet`."""
1466 def _getSnaps(collection):1468 def _getSnaps(collection):
1467 collection = collection.visibleByUser(visible_by_user)1469 collection = collection.visibleByUser(visible_by_user)
1468 owned = self._getSnapsFromCollection(collection.ownedBy(person))1470 owned = self._getSnapsFromCollection(
1469 packaged = self._getSnapsFromCollection(collection, owner=person)1471 collection.ownedBy(person), visible_by_user=visible_by_user)
1472 packaged = self._getSnapsFromCollection(
1473 collection, owner=person, visible_by_user=visible_by_user)
1470 return owned.union(packaged)1474 return owned.union(packaged)
14711475
1472 bzr_collection = removeSecurityProxy(getUtility(IAllBranches))1476 bzr_collection = removeSecurityProxy(getUtility(IAllBranches))
@@ -1481,28 +1485,35 @@ class SnapSet:
1481 """See `ISnapSet`."""1485 """See `ISnapSet`."""
1482 def _getSnaps(collection):1486 def _getSnaps(collection):
1483 return self._getSnapsFromCollection(1487 return self._getSnapsFromCollection(
1484 collection.visibleByUser(visible_by_user))1488 collection.visibleByUser(visible_by_user),
1489 visible_by_user=visible_by_user)
14851490
1486 bzr_collection = removeSecurityProxy(IBranchCollection(project))1491 bzr_collection = removeSecurityProxy(IBranchCollection(project))
1487 git_collection = removeSecurityProxy(IGitCollection(project))1492 git_collection = removeSecurityProxy(IGitCollection(project))
1488 return _getSnaps(bzr_collection).union(_getSnaps(git_collection))1493 return _getSnaps(bzr_collection).union(_getSnaps(git_collection))
14891494
1490 def findByBranch(self, branch):1495 def findByBranch(self, branch, visible_by_user=None):
1491 """See `ISnapSet`."""1496 """See `ISnapSet`."""
1492 return IStore(Snap).find(Snap, Snap.branch == branch)1497 return IStore(Snap).find(
1498 Snap,
1499 Snap.branch == branch,
1500 get_snap_privacy_filter(visible_by_user))
14931501
1494 def findByGitRepository(self, repository, paths=None):1502 def findByGitRepository(self, repository, paths=None,
1503 visible_by_user=None):
1495 """See `ISnapSet`."""1504 """See `ISnapSet`."""
1496 clauses = [Snap.git_repository == repository]1505 clauses = [Snap.git_repository == repository]
1497 if paths is not None:1506 if paths is not None:
1498 clauses.append(Snap.git_path.is_in(paths))1507 clauses.append(Snap.git_path.is_in(paths))
1508 clauses.append(get_snap_privacy_filter(visible_by_user))
1499 return IStore(Snap).find(Snap, *clauses)1509 return IStore(Snap).find(Snap, *clauses)
15001510
1501 def findByGitRef(self, ref):1511 def findByGitRef(self, ref, visible_by_user=None):
1502 """See `ISnapSet`."""1512 """See `ISnapSet`."""
1503 return IStore(Snap).find(1513 return IStore(Snap).find(
1504 Snap,1514 Snap,
1505 Snap.git_repository == ref.repository, Snap.git_path == ref.path)1515 Snap.git_repository == ref.repository, Snap.git_path == ref.path,
1516 get_snap_privacy_filter(visible_by_user))
15061517
1507 def findByContext(self, context, visible_by_user=None, order_by_date=True):1518 def findByContext(self, context, visible_by_user=None, order_by_date=True):
1508 if IPerson.providedBy(context):1519 if IPerson.providedBy(context):
@@ -1510,16 +1521,13 @@ class SnapSet:
1510 elif IProduct.providedBy(context):1521 elif IProduct.providedBy(context):
1511 snaps = self.findByProject(1522 snaps = self.findByProject(
1512 context, visible_by_user=visible_by_user)1523 context, visible_by_user=visible_by_user)
1513 # XXX cjwatson 2015-09-15: At the moment we can assume that if you
1514 # can see the source context then you can see the snap packages
1515 # based on it. This will cease to be true if snap packages gain
1516 # privacy of their own.
1517 elif IBranch.providedBy(context):1524 elif IBranch.providedBy(context):
1518 snaps = self.findByBranch(context)1525 snaps = self.findByBranch(context, visible_by_user=visible_by_user)
1519 elif IGitRepository.providedBy(context):1526 elif IGitRepository.providedBy(context):
1520 snaps = self.findByGitRepository(context)1527 snaps = self.findByGitRepository(
1528 context, visible_by_user=visible_by_user)
1521 elif IGitRef.providedBy(context):1529 elif IGitRef.providedBy(context):
1522 snaps = self.findByGitRef(context)1530 snaps = self.findByGitRef(context, visible_by_user=visible_by_user)
1523 else:1531 else:
1524 raise BadSnapSearchContext(context)1532 raise BadSnapSearchContext(context)
1525 if order_by_date:1533 if order_by_date: