From 69fb128c14760c8cb83ed1f3ec27d450e0c2992e Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Fri, 4 Mar 2016 14:17:02 -0500 Subject: [PATCH 1/3] Add search result ordering --- tests/unit/cli/search/test_reindex.py | 1 + tests/unit/packaging/test_search.py | 3 ++ tests/unit/test_views.py | 70 ++++++++++++++++++++++++- warehouse/packaging/search.py | 4 +- warehouse/static/js/main.js | 5 ++ warehouse/templates/search/results.html | 21 +++++--- warehouse/views.py | 9 +++- 7 files changed, 102 insertions(+), 11 deletions(-) diff --git a/tests/unit/cli/search/test_reindex.py b/tests/unit/cli/search/test_reindex.py index e01dd9062928..0865436a50a6 100644 --- a/tests/unit/cli/search/test_reindex.py +++ b/tests/unit/cli/search/test_reindex.py @@ -38,6 +38,7 @@ def test_project_docs(db_session): "_id": p.normalized_name, "_type": "project", "_source": { + "created": p.created, "name": p.name, "normalized_name": p.normalized_name, "version": [r.version for r in prs], diff --git a/tests/unit/packaging/test_search.py b/tests/unit/packaging/test_search.py index e85fc2bde09a..11d2283f8fb5 100644 --- a/tests/unit/packaging/test_search.py +++ b/tests/unit/packaging/test_search.py @@ -10,6 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import datetime import pretend from warehouse.packaging import search @@ -37,6 +38,7 @@ def test_build_search(): download_url="https://example.com/foobar/downloads/", keywords="the, keywords, lol", platform="any platform", + created=datetime.datetime(1956, 1, 31), uploader=pretend.stub( username="some-username", name="the-users-name", @@ -57,5 +59,6 @@ def test_build_search(): assert obj["download_url"] == "https://example.com/foobar/downloads/" assert obj["keywords"] == "the, keywords, lol" assert obj["platform"] == "any platform" + assert obj["created"] == datetime.datetime(1956, 1, 31) assert obj["uploader_name"] == "the-users-name" assert obj["uploader_username"] == "some-username" diff --git a/tests/unit/test_views.py b/tests/unit/test_views.py index 63c05f32e5d2..f01d020c7a7e 100644 --- a/tests/unit/test_views.py +++ b/tests/unit/test_views.py @@ -119,7 +119,11 @@ def test_with_a_query(self, monkeypatch, page): url_maker_factory = pretend.call_recorder(lambda request: url_maker) monkeypatch.setattr(views, "paginate_url_factory", url_maker_factory) - assert search(request) == {"page": page_obj, "term": params.get("q")} + assert search(request) == { + "page": page_obj, + "term": params.get("q"), + "order": params.get("o"), + } assert page_cls.calls == [ pretend.call(suggest, url_maker=url_maker, page=page or 1), ] @@ -143,6 +147,64 @@ def test_with_a_query(self, monkeypatch, page): ), ] + @pytest.mark.parametrize("page", [None, 1, 5]) + def test_with_an_ordering(self, monkeypatch, page): + params = {"q": "foo bar", "o": "-created"} + if page is not None: + params["page"] = page + sort = pretend.stub() + suggest = pretend.stub( + sort=pretend.call_recorder(lambda *a, **kw: sort), + ) + query = pretend.stub( + suggest=pretend.call_recorder(lambda *a, **kw: suggest), + ) + request = pretend.stub( + es=pretend.stub( + query=pretend.call_recorder(lambda *a, **kw: query), + ), + params=params, + ) + + page_obj = pretend.stub() + page_cls = pretend.call_recorder(lambda *a, **kw: page_obj) + monkeypatch.setattr(views, "ElasticsearchPage", page_cls) + + url_maker = pretend.stub() + url_maker_factory = pretend.call_recorder(lambda request: url_maker) + monkeypatch.setattr(views, "paginate_url_factory", url_maker_factory) + + assert search(request) == { + "page": page_obj, + "term": params.get("q"), + "order": params.get("o"), + } + assert page_cls.calls == [ + pretend.call(sort, url_maker=url_maker, page=page or 1), + ] + assert url_maker_factory.calls == [pretend.call(request)] + assert request.es.query.calls == [ + pretend.call( + "multi_match", + query="foo bar", + fields=[ + "name", "version", "author", "author_email", "maintainer", + "maintainer_email", "home_page", "license", "summary", + "description", "keywords", "platform", "download_url", + ], + ), + ] + assert query.suggest.calls == [ + pretend.call( + name="name_suggestion", + term={"field": "name"}, + text="foo bar", + ), + ] + assert suggest.sort.calls == [ + pretend.call("-created") + ] + @pytest.mark.parametrize("page", [None, 1, 5]) def test_without_a_query(self, monkeypatch, page): params = {} @@ -162,7 +224,11 @@ def test_without_a_query(self, monkeypatch, page): url_maker_factory = pretend.call_recorder(lambda request: url_maker) monkeypatch.setattr(views, "paginate_url_factory", url_maker_factory) - assert search(request) == {"page": page_obj, "term": params.get("q")} + assert search(request) == { + "page": page_obj, + "term": params.get("q"), + "order": params.get("o"), + } assert page_cls.calls == [ pretend.call(query, url_maker=url_maker, page=page or 1), ] diff --git a/warehouse/packaging/search.py b/warehouse/packaging/search.py index 6dd702a08d0b..3af6fd301158 100644 --- a/warehouse/packaging/search.py +++ b/warehouse/packaging/search.py @@ -10,7 +10,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from elasticsearch_dsl import DocType, String, analyzer, MetaField +from elasticsearch_dsl import DocType, String, analyzer, MetaField, Date from warehouse.search import doc_type @@ -39,6 +39,7 @@ class Project(DocType): download_url = String(index="not_analyzed") keywords = String(analyzer="snowball") platform = String(index="not_analyzed") + created = Date() uploader_name = String() uploader_username = String() @@ -63,6 +64,7 @@ def from_db(cls, release): obj["download_url"] = release.download_url obj["keywords"] = release.keywords obj["platform"] = release.platform + obj["created"] = release.created obj["uploader_name"] = release.uploader.name obj["uploader_username"] = release.uploader.username diff --git a/warehouse/static/js/main.js b/warehouse/static/js/main.js index 62718982300f..77dff171bb6e 100644 --- a/warehouse/static/js/main.js +++ b/warehouse/static/js/main.js @@ -70,6 +70,11 @@ $(document).ready(function() { positionWarning(); }); + // Search ordering + $('#order').on("change", function(event) { + this.form.submit(); + }); + $.timeago.settings.cutoff = 7 * 24 * 60 * 60 * 1000; // One week // document.l10n.ready.then(function() { diff --git a/warehouse/templates/search/results.html b/warehouse/templates/search/results.html index 563d6b47d35d..f71260a5ec7e 100644 --- a/warehouse/templates/search/results.html +++ b/warehouse/templates/search/results.html @@ -47,6 +47,10 @@

