Show More
@@ -0,0 +1,93 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2010-2019 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import pytest | |||
|
22 | from rhodecode.tests import HG_REPO | |||
|
23 | from rhodecode.api.tests.utils import ( | |||
|
24 | build_data, api_call, assert_error, assert_ok) | |||
|
25 | ||||
|
26 | ||||
|
27 | @pytest.mark.usefixtures("testuser_api", "app") | |||
|
28 | class TestApiSearch(object): | |||
|
29 | ||||
|
30 | @pytest.mark.parametrize("query, expected_hits, expected_paths", [ | |||
|
31 | ('todo', 23, [ | |||
|
32 | 'vcs/backends/hg/inmemory.py', | |||
|
33 | 'vcs/tests/test_git.py']), | |||
|
34 | ('extension:rst installation', 6, [ | |||
|
35 | 'docs/index.rst', | |||
|
36 | 'docs/installation.rst']), | |||
|
37 | ('def repo', 87, [ | |||
|
38 | 'vcs/tests/test_git.py', | |||
|
39 | 'vcs/tests/test_changesets.py']), | |||
|
40 | ('repository:%s def test' % HG_REPO, 18, [ | |||
|
41 | 'vcs/tests/test_git.py', | |||
|
42 | 'vcs/tests/test_changesets.py']), | |||
|
43 | ('"def main"', 9, [ | |||
|
44 | 'vcs/__init__.py', | |||
|
45 | 'vcs/tests/__init__.py', | |||
|
46 | 'vcs/utils/progressbar.py']), | |||
|
47 | ('owner:test_admin', 358, [ | |||
|
48 | 'vcs/tests/base.py', | |||
|
49 | 'MANIFEST.in', | |||
|
50 | 'vcs/utils/termcolors.py', | |||
|
51 | 'docs/theme/ADC/static/documentation.png']), | |||
|
52 | ('owner:test_admin def main', 72, [ | |||
|
53 | 'vcs/__init__.py', | |||
|
54 | 'vcs/tests/test_utils_filesize.py', | |||
|
55 | 'vcs/tests/test_cli.py']), | |||
|
56 | ('owner:michał test', 0, []), | |||
|
57 | ]) | |||
|
58 | def test_search_content_results(self, query, expected_hits, expected_paths): | |||
|
59 | id_, params = build_data( | |||
|
60 | self.apikey_regular, 'search', | |||
|
61 | search_query=query, | |||
|
62 | search_type='content') | |||
|
63 | ||||
|
64 | response = api_call(self.app, params) | |||
|
65 | json_response = response.json | |||
|
66 | ||||
|
67 | assert json_response['result']['item_count'] == expected_hits | |||
|
68 | paths = [x['f_path'] for x in json_response['result']['results']] | |||
|
69 | ||||
|
70 | for expected_path in expected_paths: | |||
|
71 | assert expected_path in paths | |||
|
72 | ||||
|
73 | @pytest.mark.parametrize("query, expected_hits, expected_paths", [ | |||
|
74 | ('readme.rst', 3, []), | |||
|
75 | ('test*', 75, []), | |||
|
76 | ('*model*', 1, []), | |||
|
77 | ('extension:rst', 48, []), | |||
|
78 | ('extension:rst api', 24, []), | |||
|
79 | ]) | |||
|
80 | def test_search_file_paths(self, query, expected_hits, expected_paths): | |||
|
81 | id_, params = build_data( | |||
|
82 | self.apikey_regular, 'search', | |||
|
83 | search_query=query, | |||
|
84 | search_type='path') | |||
|
85 | ||||
|
86 | response = api_call(self.app, params) | |||
|
87 | json_response = response.json | |||
|
88 | ||||
|
89 | assert json_response['result']['item_count'] == expected_hits | |||
|
90 | paths = [x['f_path'] for x in json_response['result']['results']] | |||
|
91 | ||||
|
92 | for expected_path in expected_paths: | |||
|
93 | assert expected_path in paths |
@@ -0,0 +1,112 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2011-2019 RhodeCode GmbH | |||
|
4 | # | |||
|
5 | # This program is free software: you can redistribute it and/or modify | |||
|
6 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU Affero General Public License | |||
|
15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | import logging | |||
|
23 | ||||
|
24 | from rhodecode.api import jsonrpc_method | |||
|
25 | from rhodecode.api.exc import JSONRPCValidationError | |||
|
26 | from rhodecode.api.utils import Optional | |||
|
27 | from rhodecode.lib.index import searcher_from_config | |||
|
28 | from rhodecode.model import validation_schema | |||
|
29 | from rhodecode.model.validation_schema.schemas import search_schema | |||
|
30 | ||||
|
31 | log = logging.getLogger(__name__) | |||
|
32 | ||||
|
33 | ||||
|
34 | @jsonrpc_method() | |||
|
35 | def search(request, apiuser, search_query, search_type, page_limit=Optional(10), | |||
|
36 | page=Optional(1), search_sort=Optional('newfirst'), | |||
|
37 | repo_name=Optional(None), repo_group_name=Optional(None)): | |||
|
38 | """ | |||
|
39 | Fetch Full Text Search results using API. | |||
|
40 | ||||
|
41 | :param apiuser: This is filled automatically from the |authtoken|. | |||
|
42 | :type apiuser: AuthUser | |||
|
43 | :param search_query: Search query. | |||
|
44 | :type search_query: str | |||
|
45 | :param search_type: Search type. The following are valid options: | |||
|
46 | * commit | |||
|
47 | * content | |||
|
48 | * path | |||
|
49 | :type search_type: str | |||
|
50 | :param page_limit: Page item limit, from 1 to 500. Default 10 items. | |||
|
51 | :type page_limit: Optional(int) | |||
|
52 | :param page: Page number. Default first page. | |||
|
53 | :type page: Optional(int) | |||
|
54 | :param search_sort: Search sort order. Default newfirst. The following are valid options: | |||
|
55 | * newfirst | |||
|
56 | * oldfirst | |||
|
57 | :type search_sort: Optional(str) | |||
|
58 | :param repo_name: Filter by one repo. Default is all. | |||
|
59 | :type repo_name: Optional(str) | |||
|
60 | :param repo_group_name: Filter by one repo group. Default is all. | |||
|
61 | :type repo_group_name: Optional(str) | |||
|
62 | """ | |||
|
63 | ||||
|
64 | data = {'execution_time': ''} | |||
|
65 | repo_name = Optional.extract(repo_name) | |||
|
66 | repo_group_name = Optional.extract(repo_group_name) | |||
|
67 | ||||
|
68 | schema = search_schema.SearchParamsSchema() | |||
|
69 | ||||
|
70 | try: | |||
|
71 | search_params = schema.deserialize( | |||
|
72 | dict(search_query=search_query, | |||
|
73 | search_type=search_type, | |||
|
74 | search_sort=Optional.extract(search_sort), | |||
|
75 | page_limit=Optional.extract(page_limit), | |||
|
76 | requested_page=Optional.extract(page)) | |||
|
77 | ) | |||
|
78 | except validation_schema.Invalid as err: | |||
|
79 | raise JSONRPCValidationError(colander_exc=err) | |||
|
80 | ||||
|
81 | search_query = search_params.get('search_query') | |||
|
82 | search_type = search_params.get('search_type') | |||
|
83 | search_sort = search_params.get('search_sort') | |||
|
84 | ||||
|
85 | if search_params.get('search_query'): | |||
|
86 | page_limit = search_params['page_limit'] | |||
|
87 | requested_page = search_params['requested_page'] | |||
|
88 | ||||
|
89 | searcher = searcher_from_config(request.registry.settings) | |||
|
90 | ||||
|
91 | try: | |||
|
92 | search_result = searcher.search( | |||
|
93 | search_query, search_type, apiuser, repo_name, repo_group_name, | |||
|
94 | requested_page=requested_page, page_limit=page_limit, sort=search_sort) | |||
|
95 | ||||
|
96 | data.update(dict( | |||
|
97 | results=list(search_result['results']), page=requested_page, | |||
|
98 | item_count=search_result['count'], | |||
|
99 | items_per_page=page_limit)) | |||
|
100 | finally: | |||
|
101 | searcher.cleanup() | |||
|
102 | ||||
|
103 | if not search_result['error']: | |||
|
104 | data['execution_time'] = '%s results (%.3f seconds)' % ( | |||
|
105 | search_result['count'], | |||
|
106 | search_result['runtime']) | |||
|
107 | else: | |||
|
108 | node = schema['search_query'] | |||
|
109 | raise JSONRPCValidationError( | |||
|
110 | colander_exc=validation_schema.Invalid(node, search_result['error'])) | |||
|
111 | ||||
|
112 | return data |
@@ -164,12 +164,6 b' self: super: {' | |||||
164 | }; |
|
164 | }; | |
165 | }); |
|
165 | }); | |
166 |
|
166 | |||
167 | "pytest-runner" = super."pytest-runner".override (attrs: { |
|
|||
168 | propagatedBuildInputs = [ |
|
|||
169 | self."setuptools-scm" |
|
|||
170 | ]; |
|
|||
171 | }); |
|
|||
172 |
|
||||
173 | "python-ldap" = super."python-ldap".override (attrs: { |
|
167 | "python-ldap" = super."python-ldap".override (attrs: { | |
174 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ |
|
168 | propagatedBuildInputs = attrs.propagatedBuildInputs ++ [ | |
175 | pkgs.openldap |
|
169 | pkgs.openldap |
@@ -5,7 +5,7 b'' | |||||
5 |
|
5 | |||
6 | self: super: { |
|
6 | self: super: { | |
7 | "alembic" = super.buildPythonPackage { |
|
7 | "alembic" = super.buildPythonPackage { | |
8 |
name = "alembic-1.0. |
|
8 | name = "alembic-1.0.8"; | |
9 | doCheck = false; |
|
9 | doCheck = false; | |
10 | propagatedBuildInputs = [ |
|
10 | propagatedBuildInputs = [ | |
11 | self."sqlalchemy" |
|
11 | self."sqlalchemy" | |
@@ -14,8 +14,8 b' self: super: {' | |||||
14 | self."python-dateutil" |
|
14 | self."python-dateutil" | |
15 | ]; |
|
15 | ]; | |
16 | src = fetchurl { |
|
16 | src = fetchurl { | |
17 |
url = "https://files.pythonhosted.org/packages/ |
|
17 | url = "https://files.pythonhosted.org/packages/d6/bb/ec1e21f2e303689ad2170eb47fc67df9ad4199ade6759a99474c4d3535c8/alembic-1.0.8.tar.gz"; | |
18 | sha256 = "0rpjqp2iq6p49x1nli18ivak1izz547nnjxi110mzrgc1v7dxzz9"; |
|
18 | sha256 = "1s34i1j0dsxbflxligwhnkf37a5hvcshsv8ibkcfdjf03ph42pah"; | |
19 | }; |
|
19 | }; | |
20 | meta = { |
|
20 | meta = { | |
21 | license = [ pkgs.lib.licenses.mit ]; |
|
21 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -1051,14 +1051,14 b' self: super: {' | |||||
1051 | }; |
|
1051 | }; | |
1052 | }; |
|
1052 | }; | |
1053 | "paste" = super.buildPythonPackage { |
|
1053 | "paste" = super.buildPythonPackage { | |
1054 |
name = "paste-3.0. |
|
1054 | name = "paste-3.0.8"; | |
1055 | doCheck = false; |
|
1055 | doCheck = false; | |
1056 | propagatedBuildInputs = [ |
|
1056 | propagatedBuildInputs = [ | |
1057 | self."six" |
|
1057 | self."six" | |
1058 | ]; |
|
1058 | ]; | |
1059 | src = fetchurl { |
|
1059 | src = fetchurl { | |
1060 |
url = "https://files.pythonhosted.org/packages/ |
|
1060 | url = "https://files.pythonhosted.org/packages/66/65/e3acf1663438483c1f6ced0b6c6f3b90da9f0faacb0a6e2aa0f3f9f4b235/Paste-3.0.8.tar.gz"; | |
1061 | sha256 = "1a6i8fh1fg8r4x800fvy9r82m15clwjim6yf2g9r4dff0y40dchv"; |
|
1061 | sha256 = "05w1sh6ky4d7pmdb8nv82n13w22jcn3qsagg5ih3hjmbws9kkwf4"; | |
1062 | }; |
|
1062 | }; | |
1063 | meta = { |
|
1063 | meta = { | |
1064 | license = [ pkgs.lib.licenses.mit ]; |
|
1064 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -1076,7 +1076,7 b' self: super: {' | |||||
1076 | }; |
|
1076 | }; | |
1077 | }; |
|
1077 | }; | |
1078 | "pastescript" = super.buildPythonPackage { |
|
1078 | "pastescript" = super.buildPythonPackage { | |
1079 |
name = "pastescript-3. |
|
1079 | name = "pastescript-3.1.0"; | |
1080 | doCheck = false; |
|
1080 | doCheck = false; | |
1081 | propagatedBuildInputs = [ |
|
1081 | propagatedBuildInputs = [ | |
1082 | self."paste" |
|
1082 | self."paste" | |
@@ -1084,8 +1084,8 b' self: super: {' | |||||
1084 | self."six" |
|
1084 | self."six" | |
1085 | ]; |
|
1085 | ]; | |
1086 | src = fetchurl { |
|
1086 | src = fetchurl { | |
1087 |
url = "https://files.pythonhosted.org/packages/0 |
|
1087 | url = "https://files.pythonhosted.org/packages/9e/1d/14db1c283eb21a5d36b6ba1114c13b709629711e64acab653d9994fe346f/PasteScript-3.1.0.tar.gz"; | |
1088 | sha256 = "1hvmyz1sbn7ws1syw567ph7km9fi0wi75r3vlyzx6sk0z26xkm6r"; |
|
1088 | sha256 = "02qcxjjr32ks7a6d4f533wl34ysc7yhwlrfcyqwqbzr52250v4fs"; | |
1089 | }; |
|
1089 | }; | |
1090 | meta = { |
|
1090 | meta = { | |
1091 | license = [ pkgs.lib.licenses.mit ]; |
|
1091 | license = [ pkgs.lib.licenses.mit ]; | |
@@ -1752,7 +1752,6 b' self: super: {' | |||||
1752 | ]; |
|
1752 | ]; | |
1753 | doCheck = true; |
|
1753 | doCheck = true; | |
1754 | propagatedBuildInputs = [ |
|
1754 | propagatedBuildInputs = [ | |
1755 | self."setuptools-scm" |
|
|||
1756 | self."amqp" |
|
1755 | self."amqp" | |
1757 | self."authomatic" |
|
1756 | self."authomatic" | |
1758 | self."babel" |
|
1757 | self."babel" | |
@@ -1942,17 +1941,6 b' self: super: {' | |||||
1942 | license = [ pkgs.lib.licenses.mit ]; |
|
1941 | license = [ pkgs.lib.licenses.mit ]; | |
1943 | }; |
|
1942 | }; | |
1944 | }; |
|
1943 | }; | |
1945 | "setuptools-scm" = super.buildPythonPackage { |
|
|||
1946 | name = "setuptools-scm-2.1.0"; |
|
|||
1947 | doCheck = false; |
|
|||
1948 | src = fetchurl { |
|
|||
1949 | url = "https://files.pythonhosted.org/packages/e5/62/f9e1ac314464eb5945c97542acb6bf6f3381dfa5d7a658de7730c36f31a1/setuptools_scm-2.1.0.tar.gz"; |
|
|||
1950 | sha256 = "0yb364cgk15sfw3x8ln4ssh98z1dj6n8iiz4r2rw1cfsxhgi8rx7"; |
|
|||
1951 | }; |
|
|||
1952 | meta = { |
|
|||
1953 | license = [ pkgs.lib.licenses.mit ]; |
|
|||
1954 | }; |
|
|||
1955 | }; |
|
|||
1956 | "simplegeneric" = super.buildPythonPackage { |
|
1944 | "simplegeneric" = super.buildPythonPackage { | |
1957 | name = "simplegeneric-0.8.1"; |
|
1945 | name = "simplegeneric-0.8.1"; | |
1958 | doCheck = false; |
|
1946 | doCheck = false; |
@@ -1,6 +1,5 b'' | |||||
1 | ## dependencies |
|
1 | ## dependencies | |
2 |
|
2 | |||
3 | setuptools-scm==2.1.0 |
|
|||
4 | amqp==2.3.1 |
|
3 | amqp==2.3.1 | |
5 | # not released authomatic that has updated some oauth providers |
|
4 | # not released authomatic that has updated some oauth providers | |
6 | https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801#egg=authomatic==0.1.0.post1 |
|
5 | https://code.rhodecode.com/upstream/authomatic/archive/90a9ce60cc405ae8a2bf5c3713acd5d78579a04e.tar.gz?md5=3c68720a1322b25254009518d1ff6801#egg=authomatic==0.1.0.post1 | |
@@ -35,9 +34,9 b' markupsafe==1.1.0' | |||||
35 | msgpack-python==0.5.6 |
|
34 | msgpack-python==0.5.6 | |
36 | pyotp==2.2.7 |
|
35 | pyotp==2.2.7 | |
37 | packaging==15.2 |
|
36 | packaging==15.2 | |
38 |
paste==3.0. |
|
37 | paste==3.0.8 | |
39 | pastedeploy==2.0.1 |
|
38 | pastedeploy==2.0.1 | |
40 |
pastescript==3. |
|
39 | pastescript==3.1.0 | |
41 | peppercorn==0.6 |
|
40 | peppercorn==0.6 | |
42 | psutil==5.5.1 |
|
41 | psutil==5.5.1 | |
43 | py-bcrypt==0.4 |
|
42 | py-bcrypt==0.4 | |
@@ -98,7 +97,7 b' nbformat==4.4.0' | |||||
98 | jupyter_client==5.0.0 |
|
97 | jupyter_client==5.0.0 | |
99 |
|
98 | |||
100 | ## cli tools |
|
99 | ## cli tools | |
101 |
alembic==1.0. |
|
100 | alembic==1.0.8 | |
102 | invoke==0.13.0 |
|
101 | invoke==0.13.0 | |
103 | bumpversion==0.5.3 |
|
102 | bumpversion==0.5.3 | |
104 |
|
103 |
@@ -272,17 +272,6 b'' | |||||
272 | { |
|
272 | { | |
273 | "license": [ |
|
273 | "license": [ | |
274 | { |
|
274 | { | |
275 | "fullName": "MIT License", |
|
|||
276 | "shortName": "mit", |
|
|||
277 | "spdxId": "MIT", |
|
|||
278 | "url": "http://spdx.org/licenses/MIT.html" |
|
|||
279 | } |
|
|||
280 | ], |
|
|||
281 | "name": "python2.7-setuptools-scm-2.1.0" |
|
|||
282 | }, |
|
|||
283 | { |
|
|||
284 | "license": [ |
|
|||
285 | { |
|
|||
286 | "fullName": "BSD 4-clause \"Original\" or \"Old\" License", |
|
275 | "fullName": "BSD 4-clause \"Original\" or \"Old\" License", | |
287 | "shortName": "bsdOriginal", |
|
276 | "shortName": "bsdOriginal", | |
288 | "spdxId": "BSD-4-Clause", |
|
277 | "spdxId": "BSD-4-Clause", |
General Comments 0
You need to be logged in to leave comments.
Login now