Merge ~pappacena/launchpad:ui-ociproject-search-on-projects into launchpad:master
- Git
- lp:~pappacena/launchpad
- ui-ociproject-search-on-projects
- Merge into master
Proposed by
Thiago F. Pappacena
Status: | Merged |
---|---|
Approved by: | Thiago F. Pappacena |
Approved revision: | 132b2dbb5f1280572173ad0a6aef8ad464a170cc |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~pappacena/launchpad:ui-ociproject-search-on-projects |
Merge into: | launchpad:master |
Prerequisite: | ~pappacena/launchpad:gitrepo-ociproject-refactoring |
Diff against target: |
609 lines (+235/-196) 9 files modified
lib/lp/code/browser/tests/test_product.py (+3/-2) lib/lp/registry/browser/configure.zcml (+9/-2) lib/lp/registry/browser/distribution.py (+0/-49) lib/lp/registry/browser/ociproject.py (+50/-0) lib/lp/registry/browser/product.py (+5/-1) lib/lp/registry/browser/tests/test_distribution.py (+0/-137) lib/lp/registry/browser/tests/test_ociproject.py (+163/-0) lib/lp/registry/interfaces/ociproject.py (+3/-3) lib/lp/registry/model/ociproject.py (+2/-2) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ioana Lasc (community) | Approve | ||
Tom Wardill (community) | Approve | ||
Review via email: mp+384514@code.launchpad.net |
Commit message
OCIProject search on project page.
Description of the change
To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) : | # |
Revision history for this message
Ioana Lasc (ilasc) : | # |
review:
Approve
- 7049999... by Thiago F. Pappacena
-
Fixing typo
Revision history for this message
Thiago F. Pappacena (pappacena) wrote : | # |
Pushed the typo fix. Thanks, twom!
- 132b2db... by Thiago F. Pappacena
-
Merge branch 'master' into ui-ociproject-
search- on-projects
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/code/browser/tests/test_product.py b/lib/lp/code/browser/tests/test_product.py |
2 | index d33a85e..57540e3 100644 |
3 | --- a/lib/lp/code/browser/tests/test_product.py |
4 | +++ b/lib/lp/code/browser/tests/test_product.py |
5 | @@ -1,4 +1,4 @@ |
6 | -# Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
7 | +# Copyright 2009-2020 Canonical Ltd. This software is licensed under the |
8 | # GNU Affero General Public License version 3 (see the file LICENSE). |
9 | |
10 | """Tests for the product view classes and templates.""" |
11 | @@ -432,11 +432,12 @@ class TestProductOverviewOCIProject(TestCaseWithFactory): |
12 | |
13 | layer = DatabaseFunctionalLayer |
14 | |
15 | - def test_displays_create_oci_project_link(self): |
16 | + def test_displays_create_and_list_oci_project_link(self): |
17 | product = self.factory.makeProduct() |
18 | |
19 | browser = self.getUserBrowser( |
20 | canonical_url(product), user=product.owner) |
21 | text = extract_text(find_tag_by_id(browser.contents, 'global-actions')) |
22 | |
23 | + self.assertIn("Search for OCI Project", text) |
24 | self.assertIn("Create an OCI Project", text) |
25 | diff --git a/lib/lp/registry/browser/configure.zcml b/lib/lp/registry/browser/configure.zcml |
26 | index 7e97bf9..b8f00d5 100644 |
27 | --- a/lib/lp/registry/browser/configure.zcml |
28 | +++ b/lib/lp/registry/browser/configure.zcml |
29 | @@ -2179,9 +2179,16 @@ |
30 | <browser:page |
31 | name="+search-oci-project" |
32 | for="lp.registry.interfaces.distribution.IDistribution" |
33 | - class="lp.registry.browser.distribution.DistributionOCIProjectSearchView" |
34 | + class="lp.registry.browser.ociproject.OCIProjectSearchView" |
35 | permission="zope.Public" |
36 | - template="../templates/distribution-search-oci-projects.pt" |
37 | + template="../templates/search-oci-projects.pt" |
38 | + /> |
39 | + <browser:page |
40 | + name="+search-oci-project" |
41 | + for="lp.registry.interfaces.product.IProduct" |
42 | + class="lp.registry.browser.ociproject.OCIProjectSearchView" |
43 | + permission="zope.Public" |
44 | + template="../templates/search-oci-projects.pt" |
45 | /> |
46 | <browser:page |
47 | name="+search" |
48 | diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py |
49 | index 29eab7a..351aa1a 100644 |
50 | --- a/lib/lp/registry/browser/distribution.py |
51 | +++ b/lib/lp/registry/browser/distribution.py |
52 | @@ -42,7 +42,6 @@ from collections import defaultdict |
53 | import datetime |
54 | |
55 | from lazr.restful.utils import smartquote |
56 | -import six |
57 | from zope.component import getUtility |
58 | from zope.event import notify |
59 | from zope.formlib import form |
60 | @@ -106,7 +105,6 @@ from lp.registry.interfaces.distributionmirror import ( |
61 | MirrorContent, |
62 | MirrorSpeed, |
63 | ) |
64 | -from lp.registry.interfaces.ociproject import IOCIProjectSet |
65 | from lp.registry.interfaces.series import SeriesStatus |
66 | from lp.services.database.decoratedresultset import DecoratedResultSet |
67 | from lp.services.feeds.browser import FeedsMixin |
68 | @@ -1387,50 +1385,3 @@ class DistributionPublisherConfigView(LaunchpadFormView): |
69 | self.request.response.addInfoNotification( |
70 | 'Your changes have been applied.') |
71 | self.next_url = canonical_url(self.context) |
72 | - |
73 | - |
74 | -class DistributionOCIProjectSearchView(LaunchpadView): |
75 | - """Page to search for OCI projects of a given distribution.""" |
76 | - page_title = '' |
77 | - |
78 | - @property |
79 | - def label(self): |
80 | - return "Search OCI projects in %s" % self.context.title |
81 | - |
82 | - @property |
83 | - def text(self): |
84 | - text = self.request.get("text", None) |
85 | - if isinstance(text, list): |
86 | - # The user may have URL hacked a query string with more than one |
87 | - # "text" parameter. We'll take the last one. |
88 | - text = text[-1] |
89 | - return text |
90 | - |
91 | - @property |
92 | - def search_requested(self): |
93 | - return self.text is not None |
94 | - |
95 | - @property |
96 | - def title(self): |
97 | - return self.context.name |
98 | - |
99 | - @cachedproperty |
100 | - def count(self): |
101 | - """Return the number of matched search results.""" |
102 | - return self.batchnav.batch.total() |
103 | - |
104 | - @cachedproperty |
105 | - def batchnav(self): |
106 | - """Return the batch navigator for the search results.""" |
107 | - return BatchNavigator(self.search_results, self.request) |
108 | - |
109 | - @cachedproperty |
110 | - def preloaded_batch(self): |
111 | - projects = self.batchnav.batch |
112 | - getUtility(IOCIProjectSet).preloadDataForOCIProjects(projects) |
113 | - return projects |
114 | - |
115 | - @property |
116 | - def search_results(self): |
117 | - return getUtility(IOCIProjectSet).findByDistributionAndName( |
118 | - self.context, self.text or six.ensure_text('')) |
119 | diff --git a/lib/lp/registry/browser/ociproject.py b/lib/lp/registry/browser/ociproject.py |
120 | index 99c5b43..0d23a15 100644 |
121 | --- a/lib/lp/registry/browser/ociproject.py |
122 | +++ b/lib/lp/registry/browser/ociproject.py |
123 | @@ -41,16 +41,19 @@ from lp.registry.interfaces.ociprojectname import ( |
124 | ) |
125 | from lp.registry.interfaces.product import IProduct |
126 | from lp.services.features import getFeatureFlag |
127 | +from lp.services.propertycache import cachedproperty |
128 | from lp.services.webapp import ( |
129 | canonical_url, |
130 | ContextMenu, |
131 | enabled_with_permission, |
132 | + LaunchpadView, |
133 | Link, |
134 | Navigation, |
135 | NavigationMenu, |
136 | StandardLaunchpadFacets, |
137 | stepthrough, |
138 | ) |
139 | +from lp.services.webapp.batching import BatchNavigator |
140 | from lp.services.webapp.breadcrumb import Breadcrumb |
141 | from lp.services.webapp.interfaces import IMultiFacetedBreadcrumb |
142 | |
143 | @@ -234,3 +237,50 @@ class OCIProjectEditView(LaunchpadEditFormView): |
144 | return canonical_url(self.context) |
145 | |
146 | cancel_url = next_url |
147 | + |
148 | + |
149 | +class OCIProjectSearchView(LaunchpadView): |
150 | + """Page to search for OCI projects of a given pillar.""" |
151 | + page_title = '' |
152 | + |
153 | + @property |
154 | + def label(self): |
155 | + return "Search OCI projects in %s" % self.context.title |
156 | + |
157 | + @property |
158 | + def text(self): |
159 | + text = self.request.get("text", None) |
160 | + if isinstance(text, list): |
161 | + # The user may have URL hacked a query string with more than one |
162 | + # "text" parameter. We'll take the last one. |
163 | + text = text[-1] |
164 | + return text |
165 | + |
166 | + @property |
167 | + def search_requested(self): |
168 | + return self.text is not None |
169 | + |
170 | + @property |
171 | + def title(self): |
172 | + return self.context.name |
173 | + |
174 | + @cachedproperty |
175 | + def count(self): |
176 | + """Return the number of matched search results.""" |
177 | + return self.batchnav.batch.total() |
178 | + |
179 | + @cachedproperty |
180 | + def batchnav(self): |
181 | + """Return the batch navigator for the search results.""" |
182 | + return BatchNavigator(self.search_results, self.request) |
183 | + |
184 | + @cachedproperty |
185 | + def preloaded_batch(self): |
186 | + projects = self.batchnav.batch |
187 | + getUtility(IOCIProjectSet).preloadDataForOCIProjects(projects) |
188 | + return projects |
189 | + |
190 | + @property |
191 | + def search_results(self): |
192 | + return getUtility(IOCIProjectSet).findByPillarAndName( |
193 | + self.context, self.text or '') |
194 | diff --git a/lib/lp/registry/browser/product.py b/lib/lp/registry/browser/product.py |
195 | index f974d39..aad1fc8 100644 |
196 | --- a/lib/lp/registry/browser/product.py |
197 | +++ b/lib/lp/registry/browser/product.py |
198 | @@ -509,6 +509,10 @@ class ProductEditLinksMixin(StructuralSubscriptionMenuMixin): |
199 | def sharing(self): |
200 | return Link('+sharing', 'Sharing', icon='edit') |
201 | |
202 | + def search_oci_project(self): |
203 | + text = 'Search for OCI Project' |
204 | + return Link('+search-oci-project', text, icon='info') |
205 | + |
206 | @enabled_with_permission('launchpad.Driver') |
207 | def new_oci_project(self): |
208 | text = 'Create an OCI Project' |
209 | @@ -533,7 +537,7 @@ class ProductActionNavigationMenu(NavigationMenu, ProductEditLinksMixin): |
210 | @cachedproperty |
211 | def links(self): |
212 | links = ['edit', 'review_license', 'administer', 'sharing', |
213 | - 'new_oci_project'] |
214 | + 'search_oci_project', 'new_oci_project'] |
215 | add_subscribe_link(links) |
216 | return links |
217 | |
218 | diff --git a/lib/lp/registry/browser/tests/test_distribution.py b/lib/lp/registry/browser/tests/test_distribution.py |
219 | index f7f37fd..d3cd559 100644 |
220 | --- a/lib/lp/registry/browser/tests/test_distribution.py |
221 | +++ b/lib/lp/registry/browser/tests/test_distribution.py |
222 | @@ -26,21 +26,14 @@ from lp.services.webapp import canonical_url |
223 | from lp.services.webapp.publisher import RedirectionView |
224 | from lp.testing import ( |
225 | admin_logged_in, |
226 | - BrowserTestCase, |
227 | login_celebrity, |
228 | login_person, |
229 | - record_two_runs, |
230 | TestCaseWithFactory, |
231 | ) |
232 | from lp.testing.layers import ( |
233 | DatabaseFunctionalLayer, |
234 | ZopelessDatabaseLayer, |
235 | ) |
236 | -from lp.testing.pages import ( |
237 | - extract_text, |
238 | - find_tag_by_id, |
239 | - find_tags_by_class, |
240 | - ) |
241 | from lp.testing.publication import test_traverse |
242 | from lp.testing.views import create_initialized_view |
243 | |
244 | @@ -211,133 +204,3 @@ class TestDistributionView(TestCaseWithFactory): |
245 | self.assertContentEqual( |
246 | team_membership_policy_data, |
247 | cache.objects['team_membership_policy_data']) |
248 | - |
249 | - |
250 | -class TestDistributionOCIProjectSearchView(BrowserTestCase): |
251 | - |
252 | - layer = DatabaseFunctionalLayer |
253 | - |
254 | - def assertPaginationIsPresent( |
255 | - self, browser, results_in_page, total_result): |
256 | - """Checks that pagination is shown at the browser.""" |
257 | - nav_index = find_tags_by_class( |
258 | - browser.contents, "batch-navigation-index")[0] |
259 | - nav_index_text = extract_text(nav_index).replace('\n', ' ') |
260 | - self.assertIn( |
261 | - "1 → %s of %s results" % (results_in_page, total_result), |
262 | - nav_index_text) |
263 | - |
264 | - nav_links = find_tags_by_class( |
265 | - browser.contents, "batch-navigation-links")[0] |
266 | - nav_links_text = extract_text(nav_links).replace('\n', ' ') |
267 | - self.assertIn("First • Previous • Next • Last", nav_links_text) |
268 | - |
269 | - def assertOCIProjectsArePresent(self, browser, oci_projects): |
270 | - table = find_tag_by_id(browser.contents, "projects_list") |
271 | - with admin_logged_in(): |
272 | - for oci_project in oci_projects: |
273 | - url = canonical_url(oci_project, force_local_path=True) |
274 | - self.assertIn(url, str(table)) |
275 | - self.assertIn(oci_project.name, str(table)) |
276 | - |
277 | - def assertOCIProjectsAreNotPresent(self, browser, oci_projects): |
278 | - table = find_tag_by_id(browser.contents, "projects_list") |
279 | - with admin_logged_in(): |
280 | - for oci_project in oci_projects: |
281 | - url = canonical_url(oci_project, force_local_path=True) |
282 | - self.assertNotIn(url, str(table)) |
283 | - self.assertNotIn(oci_project.name, str(table)) |
284 | - |
285 | - def test_search_no_oci_projects(self): |
286 | - person = self.factory.makePerson() |
287 | - distribution = self.factory.makeDistribution() |
288 | - browser = self.getViewBrowser( |
289 | - distribution, user=person, view_name='+search-oci-project') |
290 | - |
291 | - main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0] |
292 | - self.assertIn( |
293 | - "There are no OCI projects registered for %s" % distribution.name, |
294 | - extract_text(main_portlet).replace("\n", " ")) |
295 | - |
296 | - def test_oci_projects_no_search_keyword(self): |
297 | - person = self.factory.makePerson() |
298 | - distro = self.factory.makeDistribution(owner=person) |
299 | - |
300 | - # Creates 3 OCI Projects |
301 | - oci_projects = [ |
302 | - self.factory.makeOCIProject( |
303 | - ociprojectname="test-project-%s" % i, |
304 | - registrant=person, pillar=distro) for i in range(3)] |
305 | - |
306 | - browser = self.getViewBrowser( |
307 | - distro, user=person, view_name='+search-oci-project') |
308 | - |
309 | - # Check top message. |
310 | - main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0] |
311 | - self.assertIn( |
312 | - "There are 3 OCI projects registered for %s" % distro.name, |
313 | - extract_text(main_portlet).replace("\n", " ")) |
314 | - |
315 | - self.assertOCIProjectsArePresent(browser, oci_projects) |
316 | - self.assertPaginationIsPresent(browser, 3, 3) |
317 | - |
318 | - def test_oci_projects_with_search_keyword(self): |
319 | - person = self.factory.makePerson() |
320 | - distro = self.factory.makeDistribution(owner=person) |
321 | - |
322 | - # And 2 OCI projects that will match the name |
323 | - oci_projects = [ |
324 | - self.factory.makeOCIProject( |
325 | - ociprojectname="find-me-%s" % i, |
326 | - registrant=person, pillar=distro) for i in range(2)] |
327 | - |
328 | - # Creates 2 OCI Projects that will not match search |
329 | - other_oci_projects = [ |
330 | - self.factory.makeOCIProject( |
331 | - ociprojectname="something-%s" % i, |
332 | - registrant=person, pillar=distro) for i in range(2)] |
333 | - |
334 | - browser = self.getViewBrowser( |
335 | - distro, user=person, view_name='+search-oci-project') |
336 | - browser.getControl(name="text").value = "find-me" |
337 | - browser.getControl("Search").click() |
338 | - |
339 | - # Check top message. |
340 | - main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0] |
341 | - self.assertIn( |
342 | - 'There are 2 OCI projects registered for %s matching "%s"' % |
343 | - (distro.name, "find-me"), |
344 | - extract_text(main_portlet).replace("\n", " ")) |
345 | - |
346 | - self.assertOCIProjectsArePresent(browser, oci_projects) |
347 | - self.assertOCIProjectsAreNotPresent(browser, other_oci_projects) |
348 | - self.assertPaginationIsPresent(browser, 2, 2) |
349 | - |
350 | - def test_query_count_is_constant(self): |
351 | - batch_size = 3 |
352 | - self.pushConfig("launchpad", default_batch_size=batch_size) |
353 | - |
354 | - person = self.factory.makePerson() |
355 | - distro = self.factory.makeDistribution(owner=person) |
356 | - name_pattern = "find-me-" |
357 | - |
358 | - def createOCIProject(): |
359 | - self.factory.makeOCIProject( |
360 | - ociprojectname=self.factory.getUniqueString(name_pattern), |
361 | - pillar=distro) |
362 | - |
363 | - viewer = self.factory.makePerson() |
364 | - |
365 | - def getView(): |
366 | - browser = self.getViewBrowser( |
367 | - distro, user=viewer, view_name='+search-oci-project') |
368 | - browser.getControl(name="text").value = name_pattern |
369 | - browser.getControl("Search").click() |
370 | - return browser |
371 | - |
372 | - def do_login(): |
373 | - login_person(person) |
374 | - |
375 | - recorder1, recorder2 = record_two_runs( |
376 | - getView, createOCIProject, 1, 10, login_method=do_login) |
377 | - self.assertEqual(recorder1.count, recorder2.count) |
378 | diff --git a/lib/lp/registry/browser/tests/test_ociproject.py b/lib/lp/registry/browser/tests/test_ociproject.py |
379 | index 648f4d4..9fb5822 100644 |
380 | --- a/lib/lp/registry/browser/tests/test_ociproject.py |
381 | +++ b/lib/lp/registry/browser/tests/test_ociproject.py |
382 | @@ -12,6 +12,7 @@ __all__ = [] |
383 | from datetime import datetime |
384 | |
385 | import pytz |
386 | +from zope.security.proxy import removeSecurityProxy |
387 | |
388 | from lp.oci.interfaces.ocirecipe import OCI_RECIPE_ALLOW_CREATE |
389 | from lp.registry.interfaces.ociproject import ( |
390 | @@ -25,7 +26,9 @@ from lp.services.webapp.escaping import structured |
391 | from lp.testing import ( |
392 | admin_logged_in, |
393 | BrowserTestCase, |
394 | + login_person, |
395 | person_logged_in, |
396 | + record_two_runs, |
397 | test_tales, |
398 | TestCaseWithFactory, |
399 | ) |
400 | @@ -34,6 +37,7 @@ from lp.testing.matchers import MatchesTagText |
401 | from lp.testing.pages import ( |
402 | extract_text, |
403 | find_main_content, |
404 | + find_tag_by_id, |
405 | find_tags_by_class, |
406 | ) |
407 | from lp.testing.publication import test_traverse |
408 | @@ -376,3 +380,162 @@ class TestOCIProjectAddView(BrowserTestCase): |
409 | new_distribution, |
410 | user=another_person, |
411 | view_name='+new-oci-project') |
412 | + |
413 | + |
414 | +class TestOCIProjectSearchView(BrowserTestCase): |
415 | + |
416 | + layer = DatabaseFunctionalLayer |
417 | + |
418 | + def assertPaginationIsPresent( |
419 | + self, browser, results_in_page, total_result): |
420 | + """Checks that pagination is shown at the browser.""" |
421 | + nav_index = find_tags_by_class( |
422 | + browser.contents, "batch-navigation-index")[0] |
423 | + nav_index_text = extract_text(nav_index).replace('\n', ' ') |
424 | + self.assertIn( |
425 | + "1 → %s of %s results" % (results_in_page, total_result), |
426 | + nav_index_text) |
427 | + |
428 | + nav_links = find_tags_by_class( |
429 | + browser.contents, "batch-navigation-links")[0] |
430 | + nav_links_text = extract_text(nav_links).replace('\n', ' ') |
431 | + self.assertIn("First • Previous • Next • Last", nav_links_text) |
432 | + |
433 | + def assertOCIProjectsArePresent(self, browser, oci_projects): |
434 | + table = find_tag_by_id(browser.contents, "projects_list") |
435 | + with admin_logged_in(): |
436 | + for oci_project in oci_projects: |
437 | + url = canonical_url(oci_project, force_local_path=True) |
438 | + self.assertIn(url, str(table)) |
439 | + self.assertIn(oci_project.name, str(table)) |
440 | + |
441 | + def assertOCIProjectsAreNotPresent(self, browser, oci_projects): |
442 | + table = find_tag_by_id(browser.contents, "projects_list") |
443 | + with admin_logged_in(): |
444 | + for oci_project in oci_projects: |
445 | + url = canonical_url(oci_project, force_local_path=True) |
446 | + self.assertNotIn(url, str(table)) |
447 | + self.assertNotIn(oci_project.name, str(table)) |
448 | + |
449 | + def check_search_no_oci_projects(self, pillar): |
450 | + pillar = removeSecurityProxy(pillar) |
451 | + person = self.factory.makePerson() |
452 | + |
453 | + browser = self.getViewBrowser( |
454 | + pillar, user=person, view_name='+search-oci-project') |
455 | + |
456 | + main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0] |
457 | + self.assertIn( |
458 | + "There are no OCI projects registered for %s" % pillar.name, |
459 | + extract_text(main_portlet).replace("\n", " ")) |
460 | + |
461 | + def test_search_no_oci_projects_distribution_pillar(self): |
462 | + return self.check_search_no_oci_projects( |
463 | + self.factory.makeDistribution()) |
464 | + |
465 | + def test_search_no_oci_projects_project_pillar(self): |
466 | + return self.check_search_no_oci_projects(self.factory.makeProduct()) |
467 | + |
468 | + def check_oci_projects_no_search_keyword(self, pillar): |
469 | + pillar = removeSecurityProxy(pillar) |
470 | + person = pillar.owner |
471 | + |
472 | + # Creates 3 OCI Projects |
473 | + oci_projects = [ |
474 | + self.factory.makeOCIProject( |
475 | + ociprojectname="test-project-%s" % i, |
476 | + registrant=person, pillar=pillar) for i in range(3)] |
477 | + |
478 | + browser = self.getViewBrowser( |
479 | + pillar, user=person, view_name='+search-oci-project') |
480 | + |
481 | + # Check top message. |
482 | + main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0] |
483 | + self.assertIn( |
484 | + "There are 3 OCI projects registered for %s" % pillar.name, |
485 | + extract_text(main_portlet).replace("\n", " ")) |
486 | + |
487 | + self.assertOCIProjectsArePresent(browser, oci_projects) |
488 | + self.assertPaginationIsPresent(browser, 3, 3) |
489 | + |
490 | + def test_oci_projects_no_search_keyword_for_distribution(self): |
491 | + return self.check_oci_projects_no_search_keyword( |
492 | + self.factory.makeDistribution()) |
493 | + |
494 | + def test_oci_projects_no_search_keyword_for_project(self): |
495 | + return self.check_oci_projects_no_search_keyword( |
496 | + self.factory.makeProduct()) |
497 | + |
498 | + def check_oci_projects_with_search_keyword(self, pillar): |
499 | + pillar = removeSecurityProxy(pillar) |
500 | + person = pillar.owner |
501 | + |
502 | + # And 2 OCI projects that will match the name |
503 | + oci_projects = [ |
504 | + self.factory.makeOCIProject( |
505 | + ociprojectname="find-me-%s" % i, |
506 | + registrant=person, pillar=pillar) for i in range(2)] |
507 | + |
508 | + # Creates 2 OCI Projects that will not match search |
509 | + other_oci_projects = [ |
510 | + self.factory.makeOCIProject( |
511 | + ociprojectname="something-%s" % i, |
512 | + registrant=person, pillar=pillar) for i in range(2)] |
513 | + |
514 | + browser = self.getViewBrowser( |
515 | + pillar, user=person, view_name='+search-oci-project') |
516 | + browser.getControl(name="text").value = "find-me" |
517 | + browser.getControl("Search").click() |
518 | + |
519 | + # Check top message. |
520 | + main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0] |
521 | + self.assertIn( |
522 | + 'There are 2 OCI projects registered for %s matching "%s"' % |
523 | + (pillar.name, "find-me"), |
524 | + extract_text(main_portlet).replace("\n", " ")) |
525 | + |
526 | + self.assertOCIProjectsArePresent(browser, oci_projects) |
527 | + self.assertOCIProjectsAreNotPresent(browser, other_oci_projects) |
528 | + self.assertPaginationIsPresent(browser, 2, 2) |
529 | + |
530 | + def test_oci_projects_with_search_keyword_for_distribution(self): |
531 | + self.check_oci_projects_with_search_keyword( |
532 | + self.factory.makeDistribution()) |
533 | + |
534 | + def test_oci_projects_with_search_keyword_for_project(self): |
535 | + self.check_oci_projects_with_search_keyword(self.factory.makeProduct()) |
536 | + |
537 | + def check_query_count_is_constant(self, pillar): |
538 | + batch_size = 3 |
539 | + self.pushConfig("launchpad", default_batch_size=batch_size) |
540 | + |
541 | + person = self.factory.makePerson() |
542 | + distro = self.factory.makeDistribution(owner=person) |
543 | + name_pattern = "find-me-" |
544 | + |
545 | + def createOCIProject(): |
546 | + self.factory.makeOCIProject( |
547 | + ociprojectname=self.factory.getUniqueString(name_pattern), |
548 | + pillar=distro) |
549 | + |
550 | + viewer = self.factory.makePerson() |
551 | + |
552 | + def getView(): |
553 | + browser = self.getViewBrowser( |
554 | + distro, user=viewer, view_name='+search-oci-project') |
555 | + browser.getControl(name="text").value = name_pattern |
556 | + browser.getControl("Search").click() |
557 | + return browser |
558 | + |
559 | + def do_login(): |
560 | + login_person(person) |
561 | + |
562 | + recorder1, recorder2 = record_two_runs( |
563 | + getView, createOCIProject, 1, 10, login_method=do_login) |
564 | + self.assertEqual(recorder1.count, recorder2.count) |
565 | + |
566 | + def test_query_count_is_constant_for_distribution(self): |
567 | + self.check_query_count_is_constant(self.factory.makeDistribution()) |
568 | + |
569 | + def test_query_count_is_constant_for_project(self): |
570 | + self.check_query_count_is_constant(self.factory.makeProduct()) |
571 | diff --git a/lib/lp/registry/interfaces/ociproject.py b/lib/lp/registry/interfaces/ociproject.py |
572 | index ad3e121..1344093 100644 |
573 | --- a/lib/lp/registry/interfaces/ociproject.py |
574 | +++ b/lib/lp/registry/interfaces/ociproject.py |
575 | @@ -202,9 +202,9 @@ class IOCIProjectSet(Interface): |
576 | :return: The OCIProject found. |
577 | """ |
578 | |
579 | - def findByDistributionAndName(distribution, name_substring): |
580 | - """Find OCIProjects for a given distribution that contains the |
581 | - provided name.""" |
582 | + def findByPillarAndName(pillar, name_substring): |
583 | + """Find OCIProjects for a given pillar that contain the provided |
584 | + name.""" |
585 | |
586 | def preloadDataForOCIProjects(oci_projects): |
587 | """Preload data for the given list of OCIProject objects.""" |
588 | diff --git a/lib/lp/registry/model/ociproject.py b/lib/lp/registry/model/ociproject.py |
589 | index b991c19..28b3dc0 100644 |
590 | --- a/lib/lp/registry/model/ociproject.py |
591 | +++ b/lib/lp/registry/model/ociproject.py |
592 | @@ -269,11 +269,11 @@ class OCIProjectSet: |
593 | OCIProjectName.name == name).one() |
594 | return target |
595 | |
596 | - def findByDistributionAndName(self, distribution, name_substring): |
597 | + def findByPillarAndName(self, pillar, name_substring): |
598 | """See `IOCIProjectSet`.""" |
599 | return IStore(OCIProject).find( |
600 | OCIProject, |
601 | - OCIProject.distribution == distribution, |
602 | + self._get_pillar_attribute(pillar) == pillar, |
603 | OCIProject.ociprojectname == OCIProjectName.id, |
604 | OCIProjectName.name.contains_string(name_substring)) |
605 | |
606 | diff --git a/lib/lp/registry/templates/distribution-search-oci-projects.pt b/lib/lp/registry/templates/search-oci-projects.pt |
607 | similarity index 100% |
608 | rename from lib/lp/registry/templates/distribution-search-oci-projects.pt |
609 | rename to lib/lp/registry/templates/search-oci-projects.pt |
One minor typo fix that I think was mine to start with...