{{ text }} +{%- endmacro %} + {% block content %}
diff --git a/warehouse/views.py b/warehouse/views.py index 51efa5eaee07..7de2fed3602a 100644 --- a/warehouse/views.py +++ b/warehouse/views.py @@ -171,13 +171,20 @@ def search(request): else: query = request.es.query() + if request.params.get("o"): + query = query.sort(request.params["o"]) + page = ElasticsearchPage( query, page=int(request.params.get("page", 1)), url_maker=paginate_url_factory(request), ) - return {"page": page, "term": request.params.get("q")} + return { + "page": page, + "term": request.params.get("q"), + "order": request.params.get("o"), + } @view_config( From 9cf0892ce8ab0249abdf98b877d934fb379d1244 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Fri, 4 Mar 2016 14:17:45 -0500 Subject: [PATCH 2/3] Prefill search term --- warehouse/templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/warehouse/templates/base.html b/warehouse/templates/base.html index 6da2fdd6dc11..3eb696ede491 100644 --- a/warehouse/templates/base.html +++ b/warehouse/templates/base.html @@ -57,7 +57,7 @@
- +
From e5802a3153b3e3af6647b405e280cb8a06d79d3e Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Fri, 4 Mar 2016 14:18:05 -0500 Subject: [PATCH 3/3] Add created date to individual search result --- warehouse/templates/search/results.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/warehouse/templates/search/results.html b/warehouse/templates/search/results.html index f71260a5ec7e..9b3fbaddeea9 100644 --- a/warehouse/templates/search/results.html +++ b/warehouse/templates/search/results.html @@ -17,6 +17,7 @@ {% macro project_snippet(item) -%} {% set version = item.version[0] %} +{% set created = item.created %} {% set uploader_username = item.uploader_username %} {% set uploader_name = item.uploader_name|default(uploader_username, true) %} @@ -24,7 +25,7 @@

{{ item.name }}

- {{ version }} uploaded by {{ uploader_name }} + {{ version }} uploaded by {{ uploader_name }} on {{ created|format_date() }}

{{ item.summary }}