##// END OF EJS Templates
docs: update API documentation.
marcink -
r1603:a0209c61 default
parent child Browse files
Show More
@@ -1,376 +1,371 b''
1 .. _pull-request-methods-ref:
1 .. _pull-request-methods-ref:
2
2
3 pull_request methods
3 pull_request methods
4 ====================
4 ====================
5
5
6 close_pull_request
6 close_pull_request
7 ------------------
7 ------------------
8
8
9 .. py:function:: close_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>)
9 .. py:function:: close_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>)
10
10
11 Close the pull request specified by `pullrequestid`.
11 Close the pull request specified by `pullrequestid`.
12
12
13 :param apiuser: This is filled automatically from the |authtoken|.
13 :param apiuser: This is filled automatically from the |authtoken|.
14 :type apiuser: AuthUser
14 :type apiuser: AuthUser
15 :param repoid: Repository name or repository ID to which the pull
15 :param repoid: Repository name or repository ID to which the pull
16 request belongs.
16 request belongs.
17 :type repoid: str or int
17 :type repoid: str or int
18 :param pullrequestid: ID of the pull request to be closed.
18 :param pullrequestid: ID of the pull request to be closed.
19 :type pullrequestid: int
19 :type pullrequestid: int
20 :param userid: Close the pull request as this user.
20 :param userid: Close the pull request as this user.
21 :type userid: Optional(str or int)
21 :type userid: Optional(str or int)
22
22
23 Example output:
23 Example output:
24
24
25 .. code-block:: bash
25 .. code-block:: bash
26
26
27 "id": <id_given_in_input>,
27 "id": <id_given_in_input>,
28 "result":
28 "result": {
29 {
30 "pull_request_id": "<int>",
29 "pull_request_id": "<int>",
31 "closed": "<bool>"
30 "closed": "<bool>"
32 },
31 },
33 "error": null
32 "error": null
34
33
35
34
36 comment_pull_request
35 comment_pull_request
37 --------------------
36 --------------------
38
37
39 .. py:function:: comment_pull_request(apiuser, repoid, pullrequestid, message=<Optional:None>, commit_id=<Optional:None>, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
38 .. py:function:: comment_pull_request(apiuser, repoid, pullrequestid, message=<Optional:None>, commit_id=<Optional:None>, status=<Optional:None>, comment_type=<Optional:u'note'>, resolves_comment_id=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
40
39
41 Comment on the pull request specified with the `pullrequestid`,
40 Comment on the pull request specified with the `pullrequestid`,
42 in the |repo| specified by the `repoid`, and optionally change the
41 in the |repo| specified by the `repoid`, and optionally change the
43 review status.
42 review status.
44
43
45 :param apiuser: This is filled automatically from the |authtoken|.
44 :param apiuser: This is filled automatically from the |authtoken|.
46 :type apiuser: AuthUser
45 :type apiuser: AuthUser
47 :param repoid: The repository name or repository ID.
46 :param repoid: The repository name or repository ID.
48 :type repoid: str or int
47 :type repoid: str or int
49 :param pullrequestid: The pull request ID.
48 :param pullrequestid: The pull request ID.
50 :type pullrequestid: int
49 :type pullrequestid: int
51 :param commit_id: Specify the commit_id for which to set a comment. If
50 :param commit_id: Specify the commit_id for which to set a comment. If
52 given commit_id is different than latest in the PR status
51 given commit_id is different than latest in the PR status
53 change won't be performed.
52 change won't be performed.
54 :type commit_id: str
53 :type commit_id: str
55 :param message: The text content of the comment.
54 :param message: The text content of the comment.
56 :type message: str
55 :type message: str
57 :param status: (**Optional**) Set the approval status of the pull
56 :param status: (**Optional**) Set the approval status of the pull
58 request. One of: 'not_reviewed', 'approved', 'rejected',
57 request. One of: 'not_reviewed', 'approved', 'rejected',
59 'under_review'
58 'under_review'
60 :type status: str
59 :type status: str
61 :param comment_type: Comment type, one of: 'note', 'todo'
60 :param comment_type: Comment type, one of: 'note', 'todo'
62 :type comment_type: Optional(str), default: 'note'
61 :type comment_type: Optional(str), default: 'note'
63 :param userid: Comment on the pull request as this user
62 :param userid: Comment on the pull request as this user
64 :type userid: Optional(str or int)
63 :type userid: Optional(str or int)
65
64
66 Example output:
65 Example output:
67
66
68 .. code-block:: bash
67 .. code-block:: bash
69
68
70 id : <id_given_in_input>
69 id : <id_given_in_input>
71 result :
70 result : {
72 {
73 "pull_request_id": "<Integer>",
71 "pull_request_id": "<Integer>",
74 "comment_id": "<Integer>",
72 "comment_id": "<Integer>",
75 "status": {"given": <given_status>,
73 "status": {"given": <given_status>,
76 "was_changed": <bool status_was_actually_changed> },
74 "was_changed": <bool status_was_actually_changed> },
77 }
75 },
78 error : null
76 error : null
79
77
80
78
81 create_pull_request
79 create_pull_request
82 -------------------
80 -------------------
83
81
84 .. py:function:: create_pull_request(apiuser, source_repo, target_repo, source_ref, target_ref, title, description=<Optional:''>, reviewers=<Optional:None>)
82 .. py:function:: create_pull_request(apiuser, source_repo, target_repo, source_ref, target_ref, title, description=<Optional:''>, reviewers=<Optional:None>)
85
83
86 Creates a new pull request.
84 Creates a new pull request.
87
85
88 Accepts refs in the following formats:
86 Accepts refs in the following formats:
89
87
90 * branch:<branch_name>:<sha>
88 * branch:<branch_name>:<sha>
91 * branch:<branch_name>
89 * branch:<branch_name>
92 * bookmark:<bookmark_name>:<sha> (Mercurial only)
90 * bookmark:<bookmark_name>:<sha> (Mercurial only)
93 * bookmark:<bookmark_name> (Mercurial only)
91 * bookmark:<bookmark_name> (Mercurial only)
94
92
95 :param apiuser: This is filled automatically from the |authtoken|.
93 :param apiuser: This is filled automatically from the |authtoken|.
96 :type apiuser: AuthUser
94 :type apiuser: AuthUser
97 :param source_repo: Set the source repository name.
95 :param source_repo: Set the source repository name.
98 :type source_repo: str
96 :type source_repo: str
99 :param target_repo: Set the target repository name.
97 :param target_repo: Set the target repository name.
100 :type target_repo: str
98 :type target_repo: str
101 :param source_ref: Set the source ref name.
99 :param source_ref: Set the source ref name.
102 :type source_ref: str
100 :type source_ref: str
103 :param target_ref: Set the target ref name.
101 :param target_ref: Set the target ref name.
104 :type target_ref: str
102 :type target_ref: str
105 :param title: Set the pull request title.
103 :param title: Set the pull request title.
106 :type title: str
104 :type title: str
107 :param description: Set the pull request description.
105 :param description: Set the pull request description.
108 :type description: Optional(str)
106 :type description: Optional(str)
109 :param reviewers: Set the new pull request reviewers list.
107 :param reviewers: Set the new pull request reviewers list.
110 :type reviewers: Optional(list)
108 :type reviewers: Optional(list)
111 Accepts username strings or objects of the format:
109 Accepts username strings or objects of the format:
112 {
110
113 'username': 'nick', 'reasons': ['original author']
111 {'username': 'nick', 'reasons': ['original author']}
114 }
115
112
116
113
117 get_pull_request
114 get_pull_request
118 ----------------
115 ----------------
119
116
120 .. py:function:: get_pull_request(apiuser, repoid, pullrequestid)
117 .. py:function:: get_pull_request(apiuser, repoid, pullrequestid)
121
118
122 Get a pull request based on the given ID.
119 Get a pull request based on the given ID.
123
120
124 :param apiuser: This is filled automatically from the |authtoken|.
121 :param apiuser: This is filled automatically from the |authtoken|.
125 :type apiuser: AuthUser
122 :type apiuser: AuthUser
126 :param repoid: Repository name or repository ID from where the pull
123 :param repoid: Repository name or repository ID from where the pull
127 request was opened.
124 request was opened.
128 :type repoid: str or int
125 :type repoid: str or int
129 :param pullrequestid: ID of the requested pull request.
126 :param pullrequestid: ID of the requested pull request.
130 :type pullrequestid: int
127 :type pullrequestid: int
131
128
132 Example output:
129 Example output:
133
130
134 .. code-block:: bash
131 .. code-block:: bash
135
132
136 "id": <id_given_in_input>,
133 "id": <id_given_in_input>,
137 "result":
134 "result":
138 {
135 {
139 "pull_request_id": "<pull_request_id>",
136 "pull_request_id": "<pull_request_id>",
140 "url": "<url>",
137 "url": "<url>",
141 "title": "<title>",
138 "title": "<title>",
142 "description": "<description>",
139 "description": "<description>",
143 "status" : "<status>",
140 "status" : "<status>",
144 "created_on": "<date_time_created>",
141 "created_on": "<date_time_created>",
145 "updated_on": "<date_time_updated>",
142 "updated_on": "<date_time_updated>",
146 "commit_ids": [
143 "commit_ids": [
147 ...
144 ...
148 "<commit_id>",
145 "<commit_id>",
149 "<commit_id>",
146 "<commit_id>",
150 ...
147 ...
151 ],
148 ],
152 "review_status": "<review_status>",
149 "review_status": "<review_status>",
153 "mergeable": {
150 "mergeable": {
154 "status": "<bool>",
151 "status": "<bool>",
155 "message": "<message>",
152 "message": "<message>",
156 },
153 },
157 "source": {
154 "source": {
158 "clone_url": "<clone_url>",
155 "clone_url": "<clone_url>",
159 "repository": "<repository_name>",
156 "repository": "<repository_name>",
160 "reference":
157 "reference":
161 {
158 {
162 "name": "<name>",
159 "name": "<name>",
163 "type": "<type>",
160 "type": "<type>",
164 "commit_id": "<commit_id>",
161 "commit_id": "<commit_id>",
165 }
162 }
166 },
163 },
167 "target": {
164 "target": {
168 "clone_url": "<clone_url>",
165 "clone_url": "<clone_url>",
169 "repository": "<repository_name>",
166 "repository": "<repository_name>",
170 "reference":
167 "reference":
171 {
168 {
172 "name": "<name>",
169 "name": "<name>",
173 "type": "<type>",
170 "type": "<type>",
174 "commit_id": "<commit_id>",
171 "commit_id": "<commit_id>",
175 }
172 }
176 },
173 },
177 "merge": {
174 "merge": {
178 "clone_url": "<clone_url>",
175 "clone_url": "<clone_url>",
179 "reference":
176 "reference":
180 {
177 {
181 "name": "<name>",
178 "name": "<name>",
182 "type": "<type>",
179 "type": "<type>",
183 "commit_id": "<commit_id>",
180 "commit_id": "<commit_id>",
184 }
181 }
185 },
182 },
186 "author": <user_obj>,
183 "author": <user_obj>,
187 "reviewers": [
184 "reviewers": [
188 ...
185 ...
189 {
186 {
190 "user": "<user_obj>",
187 "user": "<user_obj>",
191 "review_status": "<review_status>",
188 "review_status": "<review_status>",
192 }
189 }
193 ...
190 ...
194 ]
191 ]
195 },
192 },
196 "error": null
193 "error": null
197
194
198
195
199 get_pull_requests
196 get_pull_requests
200 -----------------
197 -----------------
201
198
202 .. py:function:: get_pull_requests(apiuser, repoid, status=<Optional:'new'>)
199 .. py:function:: get_pull_requests(apiuser, repoid, status=<Optional:'new'>)
203
200
204 Get all pull requests from the repository specified in `repoid`.
201 Get all pull requests from the repository specified in `repoid`.
205
202
206 :param apiuser: This is filled automatically from the |authtoken|.
203 :param apiuser: This is filled automatically from the |authtoken|.
207 :type apiuser: AuthUser
204 :type apiuser: AuthUser
208 :param repoid: Repository name or repository ID.
205 :param repoid: Repository name or repository ID.
209 :type repoid: str or int
206 :type repoid: str or int
210 :param status: Only return pull requests with the specified status.
207 :param status: Only return pull requests with the specified status.
211 Valid options are.
208 Valid options are.
212 * ``new`` (default)
209 * ``new`` (default)
213 * ``open``
210 * ``open``
214 * ``closed``
211 * ``closed``
215 :type status: str
212 :type status: str
216
213
217 Example output:
214 Example output:
218
215
219 .. code-block:: bash
216 .. code-block:: bash
220
217
221 "id": <id_given_in_input>,
218 "id": <id_given_in_input>,
222 "result":
219 "result":
223 [
220 [
224 ...
221 ...
225 {
222 {
226 "pull_request_id": "<pull_request_id>",
223 "pull_request_id": "<pull_request_id>",
227 "url": "<url>",
224 "url": "<url>",
228 "title" : "<title>",
225 "title" : "<title>",
229 "description": "<description>",
226 "description": "<description>",
230 "status": "<status>",
227 "status": "<status>",
231 "created_on": "<date_time_created>",
228 "created_on": "<date_time_created>",
232 "updated_on": "<date_time_updated>",
229 "updated_on": "<date_time_updated>",
233 "commit_ids": [
230 "commit_ids": [
234 ...
231 ...
235 "<commit_id>",
232 "<commit_id>",
236 "<commit_id>",
233 "<commit_id>",
237 ...
234 ...
238 ],
235 ],
239 "review_status": "<review_status>",
236 "review_status": "<review_status>",
240 "mergeable": {
237 "mergeable": {
241 "status": "<bool>",
238 "status": "<bool>",
242 "message: "<message>",
239 "message: "<message>",
243 },
240 },
244 "source": {
241 "source": {
245 "clone_url": "<clone_url>",
242 "clone_url": "<clone_url>",
246 "reference":
243 "reference":
247 {
244 {
248 "name": "<name>",
245 "name": "<name>",
249 "type": "<type>",
246 "type": "<type>",
250 "commit_id": "<commit_id>",
247 "commit_id": "<commit_id>",
251 }
248 }
252 },
249 },
253 "target": {
250 "target": {
254 "clone_url": "<clone_url>",
251 "clone_url": "<clone_url>",
255 "reference":
252 "reference":
256 {
253 {
257 "name": "<name>",
254 "name": "<name>",
258 "type": "<type>",
255 "type": "<type>",
259 "commit_id": "<commit_id>",
256 "commit_id": "<commit_id>",
260 }
257 }
261 },
258 },
262 "merge": {
259 "merge": {
263 "clone_url": "<clone_url>",
260 "clone_url": "<clone_url>",
264 "reference":
261 "reference":
265 {
262 {
266 "name": "<name>",
263 "name": "<name>",
267 "type": "<type>",
264 "type": "<type>",
268 "commit_id": "<commit_id>",
265 "commit_id": "<commit_id>",
269 }
266 }
270 },
267 },
271 "author": <user_obj>,
268 "author": <user_obj>,
272 "reviewers": [
269 "reviewers": [
273 ...
270 ...
274 {
271 {
275 "user": "<user_obj>",
272 "user": "<user_obj>",
276 "review_status": "<review_status>",
273 "review_status": "<review_status>",
277 }
274 }
278 ...
275 ...
279 ]
276 ]
280 }
277 }
281 ...
278 ...
282 ],
279 ],
283 "error": null
280 "error": null
284
281
285
282
286 merge_pull_request
283 merge_pull_request
287 ------------------
284 ------------------
288
285
289 .. py:function:: merge_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>)
286 .. py:function:: merge_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>)
290
287
291 Merge the pull request specified by `pullrequestid` into its target
288 Merge the pull request specified by `pullrequestid` into its target
292 repository.
289 repository.
293
290
294 :param apiuser: This is filled automatically from the |authtoken|.
291 :param apiuser: This is filled automatically from the |authtoken|.
295 :type apiuser: AuthUser
292 :type apiuser: AuthUser
296 :param repoid: The Repository name or repository ID of the
293 :param repoid: The Repository name or repository ID of the
297 target repository to which the |pr| is to be merged.
294 target repository to which the |pr| is to be merged.
298 :type repoid: str or int
295 :type repoid: str or int
299 :param pullrequestid: ID of the pull request which shall be merged.
296 :param pullrequestid: ID of the pull request which shall be merged.
300 :type pullrequestid: int
297 :type pullrequestid: int
301 :param userid: Merge the pull request as this user.
298 :param userid: Merge the pull request as this user.
302 :type userid: Optional(str or int)
299 :type userid: Optional(str or int)
303
300
304 Example output:
301 Example output:
305
302
306 .. code-block:: bash
303 .. code-block:: bash
307
304
308 "id": <id_given_in_input>,
305 "id": <id_given_in_input>,
309 "result":
306 "result": {
310 {
311 "executed": "<bool>",
307 "executed": "<bool>",
312 "failure_reason": "<int>",
308 "failure_reason": "<int>",
313 "merge_commit_id": "<merge_commit_id>",
309 "merge_commit_id": "<merge_commit_id>",
314 "possible": "<bool>",
310 "possible": "<bool>",
315 "merge_ref": {
311 "merge_ref": {
316 "commit_id": "<commit_id>",
312 "commit_id": "<commit_id>",
317 "type": "<type>",
313 "type": "<type>",
318 "name": "<name>"
314 "name": "<name>"
319 }
315 }
320 },
316 },
321 "error": null
317 "error": null
322
318
323
319
324 update_pull_request
320 update_pull_request
325 -------------------
321 -------------------
326
322
327 .. py:function:: update_pull_request(apiuser, repoid, pullrequestid, title=<Optional:''>, description=<Optional:''>, reviewers=<Optional:None>, update_commits=<Optional:None>, close_pull_request=<Optional:None>)
323 .. py:function:: update_pull_request(apiuser, repoid, pullrequestid, title=<Optional:''>, description=<Optional:''>, reviewers=<Optional:None>, update_commits=<Optional:None>, close_pull_request=<Optional:None>)
328
324
329 Updates a pull request.
325 Updates a pull request.
330
326
331 :param apiuser: This is filled automatically from the |authtoken|.
327 :param apiuser: This is filled automatically from the |authtoken|.
332 :type apiuser: AuthUser
328 :type apiuser: AuthUser
333 :param repoid: The repository name or repository ID.
329 :param repoid: The repository name or repository ID.
334 :type repoid: str or int
330 :type repoid: str or int
335 :param pullrequestid: The pull request ID.
331 :param pullrequestid: The pull request ID.
336 :type pullrequestid: int
332 :type pullrequestid: int
337 :param title: Set the pull request title.
333 :param title: Set the pull request title.
338 :type title: str
334 :type title: str
339 :param description: Update pull request description.
335 :param description: Update pull request description.
340 :type description: Optional(str)
336 :type description: Optional(str)
341 :param reviewers: Update pull request reviewers list with new value.
337 :param reviewers: Update pull request reviewers list with new value.
342 :type reviewers: Optional(list)
338 :type reviewers: Optional(list)
343 :param update_commits: Trigger update of commits for this pull request
339 :param update_commits: Trigger update of commits for this pull request
344 :type: update_commits: Optional(bool)
340 :type: update_commits: Optional(bool)
345 :param close_pull_request: Close this pull request with rejected state
341 :param close_pull_request: Close this pull request with rejected state
346 :type: close_pull_request: Optional(bool)
342 :type: close_pull_request: Optional(bool)
347
343
348 Example output:
344 Example output:
349
345
350 .. code-block:: bash
346 .. code-block:: bash
351
347
352 id : <id_given_in_input>
348 id : <id_given_in_input>
353 result :
349 result : {
354 {
355 "msg": "Updated pull request `63`",
350 "msg": "Updated pull request `63`",
356 "pull_request": <pull_request_object>,
351 "pull_request": <pull_request_object>,
357 "updated_reviewers": {
352 "updated_reviewers": {
358 "added": [
353 "added": [
359 "username"
354 "username"
360 ],
355 ],
361 "removed": []
356 "removed": []
362 },
357 },
363 "updated_commits": {
358 "updated_commits": {
364 "added": [
359 "added": [
365 "<sha1_hash>"
360 "<sha1_hash>"
366 ],
361 ],
367 "common": [
362 "common": [
368 "<sha1_hash>",
363 "<sha1_hash>",
369 "<sha1_hash>",
364 "<sha1_hash>",
370 ],
365 ],
371 "removed": []
366 "removed": []
372 }
367 }
373 }
368 }
374 error : null
369 error : null
375
370
376
371
@@ -1,158 +1,210 b''
1 .. _server-methods-ref:
1 .. _server-methods-ref:
2
2
3 server methods
3 server methods
4 ==============
4 ==============
5
5
6 cleanup_sessions
6 cleanup_sessions
7 ----------------
7 ----------------
8
8
9 .. py:function:: cleanup_sessions(apiuser, older_then=<Optional:60>)
9 .. py:function:: cleanup_sessions(apiuser, older_then=<Optional:60>)
10
10
11 Triggers a session cleanup action.
11 Triggers a session cleanup action.
12
12
13 If the ``older_then`` option is set, only sessions that hasn't been
13 If the ``older_then`` option is set, only sessions that hasn't been
14 accessed in the given number of days will be removed.
14 accessed in the given number of days will be removed.
15
15
16 This command can only be run using an |authtoken| with admin rights to
16 This command can only be run using an |authtoken| with admin rights to
17 the specified repository.
17 the specified repository.
18
18
19 This command takes the following options:
19 This command takes the following options:
20
20
21 :param apiuser: This is filled automatically from the |authtoken|.
21 :param apiuser: This is filled automatically from the |authtoken|.
22 :type apiuser: AuthUser
22 :type apiuser: AuthUser
23 :param older_then: Deletes session that hasn't been accessed
23 :param older_then: Deletes session that hasn't been accessed
24 in given number of days.
24 in given number of days.
25 :type older_then: Optional(int)
25 :type older_then: Optional(int)
26
26
27 Example output:
27 Example output:
28
28
29 .. code-block:: bash
29 .. code-block:: bash
30
30
31 id : <id_given_in_input>
31 id : <id_given_in_input>
32 result: {
32 result: {
33 "backend": "<type of backend>",
33 "backend": "<type of backend>",
34 "sessions_removed": <number_of_removed_sessions>
34 "sessions_removed": <number_of_removed_sessions>
35 }
35 }
36 error : null
36 error : null
37
37
38 Example error output:
38 Example error output:
39
39
40 .. code-block:: bash
40 .. code-block:: bash
41
41
42 id : <id_given_in_input>
42 id : <id_given_in_input>
43 result : null
43 result : null
44 error : {
44 error : {
45 'Error occurred during session cleanup'
45 'Error occurred during session cleanup'
46 }
46 }
47
47
48
48
49 get_ip
49 get_ip
50 ------
50 ------
51
51
52 .. py:function:: get_ip(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
52 .. py:function:: get_ip(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
53
53
54 Displays the IP Address as seen from the |RCE| server.
54 Displays the IP Address as seen from the |RCE| server.
55
55
56 * This command displays the IP Address, as well as all the defined IP
56 * This command displays the IP Address, as well as all the defined IP
57 addresses for the specified user. If the ``userid`` is not set, the
57 addresses for the specified user. If the ``userid`` is not set, the
58 data returned is for the user calling the method.
58 data returned is for the user calling the method.
59
59
60 This command can only be run using an |authtoken| with admin rights to
60 This command can only be run using an |authtoken| with admin rights to
61 the specified repository.
61 the specified repository.
62
62
63 This command takes the following options:
63 This command takes the following options:
64
64
65 :param apiuser: This is filled automatically from |authtoken|.
65 :param apiuser: This is filled automatically from |authtoken|.
66 :type apiuser: AuthUser
66 :type apiuser: AuthUser
67 :param userid: Sets the userid for which associated IP Address data
67 :param userid: Sets the userid for which associated IP Address data
68 is returned.
68 is returned.
69 :type userid: Optional(str or int)
69 :type userid: Optional(str or int)
70
70
71 Example output:
71 Example output:
72
72
73 .. code-block:: bash
73 .. code-block:: bash
74
74
75 id : <id_given_in_input>
75 id : <id_given_in_input>
76 result : {
76 result : {
77 "server_ip_addr": "<ip_from_clien>",
77 "server_ip_addr": "<ip_from_clien>",
78 "user_ips": [
78 "user_ips": [
79 {
79 {
80 "ip_addr": "<ip_with_mask>",
80 "ip_addr": "<ip_with_mask>",
81 "ip_range": ["<start_ip>", "<end_ip>"],
81 "ip_range": ["<start_ip>", "<end_ip>"],
82 },
82 },
83 ...
83 ...
84 ]
84 ]
85 }
85 }
86
86
87
87
88 get_method
89 ----------
90
91 .. py:function:: get_method(apiuser, pattern=<Optional:'*'>)
92
93 Returns list of all available API methods. By default match pattern
94 os "*" but any other pattern can be specified. eg *comment* will return
95 all methods with comment inside them. If just single method is matched
96 returned data will also include method specification
97
98 This command can only be run using an |authtoken| with admin rights to
99 the specified repository.
100
101 This command takes the following options:
102
103 :param apiuser: This is filled automatically from the |authtoken|.
104 :type apiuser: AuthUser
105 :param pattern: pattern to match method names against
106 :type older_then: Optional("*")
107
108 Example output:
109
110 .. code-block:: bash
111
112 id : <id_given_in_input>
113 "result": [
114 "changeset_comment",
115 "comment_pull_request",
116 "comment_commit"
117 ]
118 error : null
119
120 .. code-block:: bash
121
122 id : <id_given_in_input>
123 "result": [
124 "comment_commit",
125 {
126 "apiuser": "<RequiredType>",
127 "comment_type": "<Optional:u'note'>",
128 "commit_id": "<RequiredType>",
129 "message": "<RequiredType>",
130 "repoid": "<RequiredType>",
131 "request": "<RequiredType>",
132 "resolves_comment_id": "<Optional:None>",
133 "status": "<Optional:None>",
134 "userid": "<Optional:<OptionalAttr:apiuser>>"
135 }
136 ]
137 error : null
138
139
88 get_server_info
140 get_server_info
89 ---------------
141 ---------------
90
142
91 .. py:function:: get_server_info(apiuser)
143 .. py:function:: get_server_info(apiuser)
92
144
93 Returns the |RCE| server information.
145 Returns the |RCE| server information.
94
146
95 This includes the running version of |RCE| and all installed
147 This includes the running version of |RCE| and all installed
96 packages. This command takes the following options:
148 packages. This command takes the following options:
97
149
98 :param apiuser: This is filled automatically from the |authtoken|.
150 :param apiuser: This is filled automatically from the |authtoken|.
99 :type apiuser: AuthUser
151 :type apiuser: AuthUser
100
152
101 Example output:
153 Example output:
102
154
103 .. code-block:: bash
155 .. code-block:: bash
104
156
105 id : <id_given_in_input>
157 id : <id_given_in_input>
106 result : {
158 result : {
107 'modules': [<module name>,...]
159 'modules': [<module name>,...]
108 'py_version': <python version>,
160 'py_version': <python version>,
109 'platform': <platform type>,
161 'platform': <platform type>,
110 'rhodecode_version': <rhodecode version>
162 'rhodecode_version': <rhodecode version>
111 }
163 }
112 error : null
164 error : null
113
165
114
166
115 rescan_repos
167 rescan_repos
116 ------------
168 ------------
117
169
118 .. py:function:: rescan_repos(apiuser, remove_obsolete=<Optional:False>)
170 .. py:function:: rescan_repos(apiuser, remove_obsolete=<Optional:False>)
119
171
120 Triggers a rescan of the specified repositories.
172 Triggers a rescan of the specified repositories.
121
173
122 * If the ``remove_obsolete`` option is set, it also deletes repositories
174 * If the ``remove_obsolete`` option is set, it also deletes repositories
123 that are found in the database but not on the file system, so called
175 that are found in the database but not on the file system, so called
124 "clean zombies".
176 "clean zombies".
125
177
126 This command can only be run using an |authtoken| with admin rights to
178 This command can only be run using an |authtoken| with admin rights to
127 the specified repository.
179 the specified repository.
128
180
129 This command takes the following options:
181 This command takes the following options:
130
182
131 :param apiuser: This is filled automatically from the |authtoken|.
183 :param apiuser: This is filled automatically from the |authtoken|.
132 :type apiuser: AuthUser
184 :type apiuser: AuthUser
133 :param remove_obsolete: Deletes repositories from the database that
185 :param remove_obsolete: Deletes repositories from the database that
134 are not found on the filesystem.
186 are not found on the filesystem.
135 :type remove_obsolete: Optional(``True`` | ``False``)
187 :type remove_obsolete: Optional(``True`` | ``False``)
136
188
137 Example output:
189 Example output:
138
190
139 .. code-block:: bash
191 .. code-block:: bash
140
192
141 id : <id_given_in_input>
193 id : <id_given_in_input>
142 result : {
194 result : {
143 'added': [<added repository name>,...]
195 'added': [<added repository name>,...]
144 'removed': [<removed repository name>,...]
196 'removed': [<removed repository name>,...]
145 }
197 }
146 error : null
198 error : null
147
199
148 Example error output:
200 Example error output:
149
201
150 .. code-block:: bash
202 .. code-block:: bash
151
203
152 id : <id_given_in_input>
204 id : <id_given_in_input>
153 result : null
205 result : null
154 error : {
206 error : {
155 'Error occurred during rescan repositories action'
207 'Error occurred during rescan repositories action'
156 }
208 }
157
209
158
210
@@ -1,297 +1,325 b''
1 .. _user-methods-ref:
1 .. _user-methods-ref:
2
2
3 user methods
3 user methods
4 ============
4 ============
5
5
6 create_user
6 create_user
7 -----------
7 -----------
8
8
9 .. py:function:: create_user(apiuser, username, email, password=<Optional:''>, firstname=<Optional:''>, lastname=<Optional:''>, active=<Optional:True>, admin=<Optional:False>, extern_name=<Optional:'rhodecode'>, extern_type=<Optional:'rhodecode'>, force_password_change=<Optional:False>, create_personal_repo_group=<Optional:None>)
9 .. py:function:: create_user(apiuser, username, email, password=<Optional:''>, firstname=<Optional:''>, lastname=<Optional:''>, active=<Optional:True>, admin=<Optional:False>, extern_name=<Optional:'rhodecode'>, extern_type=<Optional:'rhodecode'>, force_password_change=<Optional:False>, create_personal_repo_group=<Optional:None>)
10
10
11 Creates a new user and returns the new user object.
11 Creates a new user and returns the new user object.
12
12
13 This command can only be run using an |authtoken| with admin rights to
13 This command can only be run using an |authtoken| with admin rights to
14 the specified repository.
14 the specified repository.
15
15
16 This command takes the following options:
16 This command takes the following options:
17
17
18 :param apiuser: This is filled automatically from the |authtoken|.
18 :param apiuser: This is filled automatically from the |authtoken|.
19 :type apiuser: AuthUser
19 :type apiuser: AuthUser
20 :param username: Set the new username.
20 :param username: Set the new username.
21 :type username: str or int
21 :type username: str or int
22 :param email: Set the user email address.
22 :param email: Set the user email address.
23 :type email: str
23 :type email: str
24 :param password: Set the new user password.
24 :param password: Set the new user password.
25 :type password: Optional(str)
25 :type password: Optional(str)
26 :param firstname: Set the new user firstname.
26 :param firstname: Set the new user firstname.
27 :type firstname: Optional(str)
27 :type firstname: Optional(str)
28 :param lastname: Set the new user surname.
28 :param lastname: Set the new user surname.
29 :type lastname: Optional(str)
29 :type lastname: Optional(str)
30 :param active: Set the user as active.
30 :param active: Set the user as active.
31 :type active: Optional(``True`` | ``False``)
31 :type active: Optional(``True`` | ``False``)
32 :param admin: Give the new user admin rights.
32 :param admin: Give the new user admin rights.
33 :type admin: Optional(``True`` | ``False``)
33 :type admin: Optional(``True`` | ``False``)
34 :param extern_name: Set the authentication plugin name.
34 :param extern_name: Set the authentication plugin name.
35 Using LDAP this is filled with LDAP UID.
35 Using LDAP this is filled with LDAP UID.
36 :type extern_name: Optional(str)
36 :type extern_name: Optional(str)
37 :param extern_type: Set the new user authentication plugin.
37 :param extern_type: Set the new user authentication plugin.
38 :type extern_type: Optional(str)
38 :type extern_type: Optional(str)
39 :param force_password_change: Force the new user to change password
39 :param force_password_change: Force the new user to change password
40 on next login.
40 on next login.
41 :type force_password_change: Optional(``True`` | ``False``)
41 :type force_password_change: Optional(``True`` | ``False``)
42 :param create_personal_repo_group: Create personal repo group for this user
42 :param create_personal_repo_group: Create personal repo group for this user
43 :type create_personal_repo_group: Optional(``True`` | ``False``)
43 :type create_personal_repo_group: Optional(``True`` | ``False``)
44
44 Example output:
45 Example output:
45
46
46 .. code-block:: bash
47 .. code-block:: bash
47
48
48 id : <id_given_in_input>
49 id : <id_given_in_input>
49 result: {
50 result: {
50 "msg" : "created new user `<username>`",
51 "msg" : "created new user `<username>`",
51 "user": <user_obj>
52 "user": <user_obj>
52 }
53 }
53 error: null
54 error: null
54
55
55 Example error output:
56 Example error output:
56
57
57 .. code-block:: bash
58 .. code-block:: bash
58
59
59 id : <id_given_in_input>
60 id : <id_given_in_input>
60 result : null
61 result : null
61 error : {
62 error : {
62 "user `<username>` already exist"
63 "user `<username>` already exist"
63 or
64 or
64 "email `<email>` already exist"
65 "email `<email>` already exist"
65 or
66 or
66 "failed to create user `<username>`"
67 "failed to create user `<username>`"
67 }
68 }
68
69
69
70
70 delete_user
71 delete_user
71 -----------
72 -----------
72
73
73 .. py:function:: delete_user(apiuser, userid)
74 .. py:function:: delete_user(apiuser, userid)
74
75
75 Deletes the specified user from the |RCE| user database.
76 Deletes the specified user from the |RCE| user database.
76
77
77 This command can only be run using an |authtoken| with admin rights to
78 This command can only be run using an |authtoken| with admin rights to
78 the specified repository.
79 the specified repository.
79
80
80 .. important::
81 .. important::
81
82
82 Ensure all open pull requests and open code review
83 Ensure all open pull requests and open code review
83 requests to this user are close.
84 requests to this user are close.
84
85
85 Also ensure all repositories, or repository groups owned by this
86 Also ensure all repositories, or repository groups owned by this
86 user are reassigned before deletion.
87 user are reassigned before deletion.
87
88
88 This command takes the following options:
89 This command takes the following options:
89
90
90 :param apiuser: This is filled automatically from the |authtoken|.
91 :param apiuser: This is filled automatically from the |authtoken|.
91 :type apiuser: AuthUser
92 :type apiuser: AuthUser
92 :param userid: Set the user to delete.
93 :param userid: Set the user to delete.
93 :type userid: str or int
94 :type userid: str or int
94
95
95 Example output:
96 Example output:
96
97
97 .. code-block:: bash
98 .. code-block:: bash
98
99
99 id : <id_given_in_input>
100 id : <id_given_in_input>
100 result: {
101 result: {
101 "msg" : "deleted user ID:<userid> <username>",
102 "msg" : "deleted user ID:<userid> <username>",
102 "user": null
103 "user": null
103 }
104 }
104 error: null
105 error: null
105
106
106 Example error output:
107 Example error output:
107
108
108 .. code-block:: bash
109 .. code-block:: bash
109
110
110 id : <id_given_in_input>
111 id : <id_given_in_input>
111 result : null
112 result : null
112 error : {
113 error : {
113 "failed to delete user ID:<userid> <username>"
114 "failed to delete user ID:<userid> <username>"
114 }
115 }
115
116
116
117
117 get_user
118 get_user
118 --------
119 --------
119
120
120 .. py:function:: get_user(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
121 .. py:function:: get_user(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
121
122
122 Returns the information associated with a username or userid.
123 Returns the information associated with a username or userid.
123
124
124 * If the ``userid`` is not set, this command returns the information
125 * If the ``userid`` is not set, this command returns the information
125 for the ``userid`` calling the method.
126 for the ``userid`` calling the method.
126
127
127 .. note::
128 .. note::
128
129
129 Normal users may only run this command against their ``userid``. For
130 Normal users may only run this command against their ``userid``. For
130 full privileges you must run this command using an |authtoken| with
131 full privileges you must run this command using an |authtoken| with
131 admin rights.
132 admin rights.
132
133
133 :param apiuser: This is filled automatically from the |authtoken|.
134 :param apiuser: This is filled automatically from the |authtoken|.
134 :type apiuser: AuthUser
135 :type apiuser: AuthUser
135 :param userid: Sets the userid for which data will be returned.
136 :param userid: Sets the userid for which data will be returned.
136 :type userid: Optional(str or int)
137 :type userid: Optional(str or int)
137
138
138 Example output:
139 Example output:
139
140
140 .. code-block:: bash
141 .. code-block:: bash
141
142
142 {
143 {
143 "error": null,
144 "error": null,
144 "id": <id>,
145 "id": <id>,
145 "result": {
146 "result": {
146 "active": true,
147 "active": true,
147 "admin": false,
148 "admin": false,
148 "api_key": "api-key",
149 "api_keys": [ list of keys ],
149 "api_keys": [ list of keys ],
150 "auth_tokens": [ list of tokens with details ],
150 "email": "user@example.com",
151 "email": "user@example.com",
151 "emails": [
152 "emails": [
152 "user@example.com"
153 "user@example.com"
153 ],
154 ],
154 "extern_name": "rhodecode",
155 "extern_name": "rhodecode",
155 "extern_type": "rhodecode",
156 "extern_type": "rhodecode",
156 "firstname": "username",
157 "firstname": "username",
157 "ip_addresses": [],
158 "ip_addresses": [],
158 "language": null,
159 "language": null,
159 "last_login": "Timestamp",
160 "last_login": "Timestamp",
161 "last_activity": "Timestamp",
160 "lastname": "surnae",
162 "lastname": "surnae",
161 "permissions": {
163 "permissions": {
162 "global": [
164 "global": [
163 "hg.inherit_default_perms.true",
165 "hg.inherit_default_perms.true",
164 "usergroup.read",
166 "usergroup.read",
165 "hg.repogroup.create.false",
167 "hg.repogroup.create.false",
166 "hg.create.none",
168 "hg.create.none",
167 "hg.password_reset.enabled",
169 "hg.password_reset.enabled",
168 "hg.extern_activate.manual",
170 "hg.extern_activate.manual",
169 "hg.create.write_on_repogroup.false",
171 "hg.create.write_on_repogroup.false",
170 "hg.usergroup.create.false",
172 "hg.usergroup.create.false",
171 "group.none",
173 "group.none",
172 "repository.none",
174 "repository.none",
173 "hg.register.none",
175 "hg.register.none",
174 "hg.fork.repository"
176 "hg.fork.repository"
175 ],
177 ],
176 "repositories": { "username/example": "repository.write"},
178 "repositories": { "username/example": "repository.write"},
177 "repositories_groups": { "user-group/repo": "group.none" },
179 "repositories_groups": { "user-group/repo": "group.none" },
178 "user_groups": { "user_group_name": "usergroup.read" }
180 "user_groups": { "user_group_name": "usergroup.read" }
179 },
181 },
180 "user_id": 32,
182 "user_id": 32,
181 "username": "username"
183 "username": "username"
182 }
184 }
183 }
185 }
184
186
185
187
188 get_user_audit_logs
189 -------------------
190
191 .. py:function:: get_user_audit_logs(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
192
193 Fetches all action logs made by the specified user.
194
195 This command takes the following options:
196
197 :param apiuser: This is filled automatically from the |authtoken|.
198 :type apiuser: AuthUser
199 :param userid: Sets the userid whose list of locked |repos| will be
200 displayed.
201 :type userid: Optional(str or int)
202
203 Example output:
204
205 .. code-block:: bash
206
207 id : <id_given_in_input>
208 result : {
209 [action, action,...]
210 }
211 error : null
212
213
186 get_user_locks
214 get_user_locks
187 --------------
215 --------------
188
216
189 .. py:function:: get_user_locks(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
217 .. py:function:: get_user_locks(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
190
218
191 Displays all repositories locked by the specified user.
219 Displays all repositories locked by the specified user.
192
220
193 * If this command is run by a non-admin user, it returns
221 * If this command is run by a non-admin user, it returns
194 a list of |repos| locked by that user.
222 a list of |repos| locked by that user.
195
223
196 This command takes the following options:
224 This command takes the following options:
197
225
198 :param apiuser: This is filled automatically from the |authtoken|.
226 :param apiuser: This is filled automatically from the |authtoken|.
199 :type apiuser: AuthUser
227 :type apiuser: AuthUser
200 :param userid: Sets the userid whose list of locked |repos| will be
228 :param userid: Sets the userid whose list of locked |repos| will be
201 displayed.
229 displayed.
202 :type userid: Optional(str or int)
230 :type userid: Optional(str or int)
203
231
204 Example output:
232 Example output:
205
233
206 .. code-block:: bash
234 .. code-block:: bash
207
235
208 id : <id_given_in_input>
236 id : <id_given_in_input>
209 result : {
237 result : {
210 [repo_object, repo_object,...]
238 [repo_object, repo_object,...]
211 }
239 }
212 error : null
240 error : null
213
241
214
242
215 get_users
243 get_users
216 ---------
244 ---------
217
245
218 .. py:function:: get_users(apiuser)
246 .. py:function:: get_users(apiuser)
219
247
220 Lists all users in the |RCE| user database.
248 Lists all users in the |RCE| user database.
221
249
222 This command can only be run using an |authtoken| with admin rights to
250 This command can only be run using an |authtoken| with admin rights to
223 the specified repository.
251 the specified repository.
224
252
225 This command takes the following options:
253 This command takes the following options:
226
254
227 :param apiuser: This is filled automatically from the |authtoken|.
255 :param apiuser: This is filled automatically from the |authtoken|.
228 :type apiuser: AuthUser
256 :type apiuser: AuthUser
229
257
230 Example output:
258 Example output:
231
259
232 .. code-block:: bash
260 .. code-block:: bash
233
261
234 id : <id_given_in_input>
262 id : <id_given_in_input>
235 result: [<user_object>, ...]
263 result: [<user_object>, ...]
236 error: null
264 error: null
237
265
238
266
239 update_user
267 update_user
240 -----------
268 -----------
241
269
242 .. py:function:: update_user(apiuser, userid, username=<Optional:None>, email=<Optional:None>, password=<Optional:None>, firstname=<Optional:None>, lastname=<Optional:None>, active=<Optional:None>, admin=<Optional:None>, extern_type=<Optional:None>, extern_name=<Optional:None>)
270 .. py:function:: update_user(apiuser, userid, username=<Optional:None>, email=<Optional:None>, password=<Optional:None>, firstname=<Optional:None>, lastname=<Optional:None>, active=<Optional:None>, admin=<Optional:None>, extern_type=<Optional:None>, extern_name=<Optional:None>)
243
271
244 Updates the details for the specified user, if that user exists.
272 Updates the details for the specified user, if that user exists.
245
273
246 This command can only be run using an |authtoken| with admin rights to
274 This command can only be run using an |authtoken| with admin rights to
247 the specified repository.
275 the specified repository.
248
276
249 This command takes the following options:
277 This command takes the following options:
250
278
251 :param apiuser: This is filled automatically from |authtoken|.
279 :param apiuser: This is filled automatically from |authtoken|.
252 :type apiuser: AuthUser
280 :type apiuser: AuthUser
253 :param userid: Set the ``userid`` to update.
281 :param userid: Set the ``userid`` to update.
254 :type userid: str or int
282 :type userid: str or int
255 :param username: Set the new username.
283 :param username: Set the new username.
256 :type username: str or int
284 :type username: str or int
257 :param email: Set the new email.
285 :param email: Set the new email.
258 :type email: str
286 :type email: str
259 :param password: Set the new password.
287 :param password: Set the new password.
260 :type password: Optional(str)
288 :type password: Optional(str)
261 :param firstname: Set the new first name.
289 :param firstname: Set the new first name.
262 :type firstname: Optional(str)
290 :type firstname: Optional(str)
263 :param lastname: Set the new surname.
291 :param lastname: Set the new surname.
264 :type lastname: Optional(str)
292 :type lastname: Optional(str)
265 :param active: Set the new user as active.
293 :param active: Set the new user as active.
266 :type active: Optional(``True`` | ``False``)
294 :type active: Optional(``True`` | ``False``)
267 :param admin: Give the user admin rights.
295 :param admin: Give the user admin rights.
268 :type admin: Optional(``True`` | ``False``)
296 :type admin: Optional(``True`` | ``False``)
269 :param extern_name: Set the authentication plugin user name.
297 :param extern_name: Set the authentication plugin user name.
270 Using LDAP this is filled with LDAP UID.
298 Using LDAP this is filled with LDAP UID.
271 :type extern_name: Optional(str)
299 :type extern_name: Optional(str)
272 :param extern_type: Set the authentication plugin type.
300 :param extern_type: Set the authentication plugin type.
273 :type extern_type: Optional(str)
301 :type extern_type: Optional(str)
274
302
275
303
276 Example output:
304 Example output:
277
305
278 .. code-block:: bash
306 .. code-block:: bash
279
307
280 id : <id_given_in_input>
308 id : <id_given_in_input>
281 result: {
309 result: {
282 "msg" : "updated user ID:<userid> <username>",
310 "msg" : "updated user ID:<userid> <username>",
283 "user": <user_object>,
311 "user": <user_object>,
284 }
312 }
285 error: null
313 error: null
286
314
287 Example error output:
315 Example error output:
288
316
289 .. code-block:: bash
317 .. code-block:: bash
290
318
291 id : <id_given_in_input>
319 id : <id_given_in_input>
292 result : null
320 result : null
293 error : {
321 error : {
294 "failed to update user `<username>`"
322 "failed to update user `<username>`"
295 }
323 }
296
324
297
325
@@ -1,731 +1,725 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 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, JSONRPCError
24 from rhodecode.api import jsonrpc_method, JSONRPCError
25 from rhodecode.api.utils import (
25 from rhodecode.api.utils import (
26 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
26 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
27 get_pull_request_or_error, get_commit_or_error, get_user_or_error,
27 get_pull_request_or_error, get_commit_or_error, get_user_or_error,
28 validate_repo_permissions, resolve_ref_or_error)
28 validate_repo_permissions, resolve_ref_or_error)
29 from rhodecode.lib.auth import (HasRepoPermissionAnyApi)
29 from rhodecode.lib.auth import (HasRepoPermissionAnyApi)
30 from rhodecode.lib.base import vcs_operation_context
30 from rhodecode.lib.base import vcs_operation_context
31 from rhodecode.lib.utils2 import str2bool
31 from rhodecode.lib.utils2 import str2bool
32 from rhodecode.model.changeset_status import ChangesetStatusModel
32 from rhodecode.model.changeset_status import ChangesetStatusModel
33 from rhodecode.model.comment import CommentsModel
33 from rhodecode.model.comment import CommentsModel
34 from rhodecode.model.db import Session, ChangesetStatus, ChangesetComment
34 from rhodecode.model.db import Session, ChangesetStatus, ChangesetComment
35 from rhodecode.model.pull_request import PullRequestModel, MergeCheck
35 from rhodecode.model.pull_request import PullRequestModel, MergeCheck
36 from rhodecode.model.settings import SettingsModel
36 from rhodecode.model.settings import SettingsModel
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40
40
41 @jsonrpc_method()
41 @jsonrpc_method()
42 def get_pull_request(request, apiuser, repoid, pullrequestid):
42 def get_pull_request(request, apiuser, repoid, pullrequestid):
43 """
43 """
44 Get a pull request based on the given ID.
44 Get a pull request based on the given ID.
45
45
46 :param apiuser: This is filled automatically from the |authtoken|.
46 :param apiuser: This is filled automatically from the |authtoken|.
47 :type apiuser: AuthUser
47 :type apiuser: AuthUser
48 :param repoid: Repository name or repository ID from where the pull
48 :param repoid: Repository name or repository ID from where the pull
49 request was opened.
49 request was opened.
50 :type repoid: str or int
50 :type repoid: str or int
51 :param pullrequestid: ID of the requested pull request.
51 :param pullrequestid: ID of the requested pull request.
52 :type pullrequestid: int
52 :type pullrequestid: int
53
53
54 Example output:
54 Example output:
55
55
56 .. code-block:: bash
56 .. code-block:: bash
57
57
58 "id": <id_given_in_input>,
58 "id": <id_given_in_input>,
59 "result":
59 "result":
60 {
60 {
61 "pull_request_id": "<pull_request_id>",
61 "pull_request_id": "<pull_request_id>",
62 "url": "<url>",
62 "url": "<url>",
63 "title": "<title>",
63 "title": "<title>",
64 "description": "<description>",
64 "description": "<description>",
65 "status" : "<status>",
65 "status" : "<status>",
66 "created_on": "<date_time_created>",
66 "created_on": "<date_time_created>",
67 "updated_on": "<date_time_updated>",
67 "updated_on": "<date_time_updated>",
68 "commit_ids": [
68 "commit_ids": [
69 ...
69 ...
70 "<commit_id>",
70 "<commit_id>",
71 "<commit_id>",
71 "<commit_id>",
72 ...
72 ...
73 ],
73 ],
74 "review_status": "<review_status>",
74 "review_status": "<review_status>",
75 "mergeable": {
75 "mergeable": {
76 "status": "<bool>",
76 "status": "<bool>",
77 "message": "<message>",
77 "message": "<message>",
78 },
78 },
79 "source": {
79 "source": {
80 "clone_url": "<clone_url>",
80 "clone_url": "<clone_url>",
81 "repository": "<repository_name>",
81 "repository": "<repository_name>",
82 "reference":
82 "reference":
83 {
83 {
84 "name": "<name>",
84 "name": "<name>",
85 "type": "<type>",
85 "type": "<type>",
86 "commit_id": "<commit_id>",
86 "commit_id": "<commit_id>",
87 }
87 }
88 },
88 },
89 "target": {
89 "target": {
90 "clone_url": "<clone_url>",
90 "clone_url": "<clone_url>",
91 "repository": "<repository_name>",
91 "repository": "<repository_name>",
92 "reference":
92 "reference":
93 {
93 {
94 "name": "<name>",
94 "name": "<name>",
95 "type": "<type>",
95 "type": "<type>",
96 "commit_id": "<commit_id>",
96 "commit_id": "<commit_id>",
97 }
97 }
98 },
98 },
99 "merge": {
99 "merge": {
100 "clone_url": "<clone_url>",
100 "clone_url": "<clone_url>",
101 "reference":
101 "reference":
102 {
102 {
103 "name": "<name>",
103 "name": "<name>",
104 "type": "<type>",
104 "type": "<type>",
105 "commit_id": "<commit_id>",
105 "commit_id": "<commit_id>",
106 }
106 }
107 },
107 },
108 "author": <user_obj>,
108 "author": <user_obj>,
109 "reviewers": [
109 "reviewers": [
110 ...
110 ...
111 {
111 {
112 "user": "<user_obj>",
112 "user": "<user_obj>",
113 "review_status": "<review_status>",
113 "review_status": "<review_status>",
114 }
114 }
115 ...
115 ...
116 ]
116 ]
117 },
117 },
118 "error": null
118 "error": null
119 """
119 """
120 get_repo_or_error(repoid)
120 get_repo_or_error(repoid)
121 pull_request = get_pull_request_or_error(pullrequestid)
121 pull_request = get_pull_request_or_error(pullrequestid)
122 if not PullRequestModel().check_user_read(
122 if not PullRequestModel().check_user_read(
123 pull_request, apiuser, api=True):
123 pull_request, apiuser, api=True):
124 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
124 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
125 data = pull_request.get_api_data()
125 data = pull_request.get_api_data()
126 return data
126 return data
127
127
128
128
129 @jsonrpc_method()
129 @jsonrpc_method()
130 def get_pull_requests(request, apiuser, repoid, status=Optional('new')):
130 def get_pull_requests(request, apiuser, repoid, status=Optional('new')):
131 """
131 """
132 Get all pull requests from the repository specified in `repoid`.
132 Get all pull requests from the repository specified in `repoid`.
133
133
134 :param apiuser: This is filled automatically from the |authtoken|.
134 :param apiuser: This is filled automatically from the |authtoken|.
135 :type apiuser: AuthUser
135 :type apiuser: AuthUser
136 :param repoid: Repository name or repository ID.
136 :param repoid: Repository name or repository ID.
137 :type repoid: str or int
137 :type repoid: str or int
138 :param status: Only return pull requests with the specified status.
138 :param status: Only return pull requests with the specified status.
139 Valid options are.
139 Valid options are.
140 * ``new`` (default)
140 * ``new`` (default)
141 * ``open``
141 * ``open``
142 * ``closed``
142 * ``closed``
143 :type status: str
143 :type status: str
144
144
145 Example output:
145 Example output:
146
146
147 .. code-block:: bash
147 .. code-block:: bash
148
148
149 "id": <id_given_in_input>,
149 "id": <id_given_in_input>,
150 "result":
150 "result":
151 [
151 [
152 ...
152 ...
153 {
153 {
154 "pull_request_id": "<pull_request_id>",
154 "pull_request_id": "<pull_request_id>",
155 "url": "<url>",
155 "url": "<url>",
156 "title" : "<title>",
156 "title" : "<title>",
157 "description": "<description>",
157 "description": "<description>",
158 "status": "<status>",
158 "status": "<status>",
159 "created_on": "<date_time_created>",
159 "created_on": "<date_time_created>",
160 "updated_on": "<date_time_updated>",
160 "updated_on": "<date_time_updated>",
161 "commit_ids": [
161 "commit_ids": [
162 ...
162 ...
163 "<commit_id>",
163 "<commit_id>",
164 "<commit_id>",
164 "<commit_id>",
165 ...
165 ...
166 ],
166 ],
167 "review_status": "<review_status>",
167 "review_status": "<review_status>",
168 "mergeable": {
168 "mergeable": {
169 "status": "<bool>",
169 "status": "<bool>",
170 "message: "<message>",
170 "message: "<message>",
171 },
171 },
172 "source": {
172 "source": {
173 "clone_url": "<clone_url>",
173 "clone_url": "<clone_url>",
174 "reference":
174 "reference":
175 {
175 {
176 "name": "<name>",
176 "name": "<name>",
177 "type": "<type>",
177 "type": "<type>",
178 "commit_id": "<commit_id>",
178 "commit_id": "<commit_id>",
179 }
179 }
180 },
180 },
181 "target": {
181 "target": {
182 "clone_url": "<clone_url>",
182 "clone_url": "<clone_url>",
183 "reference":
183 "reference":
184 {
184 {
185 "name": "<name>",
185 "name": "<name>",
186 "type": "<type>",
186 "type": "<type>",
187 "commit_id": "<commit_id>",
187 "commit_id": "<commit_id>",
188 }
188 }
189 },
189 },
190 "merge": {
190 "merge": {
191 "clone_url": "<clone_url>",
191 "clone_url": "<clone_url>",
192 "reference":
192 "reference":
193 {
193 {
194 "name": "<name>",
194 "name": "<name>",
195 "type": "<type>",
195 "type": "<type>",
196 "commit_id": "<commit_id>",
196 "commit_id": "<commit_id>",
197 }
197 }
198 },
198 },
199 "author": <user_obj>,
199 "author": <user_obj>,
200 "reviewers": [
200 "reviewers": [
201 ...
201 ...
202 {
202 {
203 "user": "<user_obj>",
203 "user": "<user_obj>",
204 "review_status": "<review_status>",
204 "review_status": "<review_status>",
205 }
205 }
206 ...
206 ...
207 ]
207 ]
208 }
208 }
209 ...
209 ...
210 ],
210 ],
211 "error": null
211 "error": null
212
212
213 """
213 """
214 repo = get_repo_or_error(repoid)
214 repo = get_repo_or_error(repoid)
215 if not has_superadmin_permission(apiuser):
215 if not has_superadmin_permission(apiuser):
216 _perms = (
216 _perms = (
217 'repository.admin', 'repository.write', 'repository.read',)
217 'repository.admin', 'repository.write', 'repository.read',)
218 validate_repo_permissions(apiuser, repoid, repo, _perms)
218 validate_repo_permissions(apiuser, repoid, repo, _perms)
219
219
220 status = Optional.extract(status)
220 status = Optional.extract(status)
221 pull_requests = PullRequestModel().get_all(repo, statuses=[status])
221 pull_requests = PullRequestModel().get_all(repo, statuses=[status])
222 data = [pr.get_api_data() for pr in pull_requests]
222 data = [pr.get_api_data() for pr in pull_requests]
223 return data
223 return data
224
224
225
225
226 @jsonrpc_method()
226 @jsonrpc_method()
227 def merge_pull_request(request, apiuser, repoid, pullrequestid,
227 def merge_pull_request(request, apiuser, repoid, pullrequestid,
228 userid=Optional(OAttr('apiuser'))):
228 userid=Optional(OAttr('apiuser'))):
229 """
229 """
230 Merge the pull request specified by `pullrequestid` into its target
230 Merge the pull request specified by `pullrequestid` into its target
231 repository.
231 repository.
232
232
233 :param apiuser: This is filled automatically from the |authtoken|.
233 :param apiuser: This is filled automatically from the |authtoken|.
234 :type apiuser: AuthUser
234 :type apiuser: AuthUser
235 :param repoid: The Repository name or repository ID of the
235 :param repoid: The Repository name or repository ID of the
236 target repository to which the |pr| is to be merged.
236 target repository to which the |pr| is to be merged.
237 :type repoid: str or int
237 :type repoid: str or int
238 :param pullrequestid: ID of the pull request which shall be merged.
238 :param pullrequestid: ID of the pull request which shall be merged.
239 :type pullrequestid: int
239 :type pullrequestid: int
240 :param userid: Merge the pull request as this user.
240 :param userid: Merge the pull request as this user.
241 :type userid: Optional(str or int)
241 :type userid: Optional(str or int)
242
242
243 Example output:
243 Example output:
244
244
245 .. code-block:: bash
245 .. code-block:: bash
246
246
247 "id": <id_given_in_input>,
247 "id": <id_given_in_input>,
248 "result":
248 "result": {
249 {
250 "executed": "<bool>",
249 "executed": "<bool>",
251 "failure_reason": "<int>",
250 "failure_reason": "<int>",
252 "merge_commit_id": "<merge_commit_id>",
251 "merge_commit_id": "<merge_commit_id>",
253 "possible": "<bool>",
252 "possible": "<bool>",
254 "merge_ref": {
253 "merge_ref": {
255 "commit_id": "<commit_id>",
254 "commit_id": "<commit_id>",
256 "type": "<type>",
255 "type": "<type>",
257 "name": "<name>"
256 "name": "<name>"
258 }
257 }
259 },
258 },
260 "error": null
259 "error": null
261
262 """
260 """
263 repo = get_repo_or_error(repoid)
261 repo = get_repo_or_error(repoid)
264 if not isinstance(userid, Optional):
262 if not isinstance(userid, Optional):
265 if (has_superadmin_permission(apiuser) or
263 if (has_superadmin_permission(apiuser) or
266 HasRepoPermissionAnyApi('repository.admin')(
264 HasRepoPermissionAnyApi('repository.admin')(
267 user=apiuser, repo_name=repo.repo_name)):
265 user=apiuser, repo_name=repo.repo_name)):
268 apiuser = get_user_or_error(userid)
266 apiuser = get_user_or_error(userid)
269 else:
267 else:
270 raise JSONRPCError('userid is not the same as your user')
268 raise JSONRPCError('userid is not the same as your user')
271
269
272 pull_request = get_pull_request_or_error(pullrequestid)
270 pull_request = get_pull_request_or_error(pullrequestid)
273
271
274 check = MergeCheck.validate(pull_request, user=apiuser)
272 check = MergeCheck.validate(pull_request, user=apiuser)
275 merge_possible = not check.failed
273 merge_possible = not check.failed
276
274
277 if not merge_possible:
275 if not merge_possible:
278 reasons = ','.join([msg for _e, msg in check.errors])
276 reasons = ','.join([msg for _e, msg in check.errors])
279 raise JSONRPCError(
277 raise JSONRPCError(
280 'merge not possible for following reasons: {}'.format(reasons))
278 'merge not possible for following reasons: {}'.format(reasons))
281
279
282 target_repo = pull_request.target_repo
280 target_repo = pull_request.target_repo
283 extras = vcs_operation_context(
281 extras = vcs_operation_context(
284 request.environ, repo_name=target_repo.repo_name,
282 request.environ, repo_name=target_repo.repo_name,
285 username=apiuser.username, action='push',
283 username=apiuser.username, action='push',
286 scm=target_repo.repo_type)
284 scm=target_repo.repo_type)
287 merge_response = PullRequestModel().merge(
285 merge_response = PullRequestModel().merge(
288 pull_request, apiuser, extras=extras)
286 pull_request, apiuser, extras=extras)
289 if merge_response.executed:
287 if merge_response.executed:
290 PullRequestModel().close_pull_request(
288 PullRequestModel().close_pull_request(
291 pull_request.pull_request_id, apiuser)
289 pull_request.pull_request_id, apiuser)
292
290
293 Session().commit()
291 Session().commit()
294
292
295 # In previous versions the merge response directly contained the merge
293 # In previous versions the merge response directly contained the merge
296 # commit id. It is now contained in the merge reference object. To be
294 # commit id. It is now contained in the merge reference object. To be
297 # backwards compatible we have to extract it again.
295 # backwards compatible we have to extract it again.
298 merge_response = merge_response._asdict()
296 merge_response = merge_response._asdict()
299 merge_response['merge_commit_id'] = merge_response['merge_ref'].commit_id
297 merge_response['merge_commit_id'] = merge_response['merge_ref'].commit_id
300
298
301 return merge_response
299 return merge_response
302
300
303
301
304 @jsonrpc_method()
302 @jsonrpc_method()
305 def close_pull_request(request, apiuser, repoid, pullrequestid,
303 def close_pull_request(request, apiuser, repoid, pullrequestid,
306 userid=Optional(OAttr('apiuser'))):
304 userid=Optional(OAttr('apiuser'))):
307 """
305 """
308 Close the pull request specified by `pullrequestid`.
306 Close the pull request specified by `pullrequestid`.
309
307
310 :param apiuser: This is filled automatically from the |authtoken|.
308 :param apiuser: This is filled automatically from the |authtoken|.
311 :type apiuser: AuthUser
309 :type apiuser: AuthUser
312 :param repoid: Repository name or repository ID to which the pull
310 :param repoid: Repository name or repository ID to which the pull
313 request belongs.
311 request belongs.
314 :type repoid: str or int
312 :type repoid: str or int
315 :param pullrequestid: ID of the pull request to be closed.
313 :param pullrequestid: ID of the pull request to be closed.
316 :type pullrequestid: int
314 :type pullrequestid: int
317 :param userid: Close the pull request as this user.
315 :param userid: Close the pull request as this user.
318 :type userid: Optional(str or int)
316 :type userid: Optional(str or int)
319
317
320 Example output:
318 Example output:
321
319
322 .. code-block:: bash
320 .. code-block:: bash
323
321
324 "id": <id_given_in_input>,
322 "id": <id_given_in_input>,
325 "result":
323 "result": {
326 {
327 "pull_request_id": "<int>",
324 "pull_request_id": "<int>",
328 "closed": "<bool>"
325 "closed": "<bool>"
329 },
326 },
330 "error": null
327 "error": null
331
328
332 """
329 """
333 repo = get_repo_or_error(repoid)
330 repo = get_repo_or_error(repoid)
334 if not isinstance(userid, Optional):
331 if not isinstance(userid, Optional):
335 if (has_superadmin_permission(apiuser) or
332 if (has_superadmin_permission(apiuser) or
336 HasRepoPermissionAnyApi('repository.admin')(
333 HasRepoPermissionAnyApi('repository.admin')(
337 user=apiuser, repo_name=repo.repo_name)):
334 user=apiuser, repo_name=repo.repo_name)):
338 apiuser = get_user_or_error(userid)
335 apiuser = get_user_or_error(userid)
339 else:
336 else:
340 raise JSONRPCError('userid is not the same as your user')
337 raise JSONRPCError('userid is not the same as your user')
341
338
342 pull_request = get_pull_request_or_error(pullrequestid)
339 pull_request = get_pull_request_or_error(pullrequestid)
343 if not PullRequestModel().check_user_update(
340 if not PullRequestModel().check_user_update(
344 pull_request, apiuser, api=True):
341 pull_request, apiuser, api=True):
345 raise JSONRPCError(
342 raise JSONRPCError(
346 'pull request `%s` close failed, no permission to close.' % (
343 'pull request `%s` close failed, no permission to close.' % (
347 pullrequestid,))
344 pullrequestid,))
348 if pull_request.is_closed():
345 if pull_request.is_closed():
349 raise JSONRPCError(
346 raise JSONRPCError(
350 'pull request `%s` is already closed' % (pullrequestid,))
347 'pull request `%s` is already closed' % (pullrequestid,))
351
348
352 PullRequestModel().close_pull_request(
349 PullRequestModel().close_pull_request(
353 pull_request.pull_request_id, apiuser)
350 pull_request.pull_request_id, apiuser)
354 Session().commit()
351 Session().commit()
355 data = {
352 data = {
356 'pull_request_id': pull_request.pull_request_id,
353 'pull_request_id': pull_request.pull_request_id,
357 'closed': True,
354 'closed': True,
358 }
355 }
359 return data
356 return data
360
357
361
358
362 @jsonrpc_method()
359 @jsonrpc_method()
363 def comment_pull_request(
360 def comment_pull_request(
364 request, apiuser, repoid, pullrequestid, message=Optional(None),
361 request, apiuser, repoid, pullrequestid, message=Optional(None),
365 commit_id=Optional(None), status=Optional(None),
362 commit_id=Optional(None), status=Optional(None),
366 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
363 comment_type=Optional(ChangesetComment.COMMENT_TYPE_NOTE),
367 resolves_comment_id=Optional(None),
364 resolves_comment_id=Optional(None),
368 userid=Optional(OAttr('apiuser'))):
365 userid=Optional(OAttr('apiuser'))):
369 """
366 """
370 Comment on the pull request specified with the `pullrequestid`,
367 Comment on the pull request specified with the `pullrequestid`,
371 in the |repo| specified by the `repoid`, and optionally change the
368 in the |repo| specified by the `repoid`, and optionally change the
372 review status.
369 review status.
373
370
374 :param apiuser: This is filled automatically from the |authtoken|.
371 :param apiuser: This is filled automatically from the |authtoken|.
375 :type apiuser: AuthUser
372 :type apiuser: AuthUser
376 :param repoid: The repository name or repository ID.
373 :param repoid: The repository name or repository ID.
377 :type repoid: str or int
374 :type repoid: str or int
378 :param pullrequestid: The pull request ID.
375 :param pullrequestid: The pull request ID.
379 :type pullrequestid: int
376 :type pullrequestid: int
380 :param commit_id: Specify the commit_id for which to set a comment. If
377 :param commit_id: Specify the commit_id for which to set a comment. If
381 given commit_id is different than latest in the PR status
378 given commit_id is different than latest in the PR status
382 change won't be performed.
379 change won't be performed.
383 :type commit_id: str
380 :type commit_id: str
384 :param message: The text content of the comment.
381 :param message: The text content of the comment.
385 :type message: str
382 :type message: str
386 :param status: (**Optional**) Set the approval status of the pull
383 :param status: (**Optional**) Set the approval status of the pull
387 request. One of: 'not_reviewed', 'approved', 'rejected',
384 request. One of: 'not_reviewed', 'approved', 'rejected',
388 'under_review'
385 'under_review'
389 :type status: str
386 :type status: str
390 :param comment_type: Comment type, one of: 'note', 'todo'
387 :param comment_type: Comment type, one of: 'note', 'todo'
391 :type comment_type: Optional(str), default: 'note'
388 :type comment_type: Optional(str), default: 'note'
392 :param userid: Comment on the pull request as this user
389 :param userid: Comment on the pull request as this user
393 :type userid: Optional(str or int)
390 :type userid: Optional(str or int)
394
391
395 Example output:
392 Example output:
396
393
397 .. code-block:: bash
394 .. code-block:: bash
398
395
399 id : <id_given_in_input>
396 id : <id_given_in_input>
400 result :
397 result : {
401 {
402 "pull_request_id": "<Integer>",
398 "pull_request_id": "<Integer>",
403 "comment_id": "<Integer>",
399 "comment_id": "<Integer>",
404 "status": {"given": <given_status>,
400 "status": {"given": <given_status>,
405 "was_changed": <bool status_was_actually_changed> },
401 "was_changed": <bool status_was_actually_changed> },
406 }
402 },
407 error : null
403 error : null
408 """
404 """
409 repo = get_repo_or_error(repoid)
405 repo = get_repo_or_error(repoid)
410 if not isinstance(userid, Optional):
406 if not isinstance(userid, Optional):
411 if (has_superadmin_permission(apiuser) or
407 if (has_superadmin_permission(apiuser) or
412 HasRepoPermissionAnyApi('repository.admin')(
408 HasRepoPermissionAnyApi('repository.admin')(
413 user=apiuser, repo_name=repo.repo_name)):
409 user=apiuser, repo_name=repo.repo_name)):
414 apiuser = get_user_or_error(userid)
410 apiuser = get_user_or_error(userid)
415 else:
411 else:
416 raise JSONRPCError('userid is not the same as your user')
412 raise JSONRPCError('userid is not the same as your user')
417
413
418 pull_request = get_pull_request_or_error(pullrequestid)
414 pull_request = get_pull_request_or_error(pullrequestid)
419 if not PullRequestModel().check_user_read(
415 if not PullRequestModel().check_user_read(
420 pull_request, apiuser, api=True):
416 pull_request, apiuser, api=True):
421 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
417 raise JSONRPCError('repository `%s` does not exist' % (repoid,))
422 message = Optional.extract(message)
418 message = Optional.extract(message)
423 status = Optional.extract(status)
419 status = Optional.extract(status)
424 commit_id = Optional.extract(commit_id)
420 commit_id = Optional.extract(commit_id)
425 comment_type = Optional.extract(comment_type)
421 comment_type = Optional.extract(comment_type)
426 resolves_comment_id = Optional.extract(resolves_comment_id)
422 resolves_comment_id = Optional.extract(resolves_comment_id)
427
423
428 if not message and not status:
424 if not message and not status:
429 raise JSONRPCError(
425 raise JSONRPCError(
430 'Both message and status parameters are missing. '
426 'Both message and status parameters are missing. '
431 'At least one is required.')
427 'At least one is required.')
432
428
433 if (status not in (st[0] for st in ChangesetStatus.STATUSES) and
429 if (status not in (st[0] for st in ChangesetStatus.STATUSES) and
434 status is not None):
430 status is not None):
435 raise JSONRPCError('Unknown comment status: `%s`' % status)
431 raise JSONRPCError('Unknown comment status: `%s`' % status)
436
432
437 if commit_id and commit_id not in pull_request.revisions:
433 if commit_id and commit_id not in pull_request.revisions:
438 raise JSONRPCError(
434 raise JSONRPCError(
439 'Invalid commit_id `%s` for this pull request.' % commit_id)
435 'Invalid commit_id `%s` for this pull request.' % commit_id)
440
436
441 allowed_to_change_status = PullRequestModel().check_user_change_status(
437 allowed_to_change_status = PullRequestModel().check_user_change_status(
442 pull_request, apiuser)
438 pull_request, apiuser)
443
439
444 # if commit_id is passed re-validated if user is allowed to change status
440 # if commit_id is passed re-validated if user is allowed to change status
445 # based on latest commit_id from the PR
441 # based on latest commit_id from the PR
446 if commit_id:
442 if commit_id:
447 commit_idx = pull_request.revisions.index(commit_id)
443 commit_idx = pull_request.revisions.index(commit_id)
448 if commit_idx != 0:
444 if commit_idx != 0:
449 allowed_to_change_status = False
445 allowed_to_change_status = False
450
446
451 if resolves_comment_id:
447 if resolves_comment_id:
452 comment = ChangesetComment.get(resolves_comment_id)
448 comment = ChangesetComment.get(resolves_comment_id)
453 if not comment:
449 if not comment:
454 raise JSONRPCError(
450 raise JSONRPCError(
455 'Invalid resolves_comment_id `%s` for this pull request.'
451 'Invalid resolves_comment_id `%s` for this pull request.'
456 % resolves_comment_id)
452 % resolves_comment_id)
457 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
453 if comment.comment_type != ChangesetComment.COMMENT_TYPE_TODO:
458 raise JSONRPCError(
454 raise JSONRPCError(
459 'Comment `%s` is wrong type for setting status to resolved.'
455 'Comment `%s` is wrong type for setting status to resolved.'
460 % resolves_comment_id)
456 % resolves_comment_id)
461
457
462 text = message
458 text = message
463 status_label = ChangesetStatus.get_status_lbl(status)
459 status_label = ChangesetStatus.get_status_lbl(status)
464 if status and allowed_to_change_status:
460 if status and allowed_to_change_status:
465 st_message = ('Status change %(transition_icon)s %(status)s'
461 st_message = ('Status change %(transition_icon)s %(status)s'
466 % {'transition_icon': '>', 'status': status_label})
462 % {'transition_icon': '>', 'status': status_label})
467 text = message or st_message
463 text = message or st_message
468
464
469 rc_config = SettingsModel().get_all_settings()
465 rc_config = SettingsModel().get_all_settings()
470 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
466 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
471
467
472 status_change = status and allowed_to_change_status
468 status_change = status and allowed_to_change_status
473 comment = CommentsModel().create(
469 comment = CommentsModel().create(
474 text=text,
470 text=text,
475 repo=pull_request.target_repo.repo_id,
471 repo=pull_request.target_repo.repo_id,
476 user=apiuser.user_id,
472 user=apiuser.user_id,
477 pull_request=pull_request.pull_request_id,
473 pull_request=pull_request.pull_request_id,
478 f_path=None,
474 f_path=None,
479 line_no=None,
475 line_no=None,
480 status_change=(status_label if status_change else None),
476 status_change=(status_label if status_change else None),
481 status_change_type=(status if status_change else None),
477 status_change_type=(status if status_change else None),
482 closing_pr=False,
478 closing_pr=False,
483 renderer=renderer,
479 renderer=renderer,
484 comment_type=comment_type,
480 comment_type=comment_type,
485 resolves_comment_id=resolves_comment_id
481 resolves_comment_id=resolves_comment_id
486 )
482 )
487
483
488 if allowed_to_change_status and status:
484 if allowed_to_change_status and status:
489 ChangesetStatusModel().set_status(
485 ChangesetStatusModel().set_status(
490 pull_request.target_repo.repo_id,
486 pull_request.target_repo.repo_id,
491 status,
487 status,
492 apiuser.user_id,
488 apiuser.user_id,
493 comment,
489 comment,
494 pull_request=pull_request.pull_request_id
490 pull_request=pull_request.pull_request_id
495 )
491 )
496 Session().flush()
492 Session().flush()
497
493
498 Session().commit()
494 Session().commit()
499 data = {
495 data = {
500 'pull_request_id': pull_request.pull_request_id,
496 'pull_request_id': pull_request.pull_request_id,
501 'comment_id': comment.comment_id if comment else None,
497 'comment_id': comment.comment_id if comment else None,
502 'status': {'given': status, 'was_changed': status_change},
498 'status': {'given': status, 'was_changed': status_change},
503 }
499 }
504 return data
500 return data
505
501
506
502
507 @jsonrpc_method()
503 @jsonrpc_method()
508 def create_pull_request(
504 def create_pull_request(
509 request, apiuser, source_repo, target_repo, source_ref, target_ref,
505 request, apiuser, source_repo, target_repo, source_ref, target_ref,
510 title, description=Optional(''), reviewers=Optional(None)):
506 title, description=Optional(''), reviewers=Optional(None)):
511 """
507 """
512 Creates a new pull request.
508 Creates a new pull request.
513
509
514 Accepts refs in the following formats:
510 Accepts refs in the following formats:
515
511
516 * branch:<branch_name>:<sha>
512 * branch:<branch_name>:<sha>
517 * branch:<branch_name>
513 * branch:<branch_name>
518 * bookmark:<bookmark_name>:<sha> (Mercurial only)
514 * bookmark:<bookmark_name>:<sha> (Mercurial only)
519 * bookmark:<bookmark_name> (Mercurial only)
515 * bookmark:<bookmark_name> (Mercurial only)
520
516
521 :param apiuser: This is filled automatically from the |authtoken|.
517 :param apiuser: This is filled automatically from the |authtoken|.
522 :type apiuser: AuthUser
518 :type apiuser: AuthUser
523 :param source_repo: Set the source repository name.
519 :param source_repo: Set the source repository name.
524 :type source_repo: str
520 :type source_repo: str
525 :param target_repo: Set the target repository name.
521 :param target_repo: Set the target repository name.
526 :type target_repo: str
522 :type target_repo: str
527 :param source_ref: Set the source ref name.
523 :param source_ref: Set the source ref name.
528 :type source_ref: str
524 :type source_ref: str
529 :param target_ref: Set the target ref name.
525 :param target_ref: Set the target ref name.
530 :type target_ref: str
526 :type target_ref: str
531 :param title: Set the pull request title.
527 :param title: Set the pull request title.
532 :type title: str
528 :type title: str
533 :param description: Set the pull request description.
529 :param description: Set the pull request description.
534 :type description: Optional(str)
530 :type description: Optional(str)
535 :param reviewers: Set the new pull request reviewers list.
531 :param reviewers: Set the new pull request reviewers list.
536 :type reviewers: Optional(list)
532 :type reviewers: Optional(list)
537 Accepts username strings or objects of the format:
533 Accepts username strings or objects of the format:
538 {
534
539 'username': 'nick', 'reasons': ['original author']
535 {'username': 'nick', 'reasons': ['original author']}
540 }
541 """
536 """
542
537
543 source = get_repo_or_error(source_repo)
538 source = get_repo_or_error(source_repo)
544 target = get_repo_or_error(target_repo)
539 target = get_repo_or_error(target_repo)
545 if not has_superadmin_permission(apiuser):
540 if not has_superadmin_permission(apiuser):
546 _perms = ('repository.admin', 'repository.write', 'repository.read',)
541 _perms = ('repository.admin', 'repository.write', 'repository.read',)
547 validate_repo_permissions(apiuser, source_repo, source, _perms)
542 validate_repo_permissions(apiuser, source_repo, source, _perms)
548
543
549 full_source_ref = resolve_ref_or_error(source_ref, source)
544 full_source_ref = resolve_ref_or_error(source_ref, source)
550 full_target_ref = resolve_ref_or_error(target_ref, target)
545 full_target_ref = resolve_ref_or_error(target_ref, target)
551 source_commit = get_commit_or_error(full_source_ref, source)
546 source_commit = get_commit_or_error(full_source_ref, source)
552 target_commit = get_commit_or_error(full_target_ref, target)
547 target_commit = get_commit_or_error(full_target_ref, target)
553 source_scm = source.scm_instance()
548 source_scm = source.scm_instance()
554 target_scm = target.scm_instance()
549 target_scm = target.scm_instance()
555
550
556 commit_ranges = target_scm.compare(
551 commit_ranges = target_scm.compare(
557 target_commit.raw_id, source_commit.raw_id, source_scm,
552 target_commit.raw_id, source_commit.raw_id, source_scm,
558 merge=True, pre_load=[])
553 merge=True, pre_load=[])
559
554
560 ancestor = target_scm.get_common_ancestor(
555 ancestor = target_scm.get_common_ancestor(
561 target_commit.raw_id, source_commit.raw_id, source_scm)
556 target_commit.raw_id, source_commit.raw_id, source_scm)
562
557
563 if not commit_ranges:
558 if not commit_ranges:
564 raise JSONRPCError('no commits found')
559 raise JSONRPCError('no commits found')
565
560
566 if not ancestor:
561 if not ancestor:
567 raise JSONRPCError('no common ancestor found')
562 raise JSONRPCError('no common ancestor found')
568
563
569 reviewer_objects = Optional.extract(reviewers) or []
564 reviewer_objects = Optional.extract(reviewers) or []
570 if not isinstance(reviewer_objects, list):
565 if not isinstance(reviewer_objects, list):
571 raise JSONRPCError('reviewers should be specified as a list')
566 raise JSONRPCError('reviewers should be specified as a list')
572
567
573 reviewers_reasons = []
568 reviewers_reasons = []
574 for reviewer_object in reviewer_objects:
569 for reviewer_object in reviewer_objects:
575 reviewer_reasons = []
570 reviewer_reasons = []
576 if isinstance(reviewer_object, (basestring, int)):
571 if isinstance(reviewer_object, (basestring, int)):
577 reviewer_username = reviewer_object
572 reviewer_username = reviewer_object
578 else:
573 else:
579 reviewer_username = reviewer_object['username']
574 reviewer_username = reviewer_object['username']
580 reviewer_reasons = reviewer_object.get('reasons', [])
575 reviewer_reasons = reviewer_object.get('reasons', [])
581
576
582 user = get_user_or_error(reviewer_username)
577 user = get_user_or_error(reviewer_username)
583 reviewers_reasons.append((user.user_id, reviewer_reasons))
578 reviewers_reasons.append((user.user_id, reviewer_reasons))
584
579
585 pull_request_model = PullRequestModel()
580 pull_request_model = PullRequestModel()
586 pull_request = pull_request_model.create(
581 pull_request = pull_request_model.create(
587 created_by=apiuser.user_id,
582 created_by=apiuser.user_id,
588 source_repo=source_repo,
583 source_repo=source_repo,
589 source_ref=full_source_ref,
584 source_ref=full_source_ref,
590 target_repo=target_repo,
585 target_repo=target_repo,
591 target_ref=full_target_ref,
586 target_ref=full_target_ref,
592 revisions=reversed(
587 revisions=reversed(
593 [commit.raw_id for commit in reversed(commit_ranges)]),
588 [commit.raw_id for commit in reversed(commit_ranges)]),
594 reviewers=reviewers_reasons,
589 reviewers=reviewers_reasons,
595 title=title,
590 title=title,
596 description=Optional.extract(description)
591 description=Optional.extract(description)
597 )
592 )
598
593
599 Session().commit()
594 Session().commit()
600 data = {
595 data = {
601 'msg': 'Created new pull request `{}`'.format(title),
596 'msg': 'Created new pull request `{}`'.format(title),
602 'pull_request_id': pull_request.pull_request_id,
597 'pull_request_id': pull_request.pull_request_id,
603 }
598 }
604 return data
599 return data
605
600
606
601
607 @jsonrpc_method()
602 @jsonrpc_method()
608 def update_pull_request(
603 def update_pull_request(
609 request, apiuser, repoid, pullrequestid, title=Optional(''),
604 request, apiuser, repoid, pullrequestid, title=Optional(''),
610 description=Optional(''), reviewers=Optional(None),
605 description=Optional(''), reviewers=Optional(None),
611 update_commits=Optional(None), close_pull_request=Optional(None)):
606 update_commits=Optional(None), close_pull_request=Optional(None)):
612 """
607 """
613 Updates a pull request.
608 Updates a pull request.
614
609
615 :param apiuser: This is filled automatically from the |authtoken|.
610 :param apiuser: This is filled automatically from the |authtoken|.
616 :type apiuser: AuthUser
611 :type apiuser: AuthUser
617 :param repoid: The repository name or repository ID.
612 :param repoid: The repository name or repository ID.
618 :type repoid: str or int
613 :type repoid: str or int
619 :param pullrequestid: The pull request ID.
614 :param pullrequestid: The pull request ID.
620 :type pullrequestid: int
615 :type pullrequestid: int
621 :param title: Set the pull request title.
616 :param title: Set the pull request title.
622 :type title: str
617 :type title: str
623 :param description: Update pull request description.
618 :param description: Update pull request description.
624 :type description: Optional(str)
619 :type description: Optional(str)
625 :param reviewers: Update pull request reviewers list with new value.
620 :param reviewers: Update pull request reviewers list with new value.
626 :type reviewers: Optional(list)
621 :type reviewers: Optional(list)
627 :param update_commits: Trigger update of commits for this pull request
622 :param update_commits: Trigger update of commits for this pull request
628 :type: update_commits: Optional(bool)
623 :type: update_commits: Optional(bool)
629 :param close_pull_request: Close this pull request with rejected state
624 :param close_pull_request: Close this pull request with rejected state
630 :type: close_pull_request: Optional(bool)
625 :type: close_pull_request: Optional(bool)
631
626
632 Example output:
627 Example output:
633
628
634 .. code-block:: bash
629 .. code-block:: bash
635
630
636 id : <id_given_in_input>
631 id : <id_given_in_input>
637 result :
632 result : {
638 {
639 "msg": "Updated pull request `63`",
633 "msg": "Updated pull request `63`",
640 "pull_request": <pull_request_object>,
634 "pull_request": <pull_request_object>,
641 "updated_reviewers": {
635 "updated_reviewers": {
642 "added": [
636 "added": [
643 "username"
637 "username"
644 ],
638 ],
645 "removed": []
639 "removed": []
646 },
640 },
647 "updated_commits": {
641 "updated_commits": {
648 "added": [
642 "added": [
649 "<sha1_hash>"
643 "<sha1_hash>"
650 ],
644 ],
651 "common": [
645 "common": [
652 "<sha1_hash>",
646 "<sha1_hash>",
653 "<sha1_hash>",
647 "<sha1_hash>",
654 ],
648 ],
655 "removed": []
649 "removed": []
656 }
650 }
657 }
651 }
658 error : null
652 error : null
659 """
653 """
660
654
661 repo = get_repo_or_error(repoid)
655 repo = get_repo_or_error(repoid)
662 pull_request = get_pull_request_or_error(pullrequestid)
656 pull_request = get_pull_request_or_error(pullrequestid)
663 if not PullRequestModel().check_user_update(
657 if not PullRequestModel().check_user_update(
664 pull_request, apiuser, api=True):
658 pull_request, apiuser, api=True):
665 raise JSONRPCError(
659 raise JSONRPCError(
666 'pull request `%s` update failed, no permission to update.' % (
660 'pull request `%s` update failed, no permission to update.' % (
667 pullrequestid,))
661 pullrequestid,))
668 if pull_request.is_closed():
662 if pull_request.is_closed():
669 raise JSONRPCError(
663 raise JSONRPCError(
670 'pull request `%s` update failed, pull request is closed' % (
664 'pull request `%s` update failed, pull request is closed' % (
671 pullrequestid,))
665 pullrequestid,))
672
666
673 reviewer_objects = Optional.extract(reviewers) or []
667 reviewer_objects = Optional.extract(reviewers) or []
674 if not isinstance(reviewer_objects, list):
668 if not isinstance(reviewer_objects, list):
675 raise JSONRPCError('reviewers should be specified as a list')
669 raise JSONRPCError('reviewers should be specified as a list')
676
670
677 reviewers_reasons = []
671 reviewers_reasons = []
678 reviewer_ids = set()
672 reviewer_ids = set()
679 for reviewer_object in reviewer_objects:
673 for reviewer_object in reviewer_objects:
680 reviewer_reasons = []
674 reviewer_reasons = []
681 if isinstance(reviewer_object, (int, basestring)):
675 if isinstance(reviewer_object, (int, basestring)):
682 reviewer_username = reviewer_object
676 reviewer_username = reviewer_object
683 else:
677 else:
684 reviewer_username = reviewer_object['username']
678 reviewer_username = reviewer_object['username']
685 reviewer_reasons = reviewer_object.get('reasons', [])
679 reviewer_reasons = reviewer_object.get('reasons', [])
686
680
687 user = get_user_or_error(reviewer_username)
681 user = get_user_or_error(reviewer_username)
688 reviewer_ids.add(user.user_id)
682 reviewer_ids.add(user.user_id)
689 reviewers_reasons.append((user.user_id, reviewer_reasons))
683 reviewers_reasons.append((user.user_id, reviewer_reasons))
690
684
691 title = Optional.extract(title)
685 title = Optional.extract(title)
692 description = Optional.extract(description)
686 description = Optional.extract(description)
693 if title or description:
687 if title or description:
694 PullRequestModel().edit(
688 PullRequestModel().edit(
695 pull_request, title or pull_request.title,
689 pull_request, title or pull_request.title,
696 description or pull_request.description)
690 description or pull_request.description)
697 Session().commit()
691 Session().commit()
698
692
699 commit_changes = {"added": [], "common": [], "removed": []}
693 commit_changes = {"added": [], "common": [], "removed": []}
700 if str2bool(Optional.extract(update_commits)):
694 if str2bool(Optional.extract(update_commits)):
701 if PullRequestModel().has_valid_update_type(pull_request):
695 if PullRequestModel().has_valid_update_type(pull_request):
702 update_response = PullRequestModel().update_commits(
696 update_response = PullRequestModel().update_commits(
703 pull_request)
697 pull_request)
704 commit_changes = update_response.changes or commit_changes
698 commit_changes = update_response.changes or commit_changes
705 Session().commit()
699 Session().commit()
706
700
707 reviewers_changes = {"added": [], "removed": []}
701 reviewers_changes = {"added": [], "removed": []}
708 if reviewer_ids:
702 if reviewer_ids:
709 added_reviewers, removed_reviewers = \
703 added_reviewers, removed_reviewers = \
710 PullRequestModel().update_reviewers(pull_request, reviewers_reasons)
704 PullRequestModel().update_reviewers(pull_request, reviewers_reasons)
711
705
712 reviewers_changes['added'] = sorted(
706 reviewers_changes['added'] = sorted(
713 [get_user_or_error(n).username for n in added_reviewers])
707 [get_user_or_error(n).username for n in added_reviewers])
714 reviewers_changes['removed'] = sorted(
708 reviewers_changes['removed'] = sorted(
715 [get_user_or_error(n).username for n in removed_reviewers])
709 [get_user_or_error(n).username for n in removed_reviewers])
716 Session().commit()
710 Session().commit()
717
711
718 if str2bool(Optional.extract(close_pull_request)):
712 if str2bool(Optional.extract(close_pull_request)):
719 PullRequestModel().close_pull_request_with_comment(
713 PullRequestModel().close_pull_request_with_comment(
720 pull_request, apiuser, repo)
714 pull_request, apiuser, repo)
721 Session().commit()
715 Session().commit()
722
716
723 data = {
717 data = {
724 'msg': 'Updated pull request `{}`'.format(
718 'msg': 'Updated pull request `{}`'.format(
725 pull_request.pull_request_id),
719 pull_request.pull_request_id),
726 'pull_request': pull_request.get_api_data(),
720 'pull_request': pull_request.get_api_data(),
727 'updated_commits': commit_changes,
721 'updated_commits': commit_changes,
728 'updated_reviewers': reviewers_changes
722 'updated_reviewers': reviewers_changes
729 }
723 }
730
724
731 return data
725 return data
@@ -1,514 +1,515 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 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 import logging
21 import logging
22
22
23 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden
23 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden
24 from rhodecode.api.utils import (
24 from rhodecode.api.utils import (
25 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
25 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
26 from rhodecode.lib.auth import AuthUser, PasswordGenerator
26 from rhodecode.lib.auth import AuthUser, PasswordGenerator
27 from rhodecode.lib.exceptions import DefaultUserException
27 from rhodecode.lib.exceptions import DefaultUserException
28 from rhodecode.lib.utils2 import safe_int, str2bool
28 from rhodecode.lib.utils2 import safe_int, str2bool
29 from rhodecode.model.db import Session, User, Repository
29 from rhodecode.model.db import Session, User, Repository
30 from rhodecode.model.user import UserModel
30 from rhodecode.model.user import UserModel
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 @jsonrpc_method()
35 @jsonrpc_method()
36 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
36 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
37 """
37 """
38 Returns the information associated with a username or userid.
38 Returns the information associated with a username or userid.
39
39
40 * If the ``userid`` is not set, this command returns the information
40 * If the ``userid`` is not set, this command returns the information
41 for the ``userid`` calling the method.
41 for the ``userid`` calling the method.
42
42
43 .. note::
43 .. note::
44
44
45 Normal users may only run this command against their ``userid``. For
45 Normal users may only run this command against their ``userid``. For
46 full privileges you must run this command using an |authtoken| with
46 full privileges you must run this command using an |authtoken| with
47 admin rights.
47 admin rights.
48
48
49 :param apiuser: This is filled automatically from the |authtoken|.
49 :param apiuser: This is filled automatically from the |authtoken|.
50 :type apiuser: AuthUser
50 :type apiuser: AuthUser
51 :param userid: Sets the userid for which data will be returned.
51 :param userid: Sets the userid for which data will be returned.
52 :type userid: Optional(str or int)
52 :type userid: Optional(str or int)
53
53
54 Example output:
54 Example output:
55
55
56 .. code-block:: bash
56 .. code-block:: bash
57
57
58 {
58 {
59 "error": null,
59 "error": null,
60 "id": <id>,
60 "id": <id>,
61 "result": {
61 "result": {
62 "active": true,
62 "active": true,
63 "admin": false,
63 "admin": false,
64 "api_keys": [ list of keys ],
64 "api_keys": [ list of keys ],
65 "auth_tokens": [ list of tokens with details ],
65 "auth_tokens": [ list of tokens with details ],
66 "email": "user@example.com",
66 "email": "user@example.com",
67 "emails": [
67 "emails": [
68 "user@example.com"
68 "user@example.com"
69 ],
69 ],
70 "extern_name": "rhodecode",
70 "extern_name": "rhodecode",
71 "extern_type": "rhodecode",
71 "extern_type": "rhodecode",
72 "firstname": "username",
72 "firstname": "username",
73 "ip_addresses": [],
73 "ip_addresses": [],
74 "language": null,
74 "language": null,
75 "last_login": "Timestamp",
75 "last_login": "Timestamp",
76 "last_activity": "Timestamp",
76 "last_activity": "Timestamp",
77 "lastname": "surnae",
77 "lastname": "surnae",
78 "permissions": {
78 "permissions": {
79 "global": [
79 "global": [
80 "hg.inherit_default_perms.true",
80 "hg.inherit_default_perms.true",
81 "usergroup.read",
81 "usergroup.read",
82 "hg.repogroup.create.false",
82 "hg.repogroup.create.false",
83 "hg.create.none",
83 "hg.create.none",
84 "hg.password_reset.enabled",
84 "hg.password_reset.enabled",
85 "hg.extern_activate.manual",
85 "hg.extern_activate.manual",
86 "hg.create.write_on_repogroup.false",
86 "hg.create.write_on_repogroup.false",
87 "hg.usergroup.create.false",
87 "hg.usergroup.create.false",
88 "group.none",
88 "group.none",
89 "repository.none",
89 "repository.none",
90 "hg.register.none",
90 "hg.register.none",
91 "hg.fork.repository"
91 "hg.fork.repository"
92 ],
92 ],
93 "repositories": { "username/example": "repository.write"},
93 "repositories": { "username/example": "repository.write"},
94 "repositories_groups": { "user-group/repo": "group.none" },
94 "repositories_groups": { "user-group/repo": "group.none" },
95 "user_groups": { "user_group_name": "usergroup.read" }
95 "user_groups": { "user_group_name": "usergroup.read" }
96 },
96 },
97 "user_id": 32,
97 "user_id": 32,
98 "username": "username"
98 "username": "username"
99 }
99 }
100 }
100 }
101 """
101 """
102
102
103 if not has_superadmin_permission(apiuser):
103 if not has_superadmin_permission(apiuser):
104 # make sure normal user does not pass someone else userid,
104 # make sure normal user does not pass someone else userid,
105 # he is not allowed to do that
105 # he is not allowed to do that
106 if not isinstance(userid, Optional) and userid != apiuser.user_id:
106 if not isinstance(userid, Optional) and userid != apiuser.user_id:
107 raise JSONRPCError('userid is not the same as your user')
107 raise JSONRPCError('userid is not the same as your user')
108
108
109 userid = Optional.extract(userid, evaluate_locals=locals())
109 userid = Optional.extract(userid, evaluate_locals=locals())
110 userid = getattr(userid, 'user_id', userid)
110 userid = getattr(userid, 'user_id', userid)
111
111
112 user = get_user_or_error(userid)
112 user = get_user_or_error(userid)
113 data = user.get_api_data(include_secrets=True)
113 data = user.get_api_data(include_secrets=True)
114 data['permissions'] = AuthUser(user_id=user.user_id).permissions
114 data['permissions'] = AuthUser(user_id=user.user_id).permissions
115 return data
115 return data
116
116
117
117
118 @jsonrpc_method()
118 @jsonrpc_method()
119 def get_users(request, apiuser):
119 def get_users(request, apiuser):
120 """
120 """
121 Lists all users in the |RCE| user database.
121 Lists all users in the |RCE| user database.
122
122
123 This command can only be run using an |authtoken| with admin rights to
123 This command can only be run using an |authtoken| with admin rights to
124 the specified repository.
124 the specified repository.
125
125
126 This command takes the following options:
126 This command takes the following options:
127
127
128 :param apiuser: This is filled automatically from the |authtoken|.
128 :param apiuser: This is filled automatically from the |authtoken|.
129 :type apiuser: AuthUser
129 :type apiuser: AuthUser
130
130
131 Example output:
131 Example output:
132
132
133 .. code-block:: bash
133 .. code-block:: bash
134
134
135 id : <id_given_in_input>
135 id : <id_given_in_input>
136 result: [<user_object>, ...]
136 result: [<user_object>, ...]
137 error: null
137 error: null
138 """
138 """
139
139
140 if not has_superadmin_permission(apiuser):
140 if not has_superadmin_permission(apiuser):
141 raise JSONRPCForbidden()
141 raise JSONRPCForbidden()
142
142
143 result = []
143 result = []
144 users_list = User.query().order_by(User.username) \
144 users_list = User.query().order_by(User.username) \
145 .filter(User.username != User.DEFAULT_USER) \
145 .filter(User.username != User.DEFAULT_USER) \
146 .all()
146 .all()
147 for user in users_list:
147 for user in users_list:
148 result.append(user.get_api_data(include_secrets=True))
148 result.append(user.get_api_data(include_secrets=True))
149 return result
149 return result
150
150
151
151
152 @jsonrpc_method()
152 @jsonrpc_method()
153 def create_user(request, apiuser, username, email, password=Optional(''),
153 def create_user(request, apiuser, username, email, password=Optional(''),
154 firstname=Optional(''), lastname=Optional(''),
154 firstname=Optional(''), lastname=Optional(''),
155 active=Optional(True), admin=Optional(False),
155 active=Optional(True), admin=Optional(False),
156 extern_name=Optional('rhodecode'),
156 extern_name=Optional('rhodecode'),
157 extern_type=Optional('rhodecode'),
157 extern_type=Optional('rhodecode'),
158 force_password_change=Optional(False),
158 force_password_change=Optional(False),
159 create_personal_repo_group=Optional(None)):
159 create_personal_repo_group=Optional(None)):
160 """
160 """
161 Creates a new user and returns the new user object.
161 Creates a new user and returns the new user object.
162
162
163 This command can only be run using an |authtoken| with admin rights to
163 This command can only be run using an |authtoken| with admin rights to
164 the specified repository.
164 the specified repository.
165
165
166 This command takes the following options:
166 This command takes the following options:
167
167
168 :param apiuser: This is filled automatically from the |authtoken|.
168 :param apiuser: This is filled automatically from the |authtoken|.
169 :type apiuser: AuthUser
169 :type apiuser: AuthUser
170 :param username: Set the new username.
170 :param username: Set the new username.
171 :type username: str or int
171 :type username: str or int
172 :param email: Set the user email address.
172 :param email: Set the user email address.
173 :type email: str
173 :type email: str
174 :param password: Set the new user password.
174 :param password: Set the new user password.
175 :type password: Optional(str)
175 :type password: Optional(str)
176 :param firstname: Set the new user firstname.
176 :param firstname: Set the new user firstname.
177 :type firstname: Optional(str)
177 :type firstname: Optional(str)
178 :param lastname: Set the new user surname.
178 :param lastname: Set the new user surname.
179 :type lastname: Optional(str)
179 :type lastname: Optional(str)
180 :param active: Set the user as active.
180 :param active: Set the user as active.
181 :type active: Optional(``True`` | ``False``)
181 :type active: Optional(``True`` | ``False``)
182 :param admin: Give the new user admin rights.
182 :param admin: Give the new user admin rights.
183 :type admin: Optional(``True`` | ``False``)
183 :type admin: Optional(``True`` | ``False``)
184 :param extern_name: Set the authentication plugin name.
184 :param extern_name: Set the authentication plugin name.
185 Using LDAP this is filled with LDAP UID.
185 Using LDAP this is filled with LDAP UID.
186 :type extern_name: Optional(str)
186 :type extern_name: Optional(str)
187 :param extern_type: Set the new user authentication plugin.
187 :param extern_type: Set the new user authentication plugin.
188 :type extern_type: Optional(str)
188 :type extern_type: Optional(str)
189 :param force_password_change: Force the new user to change password
189 :param force_password_change: Force the new user to change password
190 on next login.
190 on next login.
191 :type force_password_change: Optional(``True`` | ``False``)
191 :type force_password_change: Optional(``True`` | ``False``)
192 :param create_personal_repo_group: Create personal repo group for this user
192 :param create_personal_repo_group: Create personal repo group for this user
193 :type create_personal_repo_group: Optional(``True`` | ``False``)
193 :type create_personal_repo_group: Optional(``True`` | ``False``)
194
194 Example output:
195 Example output:
195
196
196 .. code-block:: bash
197 .. code-block:: bash
197
198
198 id : <id_given_in_input>
199 id : <id_given_in_input>
199 result: {
200 result: {
200 "msg" : "created new user `<username>`",
201 "msg" : "created new user `<username>`",
201 "user": <user_obj>
202 "user": <user_obj>
202 }
203 }
203 error: null
204 error: null
204
205
205 Example error output:
206 Example error output:
206
207
207 .. code-block:: bash
208 .. code-block:: bash
208
209
209 id : <id_given_in_input>
210 id : <id_given_in_input>
210 result : null
211 result : null
211 error : {
212 error : {
212 "user `<username>` already exist"
213 "user `<username>` already exist"
213 or
214 or
214 "email `<email>` already exist"
215 "email `<email>` already exist"
215 or
216 or
216 "failed to create user `<username>`"
217 "failed to create user `<username>`"
217 }
218 }
218
219
219 """
220 """
220 if not has_superadmin_permission(apiuser):
221 if not has_superadmin_permission(apiuser):
221 raise JSONRPCForbidden()
222 raise JSONRPCForbidden()
222
223
223 if UserModel().get_by_username(username):
224 if UserModel().get_by_username(username):
224 raise JSONRPCError("user `%s` already exist" % (username,))
225 raise JSONRPCError("user `%s` already exist" % (username,))
225
226
226 if UserModel().get_by_email(email, case_insensitive=True):
227 if UserModel().get_by_email(email, case_insensitive=True):
227 raise JSONRPCError("email `%s` already exist" % (email,))
228 raise JSONRPCError("email `%s` already exist" % (email,))
228
229
229 # generate random password if we actually given the
230 # generate random password if we actually given the
230 # extern_name and it's not rhodecode
231 # extern_name and it's not rhodecode
231 if (not isinstance(extern_name, Optional) and
232 if (not isinstance(extern_name, Optional) and
232 Optional.extract(extern_name) != 'rhodecode'):
233 Optional.extract(extern_name) != 'rhodecode'):
233 # generate temporary password if user is external
234 # generate temporary password if user is external
234 password = PasswordGenerator().gen_password(length=16)
235 password = PasswordGenerator().gen_password(length=16)
235 create_repo_group = Optional.extract(create_personal_repo_group)
236 create_repo_group = Optional.extract(create_personal_repo_group)
236 if isinstance(create_repo_group, basestring):
237 if isinstance(create_repo_group, basestring):
237 create_repo_group = str2bool(create_repo_group)
238 create_repo_group = str2bool(create_repo_group)
238
239
239 try:
240 try:
240 user = UserModel().create_or_update(
241 user = UserModel().create_or_update(
241 username=Optional.extract(username),
242 username=Optional.extract(username),
242 password=Optional.extract(password),
243 password=Optional.extract(password),
243 email=Optional.extract(email),
244 email=Optional.extract(email),
244 firstname=Optional.extract(firstname),
245 firstname=Optional.extract(firstname),
245 lastname=Optional.extract(lastname),
246 lastname=Optional.extract(lastname),
246 active=Optional.extract(active),
247 active=Optional.extract(active),
247 admin=Optional.extract(admin),
248 admin=Optional.extract(admin),
248 extern_type=Optional.extract(extern_type),
249 extern_type=Optional.extract(extern_type),
249 extern_name=Optional.extract(extern_name),
250 extern_name=Optional.extract(extern_name),
250 force_password_change=Optional.extract(force_password_change),
251 force_password_change=Optional.extract(force_password_change),
251 create_repo_group=create_repo_group
252 create_repo_group=create_repo_group
252 )
253 )
253 Session().commit()
254 Session().commit()
254 return {
255 return {
255 'msg': 'created new user `%s`' % username,
256 'msg': 'created new user `%s`' % username,
256 'user': user.get_api_data(include_secrets=True)
257 'user': user.get_api_data(include_secrets=True)
257 }
258 }
258 except Exception:
259 except Exception:
259 log.exception('Error occurred during creation of user')
260 log.exception('Error occurred during creation of user')
260 raise JSONRPCError('failed to create user `%s`' % (username,))
261 raise JSONRPCError('failed to create user `%s`' % (username,))
261
262
262
263
263 @jsonrpc_method()
264 @jsonrpc_method()
264 def update_user(request, apiuser, userid, username=Optional(None),
265 def update_user(request, apiuser, userid, username=Optional(None),
265 email=Optional(None), password=Optional(None),
266 email=Optional(None), password=Optional(None),
266 firstname=Optional(None), lastname=Optional(None),
267 firstname=Optional(None), lastname=Optional(None),
267 active=Optional(None), admin=Optional(None),
268 active=Optional(None), admin=Optional(None),
268 extern_type=Optional(None), extern_name=Optional(None), ):
269 extern_type=Optional(None), extern_name=Optional(None), ):
269 """
270 """
270 Updates the details for the specified user, if that user exists.
271 Updates the details for the specified user, if that user exists.
271
272
272 This command can only be run using an |authtoken| with admin rights to
273 This command can only be run using an |authtoken| with admin rights to
273 the specified repository.
274 the specified repository.
274
275
275 This command takes the following options:
276 This command takes the following options:
276
277
277 :param apiuser: This is filled automatically from |authtoken|.
278 :param apiuser: This is filled automatically from |authtoken|.
278 :type apiuser: AuthUser
279 :type apiuser: AuthUser
279 :param userid: Set the ``userid`` to update.
280 :param userid: Set the ``userid`` to update.
280 :type userid: str or int
281 :type userid: str or int
281 :param username: Set the new username.
282 :param username: Set the new username.
282 :type username: str or int
283 :type username: str or int
283 :param email: Set the new email.
284 :param email: Set the new email.
284 :type email: str
285 :type email: str
285 :param password: Set the new password.
286 :param password: Set the new password.
286 :type password: Optional(str)
287 :type password: Optional(str)
287 :param firstname: Set the new first name.
288 :param firstname: Set the new first name.
288 :type firstname: Optional(str)
289 :type firstname: Optional(str)
289 :param lastname: Set the new surname.
290 :param lastname: Set the new surname.
290 :type lastname: Optional(str)
291 :type lastname: Optional(str)
291 :param active: Set the new user as active.
292 :param active: Set the new user as active.
292 :type active: Optional(``True`` | ``False``)
293 :type active: Optional(``True`` | ``False``)
293 :param admin: Give the user admin rights.
294 :param admin: Give the user admin rights.
294 :type admin: Optional(``True`` | ``False``)
295 :type admin: Optional(``True`` | ``False``)
295 :param extern_name: Set the authentication plugin user name.
296 :param extern_name: Set the authentication plugin user name.
296 Using LDAP this is filled with LDAP UID.
297 Using LDAP this is filled with LDAP UID.
297 :type extern_name: Optional(str)
298 :type extern_name: Optional(str)
298 :param extern_type: Set the authentication plugin type.
299 :param extern_type: Set the authentication plugin type.
299 :type extern_type: Optional(str)
300 :type extern_type: Optional(str)
300
301
301
302
302 Example output:
303 Example output:
303
304
304 .. code-block:: bash
305 .. code-block:: bash
305
306
306 id : <id_given_in_input>
307 id : <id_given_in_input>
307 result: {
308 result: {
308 "msg" : "updated user ID:<userid> <username>",
309 "msg" : "updated user ID:<userid> <username>",
309 "user": <user_object>,
310 "user": <user_object>,
310 }
311 }
311 error: null
312 error: null
312
313
313 Example error output:
314 Example error output:
314
315
315 .. code-block:: bash
316 .. code-block:: bash
316
317
317 id : <id_given_in_input>
318 id : <id_given_in_input>
318 result : null
319 result : null
319 error : {
320 error : {
320 "failed to update user `<username>`"
321 "failed to update user `<username>`"
321 }
322 }
322
323
323 """
324 """
324 if not has_superadmin_permission(apiuser):
325 if not has_superadmin_permission(apiuser):
325 raise JSONRPCForbidden()
326 raise JSONRPCForbidden()
326
327
327 user = get_user_or_error(userid)
328 user = get_user_or_error(userid)
328
329
329 # only non optional arguments will be stored in updates
330 # only non optional arguments will be stored in updates
330 updates = {}
331 updates = {}
331
332
332 try:
333 try:
333
334
334 store_update(updates, username, 'username')
335 store_update(updates, username, 'username')
335 store_update(updates, password, 'password')
336 store_update(updates, password, 'password')
336 store_update(updates, email, 'email')
337 store_update(updates, email, 'email')
337 store_update(updates, firstname, 'name')
338 store_update(updates, firstname, 'name')
338 store_update(updates, lastname, 'lastname')
339 store_update(updates, lastname, 'lastname')
339 store_update(updates, active, 'active')
340 store_update(updates, active, 'active')
340 store_update(updates, admin, 'admin')
341 store_update(updates, admin, 'admin')
341 store_update(updates, extern_name, 'extern_name')
342 store_update(updates, extern_name, 'extern_name')
342 store_update(updates, extern_type, 'extern_type')
343 store_update(updates, extern_type, 'extern_type')
343
344
344 user = UserModel().update_user(user, **updates)
345 user = UserModel().update_user(user, **updates)
345 Session().commit()
346 Session().commit()
346 return {
347 return {
347 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
348 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
348 'user': user.get_api_data(include_secrets=True)
349 'user': user.get_api_data(include_secrets=True)
349 }
350 }
350 except DefaultUserException:
351 except DefaultUserException:
351 log.exception("Default user edit exception")
352 log.exception("Default user edit exception")
352 raise JSONRPCError('editing default user is forbidden')
353 raise JSONRPCError('editing default user is forbidden')
353 except Exception:
354 except Exception:
354 log.exception("Error occurred during update of user")
355 log.exception("Error occurred during update of user")
355 raise JSONRPCError('failed to update user `%s`' % (userid,))
356 raise JSONRPCError('failed to update user `%s`' % (userid,))
356
357
357
358
358 @jsonrpc_method()
359 @jsonrpc_method()
359 def delete_user(request, apiuser, userid):
360 def delete_user(request, apiuser, userid):
360 """
361 """
361 Deletes the specified user from the |RCE| user database.
362 Deletes the specified user from the |RCE| user database.
362
363
363 This command can only be run using an |authtoken| with admin rights to
364 This command can only be run using an |authtoken| with admin rights to
364 the specified repository.
365 the specified repository.
365
366
366 .. important::
367 .. important::
367
368
368 Ensure all open pull requests and open code review
369 Ensure all open pull requests and open code review
369 requests to this user are close.
370 requests to this user are close.
370
371
371 Also ensure all repositories, or repository groups owned by this
372 Also ensure all repositories, or repository groups owned by this
372 user are reassigned before deletion.
373 user are reassigned before deletion.
373
374
374 This command takes the following options:
375 This command takes the following options:
375
376
376 :param apiuser: This is filled automatically from the |authtoken|.
377 :param apiuser: This is filled automatically from the |authtoken|.
377 :type apiuser: AuthUser
378 :type apiuser: AuthUser
378 :param userid: Set the user to delete.
379 :param userid: Set the user to delete.
379 :type userid: str or int
380 :type userid: str or int
380
381
381 Example output:
382 Example output:
382
383
383 .. code-block:: bash
384 .. code-block:: bash
384
385
385 id : <id_given_in_input>
386 id : <id_given_in_input>
386 result: {
387 result: {
387 "msg" : "deleted user ID:<userid> <username>",
388 "msg" : "deleted user ID:<userid> <username>",
388 "user": null
389 "user": null
389 }
390 }
390 error: null
391 error: null
391
392
392 Example error output:
393 Example error output:
393
394
394 .. code-block:: bash
395 .. code-block:: bash
395
396
396 id : <id_given_in_input>
397 id : <id_given_in_input>
397 result : null
398 result : null
398 error : {
399 error : {
399 "failed to delete user ID:<userid> <username>"
400 "failed to delete user ID:<userid> <username>"
400 }
401 }
401
402
402 """
403 """
403 if not has_superadmin_permission(apiuser):
404 if not has_superadmin_permission(apiuser):
404 raise JSONRPCForbidden()
405 raise JSONRPCForbidden()
405
406
406 user = get_user_or_error(userid)
407 user = get_user_or_error(userid)
407
408
408 try:
409 try:
409 UserModel().delete(userid)
410 UserModel().delete(userid)
410 Session().commit()
411 Session().commit()
411 return {
412 return {
412 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
413 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
413 'user': None
414 'user': None
414 }
415 }
415 except Exception:
416 except Exception:
416 log.exception("Error occurred during deleting of user")
417 log.exception("Error occurred during deleting of user")
417 raise JSONRPCError(
418 raise JSONRPCError(
418 'failed to delete user ID:%s %s' % (user.user_id, user.username))
419 'failed to delete user ID:%s %s' % (user.user_id, user.username))
419
420
420
421
421 @jsonrpc_method()
422 @jsonrpc_method()
422 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
423 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
423 """
424 """
424 Displays all repositories locked by the specified user.
425 Displays all repositories locked by the specified user.
425
426
426 * If this command is run by a non-admin user, it returns
427 * If this command is run by a non-admin user, it returns
427 a list of |repos| locked by that user.
428 a list of |repos| locked by that user.
428
429
429 This command takes the following options:
430 This command takes the following options:
430
431
431 :param apiuser: This is filled automatically from the |authtoken|.
432 :param apiuser: This is filled automatically from the |authtoken|.
432 :type apiuser: AuthUser
433 :type apiuser: AuthUser
433 :param userid: Sets the userid whose list of locked |repos| will be
434 :param userid: Sets the userid whose list of locked |repos| will be
434 displayed.
435 displayed.
435 :type userid: Optional(str or int)
436 :type userid: Optional(str or int)
436
437
437 Example output:
438 Example output:
438
439
439 .. code-block:: bash
440 .. code-block:: bash
440
441
441 id : <id_given_in_input>
442 id : <id_given_in_input>
442 result : {
443 result : {
443 [repo_object, repo_object,...]
444 [repo_object, repo_object,...]
444 }
445 }
445 error : null
446 error : null
446 """
447 """
447
448
448 include_secrets = False
449 include_secrets = False
449 if not has_superadmin_permission(apiuser):
450 if not has_superadmin_permission(apiuser):
450 # make sure normal user does not pass someone else userid,
451 # make sure normal user does not pass someone else userid,
451 # he is not allowed to do that
452 # he is not allowed to do that
452 if not isinstance(userid, Optional) and userid != apiuser.user_id:
453 if not isinstance(userid, Optional) and userid != apiuser.user_id:
453 raise JSONRPCError('userid is not the same as your user')
454 raise JSONRPCError('userid is not the same as your user')
454 else:
455 else:
455 include_secrets = True
456 include_secrets = True
456
457
457 userid = Optional.extract(userid, evaluate_locals=locals())
458 userid = Optional.extract(userid, evaluate_locals=locals())
458 userid = getattr(userid, 'user_id', userid)
459 userid = getattr(userid, 'user_id', userid)
459 user = get_user_or_error(userid)
460 user = get_user_or_error(userid)
460
461
461 ret = []
462 ret = []
462
463
463 # show all locks
464 # show all locks
464 for r in Repository.getAll():
465 for r in Repository.getAll():
465 _user_id, _time, _reason = r.locked
466 _user_id, _time, _reason = r.locked
466 if _user_id and _time:
467 if _user_id and _time:
467 _api_data = r.get_api_data(include_secrets=include_secrets)
468 _api_data = r.get_api_data(include_secrets=include_secrets)
468 # if we use user filter just show the locks for this user
469 # if we use user filter just show the locks for this user
469 if safe_int(_user_id) == user.user_id:
470 if safe_int(_user_id) == user.user_id:
470 ret.append(_api_data)
471 ret.append(_api_data)
471
472
472 return ret
473 return ret
473
474
474
475
475 @jsonrpc_method()
476 @jsonrpc_method()
476 def get_user_audit_logs(request, apiuser, userid=Optional(OAttr('apiuser'))):
477 def get_user_audit_logs(request, apiuser, userid=Optional(OAttr('apiuser'))):
477 """
478 """
478 Fetches all action logs made by the specified user.
479 Fetches all action logs made by the specified user.
479
480
480 This command takes the following options:
481 This command takes the following options:
481
482
482 :param apiuser: This is filled automatically from the |authtoken|.
483 :param apiuser: This is filled automatically from the |authtoken|.
483 :type apiuser: AuthUser
484 :type apiuser: AuthUser
484 :param userid: Sets the userid whose list of locked |repos| will be
485 :param userid: Sets the userid whose list of locked |repos| will be
485 displayed.
486 displayed.
486 :type userid: Optional(str or int)
487 :type userid: Optional(str or int)
487
488
488 Example output:
489 Example output:
489
490
490 .. code-block:: bash
491 .. code-block:: bash
491
492
492 id : <id_given_in_input>
493 id : <id_given_in_input>
493 result : {
494 result : {
494 [action, action,...]
495 [action, action,...]
495 }
496 }
496 error : null
497 error : null
497 """
498 """
498
499
499 if not has_superadmin_permission(apiuser):
500 if not has_superadmin_permission(apiuser):
500 # make sure normal user does not pass someone else userid,
501 # make sure normal user does not pass someone else userid,
501 # he is not allowed to do that
502 # he is not allowed to do that
502 if not isinstance(userid, Optional) and userid != apiuser.user_id:
503 if not isinstance(userid, Optional) and userid != apiuser.user_id:
503 raise JSONRPCError('userid is not the same as your user')
504 raise JSONRPCError('userid is not the same as your user')
504
505
505 userid = Optional.extract(userid, evaluate_locals=locals())
506 userid = Optional.extract(userid, evaluate_locals=locals())
506 userid = getattr(userid, 'user_id', userid)
507 userid = getattr(userid, 'user_id', userid)
507 user = get_user_or_error(userid)
508 user = get_user_or_error(userid)
508
509
509 ret = []
510 ret = []
510
511
511 # show all user actions
512 # show all user actions
512 for entry in UserModel().get_user_log(user, filter_term=None):
513 for entry in UserModel().get_user_log(user, filter_term=None):
513 ret.append(entry)
514 ret.append(entry)
514 return ret
515 return ret
General Comments 0
You need to be logged in to leave comments. Login now