##// END OF EJS Templates
api: expose audit-logs API
ergo -
r4353:7a7df1ad default
parent child Browse files
Show More
@@ -1,118 +1,152 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2020 RhodeCode GmbH
3 # Copyright (C) 2011-2020 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
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
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
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/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import logging
22 import logging
23
23
24 from rhodecode.api import jsonrpc_method
24 from rhodecode.api import jsonrpc_method
25 from rhodecode.api.exc import JSONRPCValidationError
25 from rhodecode.api.exc import JSONRPCValidationError, JSONRPCForbidden
26 from rhodecode.api.utils import Optional
26 from rhodecode.api.utils import Optional, has_superadmin_permission
27 from rhodecode.lib.index import searcher_from_config
27 from rhodecode.lib.index import searcher_from_config
28 from rhodecode.lib.user_log_filter import user_log_filter
28 from rhodecode.model import validation_schema
29 from rhodecode.model import validation_schema
30 from rhodecode.model.db import joinedload, UserLog
29 from rhodecode.model.validation_schema.schemas import search_schema
31 from rhodecode.model.validation_schema.schemas import search_schema
30
32
31 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
32
34
33
35
34 @jsonrpc_method()
36 @jsonrpc_method()
35 def search(request, apiuser, search_query, search_type, page_limit=Optional(10),
37 def search(request, apiuser, search_query, search_type, page_limit=Optional(10),
36 page=Optional(1), search_sort=Optional('desc:date'),
38 page=Optional(1), search_sort=Optional('desc:date'),
37 repo_name=Optional(None), repo_group_name=Optional(None)):
39 repo_name=Optional(None), repo_group_name=Optional(None)):
38 """
40 """
39 Fetch Full Text Search results using API.
41 Fetch Full Text Search results using API.
40
42
41 :param apiuser: This is filled automatically from the |authtoken|.
43 :param apiuser: This is filled automatically from the |authtoken|.
42 :type apiuser: AuthUser
44 :type apiuser: AuthUser
43 :param search_query: Search query.
45 :param search_query: Search query.
44 :type search_query: str
46 :type search_query: str
45 :param search_type: Search type. The following are valid options:
47 :param search_type: Search type. The following are valid options:
46 * commit
48 * commit
47 * content
49 * content
48 * path
50 * path
49 :type search_type: str
51 :type search_type: str
50 :param page_limit: Page item limit, from 1 to 500. Default 10 items.
52 :param page_limit: Page item limit, from 1 to 500. Default 10 items.
51 :type page_limit: Optional(int)
53 :type page_limit: Optional(int)
52 :param page: Page number. Default first page.
54 :param page: Page number. Default first page.
53 :type page: Optional(int)
55 :type page: Optional(int)
54 :param search_sort: Search sort order.Must start with asc: or desc: Default desc:date.
56 :param search_sort: Search sort order.Must start with asc: or desc: Default desc:date.
55 The following are valid options:
57 The following are valid options:
56 * asc|desc:message.raw
58 * asc|desc:message.raw
57 * asc|desc:date
59 * asc|desc:date
58 * asc|desc:author.email.raw
60 * asc|desc:author.email.raw
59 * asc|desc:message.raw
61 * asc|desc:message.raw
60 * newfirst (old legacy equal to desc:date)
62 * newfirst (old legacy equal to desc:date)
61 * oldfirst (old legacy equal to asc:date)
63 * oldfirst (old legacy equal to asc:date)
62
64
63 :type search_sort: Optional(str)
65 :type search_sort: Optional(str)
64 :param repo_name: Filter by one repo. Default is all.
66 :param repo_name: Filter by one repo. Default is all.
65 :type repo_name: Optional(str)
67 :type repo_name: Optional(str)
66 :param repo_group_name: Filter by one repo group. Default is all.
68 :param repo_group_name: Filter by one repo group. Default is all.
67 :type repo_group_name: Optional(str)
69 :type repo_group_name: Optional(str)
68 """
70 """
69
71
70 data = {'execution_time': ''}
72 data = {'execution_time': ''}
71 repo_name = Optional.extract(repo_name)
73 repo_name = Optional.extract(repo_name)
72 repo_group_name = Optional.extract(repo_group_name)
74 repo_group_name = Optional.extract(repo_group_name)
73
75
74 schema = search_schema.SearchParamsSchema()
76 schema = search_schema.SearchParamsSchema()
75
77
76 try:
78 try:
77 search_params = schema.deserialize(
79 search_params = schema.deserialize(
78 dict(search_query=search_query,
80 dict(search_query=search_query,
79 search_type=search_type,
81 search_type=search_type,
80 search_sort=Optional.extract(search_sort),
82 search_sort=Optional.extract(search_sort),
81 page_limit=Optional.extract(page_limit),
83 page_limit=Optional.extract(page_limit),
82 requested_page=Optional.extract(page))
84 requested_page=Optional.extract(page))
83 )
85 )
84 except validation_schema.Invalid as err:
86 except validation_schema.Invalid as err:
85 raise JSONRPCValidationError(colander_exc=err)
87 raise JSONRPCValidationError(colander_exc=err)
86
88
87 search_query = search_params.get('search_query')
89 search_query = search_params.get('search_query')
88 search_type = search_params.get('search_type')
90 search_type = search_params.get('search_type')
89 search_sort = search_params.get('search_sort')
91 search_sort = search_params.get('search_sort')
90
92
91 if search_params.get('search_query'):
93 if search_params.get('search_query'):
92 page_limit = search_params['page_limit']
94 page_limit = search_params['page_limit']
93 requested_page = search_params['requested_page']
95 requested_page = search_params['requested_page']
94
96
95 searcher = searcher_from_config(request.registry.settings)
97 searcher = searcher_from_config(request.registry.settings)
96
98
97 try:
99 try:
98 search_result = searcher.search(
100 search_result = searcher.search(
99 search_query, search_type, apiuser, repo_name, repo_group_name,
101 search_query, search_type, apiuser, repo_name, repo_group_name,
100 requested_page=requested_page, page_limit=page_limit, sort=search_sort)
102 requested_page=requested_page, page_limit=page_limit, sort=search_sort)
101
103
102 data.update(dict(
104 data.update(dict(
103 results=list(search_result['results']), page=requested_page,
105 results=list(search_result['results']), page=requested_page,
104 item_count=search_result['count'],
106 item_count=search_result['count'],
105 items_per_page=page_limit))
107 items_per_page=page_limit))
106 finally:
108 finally:
107 searcher.cleanup()
109 searcher.cleanup()
108
110
109 if not search_result['error']:
111 if not search_result['error']:
110 data['execution_time'] = '%s results (%.4f seconds)' % (
112 data['execution_time'] = '%s results (%.4f seconds)' % (
111 search_result['count'],
113 search_result['count'],
112 search_result['runtime'])
114 search_result['runtime'])
113 else:
115 else:
114 node = schema['search_query']
116 node = schema['search_query']
115 raise JSONRPCValidationError(
117 raise JSONRPCValidationError(
116 colander_exc=validation_schema.Invalid(node, search_result['error']))
118 colander_exc=validation_schema.Invalid(node, search_result['error']))
117
119
118 return data
120 return data
121
122
123 @jsonrpc_method()
124 def get_audit_logs(request, apiuser, query):
125 """
126 return full audit logs based on the query.
127
128 Please see `example query in admin > settings > audit logs` for examples
129
130 :param apiuser: This is filled automatically from the |authtoken|.
131 :type apiuser: AuthUser
132 :param query: filter query, example: action:repo.artifact.add date:[20200401 TO 20200601]"
133 :type query: str
134 """
135
136 if not has_superadmin_permission(apiuser):
137 raise JSONRPCForbidden()
138
139 filter_term = query
140 ret = []
141
142 # show all user actions
143 user_log = UserLog.query() \
144 .options(joinedload(UserLog.user)) \
145 .options(joinedload(UserLog.repository)) \
146 .order_by(UserLog.action_date.desc())
147
148 audit_log = user_log_filter(user_log, filter_term)
149
150 for entry in audit_log:
151 ret.append(entry)
152 return ret
General Comments 0
You need to be logged in to leave comments. Login now