Merge lp:~cjwatson/launchpad/snap-find-by-store-name into lp:launchpad
- snap-find-by-store-name
- Merge into devel
Proposed by
Colin Watson
Status: | Merged |
---|---|
Merged at revision: | 19030 |
Proposed branch: | lp:~cjwatson/launchpad/snap-find-by-store-name |
Merge into: | lp:launchpad |
Diff against target: |
297 lines (+152/-3) 4 files modified
database/schema/patch-2210-05-0.sql (+9/-0) lib/lp/snappy/interfaces/snap.py (+17/-0) lib/lp/snappy/model/snap.py (+11/-3) lib/lp/snappy/tests/test_snap.py (+115/-0) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad/snap-find-by-store-name |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code db | Approve | |
Review via email: mp+370562@code.launchpad.net |
Commit message
Add SnapSet.
Description of the change
This will be useful for the next iteration of build.snapcraft.io, and is handy for ad-hoc operational queries as well.
To post a comment you must log in.
Revision history for this message
William Grant (wgrant) : | # |
review:
Approve
(code db)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'database/schema/patch-2210-05-0.sql' |
2 | --- database/schema/patch-2210-05-0.sql 1970-01-01 00:00:00 +0000 |
3 | +++ database/schema/patch-2210-05-0.sql 2019-08-22 10:39:42 +0000 |
4 | @@ -0,0 +1,9 @@ |
5 | +-- Copyright 2019 Canonical Ltd. This software is licensed under the |
6 | +-- GNU Affero General Public License version 3 (see the file LICENSE). |
7 | + |
8 | +SET client_min_messages=ERROR; |
9 | + |
10 | +CREATE INDEX snap__git_repository_url__idx ON Snap (git_repository_url); |
11 | +CREATE INDEX snap__store_name__idx ON Snap (store_name); |
12 | + |
13 | +INSERT INTO LaunchpadDatabaseRevision VALUES (2210, 05, 0); |
14 | |
15 | === modified file 'lib/lp/snappy/interfaces/snap.py' |
16 | --- lib/lp/snappy/interfaces/snap.py 2019-06-21 11:30:26 +0000 |
17 | +++ lib/lp/snappy/interfaces/snap.py 2019-08-22 10:39:42 +0000 |
18 | @@ -1005,6 +1005,23 @@ |
19 | this user; otherwise, only return publicly-visible packages. |
20 | """ |
21 | |
22 | + @operation_parameters( |
23 | + store_name=TextLine( |
24 | + title=_("The registered store package name to search for.")), |
25 | + owner=Reference(IPerson, title=_("Owner"), required=False)) |
26 | + @call_with(visible_by_user=REQUEST_USER) |
27 | + @operation_returns_collection_of(ISnap) |
28 | + @export_read_operation() |
29 | + @operation_for_version("devel") |
30 | + def findByStoreName(store_name, owner=None, visible_by_user=None): |
31 | + """Return all snap packages with the given store package name. |
32 | + |
33 | + :param store_name: A registered store package name. |
34 | + :param owner: Only return packages owned by this user. |
35 | + :param visible_by_user: If not None, only return packages visible by |
36 | + this user; otherwise, only return publicly-visible packages. |
37 | + """ |
38 | + |
39 | def preloadDataForSnaps(snaps, user): |
40 | """Load the data related to a list of snap packages.""" |
41 | |
42 | |
43 | === modified file 'lib/lp/snappy/model/snap.py' |
44 | --- lib/lp/snappy/model/snap.py 2019-08-21 10:36:27 +0000 |
45 | +++ lib/lp/snappy/model/snap.py 2019-08-22 10:39:42 +0000 |
46 | @@ -1244,7 +1244,7 @@ |
47 | snaps.order_by(Desc(Snap.date_last_modified)) |
48 | return snaps |
49 | |
50 | - def _findByURLVisibilityClause(self, visible_by_user): |
51 | + def _findSnapVisibilityClause(self, visible_by_user): |
52 | # XXX cjwatson 2016-11-25: This is in principle a poor query, but we |
53 | # don't yet have the access grant infrastructure to do better, and |
54 | # in any case the numbers involved should be very small. |
55 | @@ -1266,7 +1266,7 @@ |
56 | clauses = [Snap.git_repository_url == url] |
57 | if owner is not None: |
58 | clauses.append(Snap.owner == owner) |
59 | - clauses.append(self._findByURLVisibilityClause(visible_by_user)) |
60 | + clauses.append(self._findSnapVisibilityClause(visible_by_user)) |
61 | return IStore(Snap).find(Snap, *clauses) |
62 | |
63 | def findByURLPrefix(self, url_prefix, owner=None, visible_by_user=None): |
64 | @@ -1283,7 +1283,15 @@ |
65 | clauses = [Or(*prefix_clauses)] |
66 | if owner is not None: |
67 | clauses.append(Snap.owner == owner) |
68 | - clauses.append(self._findByURLVisibilityClause(visible_by_user)) |
69 | + clauses.append(self._findSnapVisibilityClause(visible_by_user)) |
70 | + return IStore(Snap).find(Snap, *clauses) |
71 | + |
72 | + def findByStoreName(self, store_name, owner=None, visible_by_user=None): |
73 | + """See `ISnapSet`.""" |
74 | + clauses = [Snap.store_name == store_name] |
75 | + if owner is not None: |
76 | + clauses.append(Snap.owner == owner) |
77 | + clauses.append(self._findSnapVisibilityClause(visible_by_user)) |
78 | return IStore(Snap).find(Snap, *clauses) |
79 | |
80 | def preloadDataForSnaps(self, snaps, user=None): |
81 | |
82 | === modified file 'lib/lp/snappy/tests/test_snap.py' |
83 | --- lib/lp/snappy/tests/test_snap.py 2019-08-21 10:36:27 +0000 |
84 | +++ lib/lp/snappy/tests/test_snap.py 2019-08-22 10:39:42 +0000 |
85 | @@ -1677,6 +1677,34 @@ |
86 | [snaps[0], snaps[2], snaps[4], snaps[6]], |
87 | getUtility(ISnapSet).findByURLPrefixes(prefixes, owner=owners[0])) |
88 | |
89 | + def test_findByStoreName(self): |
90 | + # ISnapSet.findByStoreName returns visible Snaps with the given |
91 | + # store name. |
92 | + store_names = ["foo", "bar"] |
93 | + owners = [self.factory.makePerson() for i in range(2)] |
94 | + snaps = [] |
95 | + for store_name in store_names: |
96 | + for owner in owners: |
97 | + for private in (False, True): |
98 | + snaps.append(self.factory.makeSnap( |
99 | + registrant=owner, owner=owner, private=private, |
100 | + store_name=store_name)) |
101 | + snaps.append(self.factory.makeSnap()) |
102 | + self.assertContentEqual( |
103 | + [snaps[0], snaps[2]], |
104 | + getUtility(ISnapSet).findByStoreName(store_names[0])) |
105 | + with person_logged_in(owners[0]): |
106 | + self.assertContentEqual( |
107 | + snaps[:2], |
108 | + getUtility(ISnapSet).findByStoreName( |
109 | + store_names[0], owner=owners[0], |
110 | + visible_by_user=owners[0])) |
111 | + self.assertContentEqual( |
112 | + [snaps[2]], |
113 | + getUtility(ISnapSet).findByStoreName( |
114 | + store_names[0], owner=owners[1], |
115 | + visible_by_user=owners[0])) |
116 | + |
117 | def test_getSnapcraftYaml_bzr_snap_snapcraft_yaml(self): |
118 | def getInventory(unique_name, dirname, *args, **kwargs): |
119 | if dirname == "snap": |
120 | @@ -2732,6 +2760,7 @@ |
121 | commercial_admin = ( |
122 | getUtility(ILaunchpadCelebrities).commercial_admin.teamowner) |
123 | logout() |
124 | + |
125 | # Anonymous requests can only see public snaps. |
126 | anon_webservice = LaunchpadWebServiceCaller("test", "") |
127 | response = anon_webservice.named_get( |
128 | @@ -2741,6 +2770,7 @@ |
129 | self.assertContentEqual( |
130 | [ws_snaps[0]], |
131 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
132 | + |
133 | # persons[0] can see their own private snap as well, but not those |
134 | # for other people. |
135 | webservice = webservice_for_person( |
136 | @@ -2759,6 +2789,7 @@ |
137 | self.assertContentEqual( |
138 | [ws_snaps[2]], |
139 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
140 | + |
141 | # Admins can see all snaps. |
142 | commercial_admin_webservice = webservice_for_person( |
143 | commercial_admin, permission=OAuthPermission.READ_PRIVATE) |
144 | @@ -2797,6 +2828,7 @@ |
145 | commercial_admin = ( |
146 | getUtility(ILaunchpadCelebrities).commercial_admin.teamowner) |
147 | logout() |
148 | + |
149 | # Anonymous requests can only see public snaps. |
150 | anon_webservice = LaunchpadWebServiceCaller("test", "") |
151 | response = anon_webservice.named_get( |
152 | @@ -2812,6 +2844,7 @@ |
153 | self.assertContentEqual( |
154 | [ws_snaps[0]], |
155 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
156 | + |
157 | # persons[0] can see both public snaps with this URL, as well as |
158 | # their own private snap. |
159 | webservice = webservice_for_person( |
160 | @@ -2829,6 +2862,7 @@ |
161 | self.assertContentEqual( |
162 | ws_snaps[:2], |
163 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
164 | + |
165 | # Admins can see all snaps with this URL. |
166 | commercial_admin_webservice = webservice_for_person( |
167 | commercial_admin, permission=OAuthPermission.READ_PRIVATE) |
168 | @@ -2873,6 +2907,7 @@ |
169 | getUtility(ILaunchpadCelebrities).commercial_admin.teamowner) |
170 | logout() |
171 | prefix = "https://git.example.org/foo/" |
172 | + |
173 | # Anonymous requests can only see public snaps. |
174 | anon_webservice = LaunchpadWebServiceCaller("test", "") |
175 | response = anon_webservice.named_get( |
176 | @@ -2889,6 +2924,7 @@ |
177 | self.assertContentEqual( |
178 | [ws_snaps[i] for i in (0, 4)], |
179 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
180 | + |
181 | # persons[0] can see all public snaps with this URL prefix, as well |
182 | # as their own matching private snaps. |
183 | webservice = webservice_for_person( |
184 | @@ -2907,6 +2943,7 @@ |
185 | self.assertContentEqual( |
186 | [ws_snaps[i] for i in (0, 1, 4, 5)], |
187 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
188 | + |
189 | # Admins can see all snaps with this URL prefix. |
190 | commercial_admin_webservice = webservice_for_person( |
191 | commercial_admin, permission=OAuthPermission.READ_PRIVATE) |
192 | @@ -2955,6 +2992,7 @@ |
193 | logout() |
194 | prefixes = [ |
195 | "https://git.example.org/foo/", "https://git.example.org/bar/"] |
196 | + |
197 | # Anonymous requests can only see public snaps. |
198 | anon_webservice = LaunchpadWebServiceCaller("test", "") |
199 | response = anon_webservice.named_get( |
200 | @@ -2971,6 +3009,7 @@ |
201 | self.assertContentEqual( |
202 | [ws_snaps[i] for i in (0, 4, 8, 12)], |
203 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
204 | + |
205 | # persons[0] can see all public snaps with any of these URL |
206 | # prefixes, as well as their own matching private snaps. |
207 | webservice = webservice_for_person( |
208 | @@ -2989,6 +3028,7 @@ |
209 | self.assertContentEqual( |
210 | [ws_snaps[i] for i in (0, 1, 4, 5, 8, 9, 12, 13)], |
211 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
212 | + |
213 | # Admins can see all snaps with any of these URL prefixes. |
214 | commercial_admin_webservice = webservice_for_person( |
215 | commercial_admin, permission=OAuthPermission.READ_PRIVATE) |
216 | @@ -3007,6 +3047,81 @@ |
217 | [ws_snaps[i] for i in (0, 1, 4, 5, 8, 9, 12, 13)], |
218 | [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
219 | |
220 | + def test_findByStoreName(self): |
221 | + # lp.snaps.findByStoreName returns visible Snaps with the given |
222 | + # store name. |
223 | + persons = [self.factory.makePerson(), self.factory.makePerson()] |
224 | + store_names = ["foo", "bar"] |
225 | + snaps = [] |
226 | + for store_name in store_names: |
227 | + for person in persons: |
228 | + for private in (False, True): |
229 | + snaps.append(self.factory.makeSnap( |
230 | + registrant=person, owner=person, private=private, |
231 | + store_name=store_name)) |
232 | + with admin_logged_in(): |
233 | + person_urls = [api_url(person) for person in persons] |
234 | + ws_snaps = [ |
235 | + self.webservice.getAbsoluteUrl(api_url(snap)) |
236 | + for snap in snaps] |
237 | + commercial_admin = ( |
238 | + getUtility(ILaunchpadCelebrities).commercial_admin.teamowner) |
239 | + logout() |
240 | + |
241 | + # Anonymous requests can only see public snaps. |
242 | + anon_webservice = LaunchpadWebServiceCaller("test", "") |
243 | + response = anon_webservice.named_get( |
244 | + "/+snaps", "findByStoreName", store_name=store_names[0], |
245 | + api_version="devel") |
246 | + self.assertEqual(200, response.status) |
247 | + self.assertContentEqual( |
248 | + [ws_snaps[0], ws_snaps[2]], |
249 | + [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
250 | + response = anon_webservice.named_get( |
251 | + "/+snaps", "findByStoreName", store_name=store_names[0], |
252 | + owner=person_urls[0], api_version="devel") |
253 | + self.assertEqual(200, response.status) |
254 | + self.assertContentEqual( |
255 | + [ws_snaps[0]], |
256 | + [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
257 | + |
258 | + # persons[0] can see both public snaps with this store name, as well |
259 | + # as their own private snap. |
260 | + webservice = webservice_for_person( |
261 | + persons[0], permission=OAuthPermission.READ_PRIVATE) |
262 | + response = webservice.named_get( |
263 | + "/+snaps", "findByStoreName", store_name=store_names[0], |
264 | + api_version="devel") |
265 | + self.assertEqual(200, response.status) |
266 | + self.assertContentEqual( |
267 | + ws_snaps[:3], |
268 | + [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
269 | + response = webservice.named_get( |
270 | + "/+snaps", "findByStoreName", store_name=store_names[0], |
271 | + owner=person_urls[0], api_version="devel") |
272 | + self.assertEqual(200, response.status) |
273 | + self.assertContentEqual( |
274 | + ws_snaps[:2], |
275 | + [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
276 | + |
277 | + # Admins can see all snaps with this store name. |
278 | + commercial_admin_webservice = webservice_for_person( |
279 | + commercial_admin, permission=OAuthPermission.READ_PRIVATE) |
280 | + response = commercial_admin_webservice.named_get( |
281 | + "/+snaps", "findByStoreName", store_name=store_names[0], |
282 | + api_version="devel") |
283 | + self.assertEqual(200, response.status) |
284 | + self.assertContentEqual( |
285 | + ws_snaps[:4], |
286 | + [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
287 | + response = commercial_admin_webservice.named_get( |
288 | + "/+snaps", "findByStoreName", store_name=store_names[0], |
289 | + owner=person_urls[0], api_version="devel") |
290 | + self.assertEqual(200, response.status) |
291 | + self.assertContentEqual( |
292 | + ws_snaps[:2], |
293 | + [entry["self_link"] for entry in response.jsonBody()["entries"]]) |
294 | + |
295 | def setProcessors(self, user, snap, names): |
296 | ws = webservice_for_person( |
297 | user, permission=OAuthPermission.WRITE_PUBLIC) |