##// END OF EJS Templates
API invalidate_cache function ref #733
marcink -
r3235:d6029dac beta
parent child Browse files
Show More
@@ -1,959 +1,981 b''
1 .. _api:
1 .. _api:
2
2
3 ===
3 ===
4 API
4 API
5 ===
5 ===
6
6
7
7
8 Starting from RhodeCode version 1.2 a simple API was implemented.
8 Starting from RhodeCode version 1.2 a simple API was implemented.
9 There's a single schema for calling all api methods. API is implemented
9 There's a single schema for calling all api methods. API is implemented
10 with JSON protocol both ways. An url to send API request to RhodeCode is
10 with JSON protocol both ways. An url to send API request to RhodeCode is
11 <your_server>/_admin/api
11 <your_server>/_admin/api
12
12
13 API ACCESS FOR WEB VIEWS
13 API ACCESS FOR WEB VIEWS
14 ++++++++++++++++++++++++
14 ++++++++++++++++++++++++
15
15
16 API access can also be turned on for each web view in RhodeCode that is
16 API access can also be turned on for each web view in RhodeCode that is
17 decorated with `@LoginRequired` decorator. To enable API access simple change
17 decorated with `@LoginRequired` decorator. To enable API access simple change
18 the standard login decorator to `@LoginRequired(api_access=True)`.
18 the standard login decorator to `@LoginRequired(api_access=True)`.
19 After this change, a rhodecode view can be accessed without login by adding a
19 After this change, a rhodecode view can be accessed without login by adding a
20 GET parameter `?api_key=<api_key>` to url. By default this is only
20 GET parameter `?api_key=<api_key>` to url. By default this is only
21 enabled on RSS/ATOM feed views.
21 enabled on RSS/ATOM feed views.
22
22
23
23
24 API ACCESS
24 API ACCESS
25 ++++++++++
25 ++++++++++
26
26
27 All clients are required to send JSON-RPC spec JSON data::
27 All clients are required to send JSON-RPC spec JSON data::
28
28
29 {
29 {
30 "id:"<id>",
30 "id:"<id>",
31 "api_key":"<api_key>",
31 "api_key":"<api_key>",
32 "method":"<method_name>",
32 "method":"<method_name>",
33 "args":{"<arg_key>":"<arg_val>"}
33 "args":{"<arg_key>":"<arg_val>"}
34 }
34 }
35
35
36 Example call for autopulling remotes repos using curl::
36 Example call for autopulling remotes repos using curl::
37 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
37 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"id":1,"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
38
38
39 Simply provide
39 Simply provide
40 - *id* A value of any type, which is used to match the response with the request that it is replying to.
40 - *id* A value of any type, which is used to match the response with the request that it is replying to.
41 - *api_key* for access and permission validation.
41 - *api_key* for access and permission validation.
42 - *method* is name of method to call
42 - *method* is name of method to call
43 - *args* is an key:value list of arguments to pass to method
43 - *args* is an key:value list of arguments to pass to method
44
44
45 .. note::
45 .. note::
46
46
47 api_key can be found in your user account page
47 api_key can be found in your user account page
48
48
49
49
50 RhodeCode API will return always a JSON-RPC response::
50 RhodeCode API will return always a JSON-RPC response::
51
51
52 {
52 {
53 "id":<id>, # matching id sent by request
53 "id":<id>, # matching id sent by request
54 "result": "<result>"|null, # JSON formatted result, null if any errors
54 "result": "<result>"|null, # JSON formatted result, null if any errors
55 "error": "null"|<error_message> # JSON formatted error (if any)
55 "error": "null"|<error_message> # JSON formatted error (if any)
56 }
56 }
57
57
58 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
58 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
59 calling api *error* key from response will contain failure description
59 calling api *error* key from response will contain failure description
60 and result will be null.
60 and result will be null.
61
61
62
62
63 API CLIENT
63 API CLIENT
64 ++++++++++
64 ++++++++++
65
65
66 From version 1.4 RhodeCode adds a script that allows to easily
66 From version 1.4 RhodeCode adds a script that allows to easily
67 communicate with API. After installing RhodeCode a `rhodecode-api` script
67 communicate with API. After installing RhodeCode a `rhodecode-api` script
68 will be available.
68 will be available.
69
69
70 To get started quickly simply run::
70 To get started quickly simply run::
71
71
72 rhodecode-api _create_config --apikey=<youapikey> --apihost=<rhodecode host>
72 rhodecode-api _create_config --apikey=<youapikey> --apihost=<rhodecode host>
73
73
74 This will create a file named .config in the directory you executed it storing
74 This will create a file named .config in the directory you executed it storing
75 json config file with credentials. You can skip this step and always provide
75 json config file with credentials. You can skip this step and always provide
76 both of the arguments to be able to communicate with server
76 both of the arguments to be able to communicate with server
77
77
78
78
79 after that simply run any api command for example get_repo::
79 after that simply run any api command for example get_repo::
80
80
81 rhodecode-api get_repo
81 rhodecode-api get_repo
82
82
83 calling {"api_key": "<apikey>", "id": 75, "args": {}, "method": "get_repo"} to http://127.0.0.1:5000
83 calling {"api_key": "<apikey>", "id": 75, "args": {}, "method": "get_repo"} to http://127.0.0.1:5000
84 rhodecode said:
84 rhodecode said:
85 {'error': 'Missing non optional `repoid` arg in JSON DATA',
85 {'error': 'Missing non optional `repoid` arg in JSON DATA',
86 'id': 75,
86 'id': 75,
87 'result': None}
87 'result': None}
88
88
89 Ups looks like we forgot to add an argument
89 Ups looks like we forgot to add an argument
90
90
91 Let's try again now giving the repoid as parameters::
91 Let's try again now giving the repoid as parameters::
92
92
93 rhodecode-api get_repo repoid:rhodecode
93 rhodecode-api get_repo repoid:rhodecode
94
94
95 calling {"api_key": "<apikey>", "id": 39, "args": {"repoid": "rhodecode"}, "method": "get_repo"} to http://127.0.0.1:5000
95 calling {"api_key": "<apikey>", "id": 39, "args": {"repoid": "rhodecode"}, "method": "get_repo"} to http://127.0.0.1:5000
96 rhodecode said:
96 rhodecode said:
97 {'error': None,
97 {'error': None,
98 'id': 39,
98 'id': 39,
99 'result': <json data...>}
99 'result': <json data...>}
100
100
101
101
102
102
103 API METHODS
103 API METHODS
104 +++++++++++
104 +++++++++++
105
105
106
106
107 pull
107 pull
108 ----
108 ----
109
109
110 Pulls given repo from remote location. Can be used to automatically keep
110 Pulls given repo from remote location. Can be used to automatically keep
111 remote repos up to date. This command can be executed only using api_key
111 remote repos up to date. This command can be executed only using api_key
112 belonging to user with admin rights
112 belonging to user with admin rights
113
113
114 INPUT::
114 INPUT::
115
115
116 id : <id_for_response>
116 id : <id_for_response>
117 api_key : "<api_key>"
117 api_key : "<api_key>"
118 method : "pull"
118 method : "pull"
119 args : {
119 args : {
120 "repoid" : "<reponame or repo_id>"
120 "repoid" : "<reponame or repo_id>"
121 }
121 }
122
122
123 OUTPUT::
123 OUTPUT::
124
124
125 id : <id_given_in_input>
125 id : <id_given_in_input>
126 result : "Pulled from `<reponame>`"
126 result : "Pulled from `<reponame>`"
127 error : null
127 error : null
128
128
129
129
130 rescan_repos
130 rescan_repos
131 ------------
131 ------------
132
132
133 Dispatch rescan repositories action. If remove_obsolete is set
133 Dispatch rescan repositories action. If remove_obsolete is set
134 RhodeCode will delete repos that are in database but not in the filesystem.
134 RhodeCode will delete repos that are in database but not in the filesystem.
135 This command can be executed only using api_key belonging to user with admin
135 This command can be executed only using api_key belonging to user with admin
136 rights.
136 rights.
137
137
138 INPUT::
138 INPUT::
139
139
140 id : <id_for_response>
140 id : <id_for_response>
141 api_key : "<api_key>"
141 api_key : "<api_key>"
142 method : "rescan_repos"
142 method : "rescan_repos"
143 args : {
143 args : {
144 "remove_obsolete" : "<boolean = Optional(False)>"
144 "remove_obsolete" : "<boolean = Optional(False)>"
145 }
145 }
146
146
147 OUTPUT::
147 OUTPUT::
148
148
149 id : <id_given_in_input>
149 id : <id_given_in_input>
150 result : "{'added': [<list of names of added repos>],
150 result : "{'added': [<list of names of added repos>],
151 'removed': [<list of names of removed repos>]}"
151 'removed': [<list of names of removed repos>]}"
152 error : null
152 error : null
153
153
154
154
155 invalidate_cache
156 ----------------
157
158 Invalidate cache for repository.
159 This command can be executed only using api_key belonging to user with admin
160 rights or regular user that have write or admin or write access to repository.
161
162 INPUT::
163
164 id : <id_for_response>
165 api_key : "<api_key>"
166 method : "invalidate_cache"
167 args : {
168 "repoid" : "<reponame or repo_id>"
169 }
170
171 OUTPUT::
172
173 id : <id_given_in_input>
174 result : "Cache for repository `<reponame>` was invalidated: invalidated cache keys: <list_of_cache_keys>"
175 error : null
176
155 lock
177 lock
156 ----
178 ----
157
179
158 Set locking state on given repository by given user. If userid param is skipped
180 Set locking state on given repository by given user. If userid param is skipped
159 , then it is set to id of user whos calling this method.
181 , then it is set to id of user whos calling this method.
160 This command can be executed only using api_key belonging to user with admin
182 This command can be executed only using api_key belonging to user with admin
161 rights or regular user that have admin or write access to repository.
183 rights or regular user that have admin or write access to repository.
162
184
163 INPUT::
185 INPUT::
164
186
165 id : <id_for_response>
187 id : <id_for_response>
166 api_key : "<api_key>"
188 api_key : "<api_key>"
167 method : "lock"
189 method : "lock"
168 args : {
190 args : {
169 "repoid" : "<reponame or repo_id>"
191 "repoid" : "<reponame or repo_id>"
170 "userid" : "<user_id or username = Optional(=apiuser)>",
192 "userid" : "<user_id or username = Optional(=apiuser)>",
171 "locked" : "<bool true|false>"
193 "locked" : "<bool true|false>"
172 }
194 }
173
195
174 OUTPUT::
196 OUTPUT::
175
197
176 id : <id_given_in_input>
198 id : <id_given_in_input>
177 result : "User `<username>` set lock state for repo `<reponame>` to `true|false`"
199 result : "User `<username>` set lock state for repo `<reponame>` to `true|false`"
178 error : null
200 error : null
179
201
180
202
181 show_ip
203 show_ip
182 -------
204 -------
183
205
184 Shows IP address as seen from RhodeCode server, together with all
206 Shows IP address as seen from RhodeCode server, together with all
185 defined IP addresses for given user.
207 defined IP addresses for given user.
186 This command can be executed only using api_key belonging to user with admin
208 This command can be executed only using api_key belonging to user with admin
187 rights.
209 rights.
188
210
189 INPUT::
211 INPUT::
190
212
191 id : <id_for_response>
213 id : <id_for_response>
192 api_key : "<api_key>"
214 api_key : "<api_key>"
193 method : "show_ip"
215 method : "show_ip"
194 args : {
216 args : {
195 "userid" : "<user_id or username>",
217 "userid" : "<user_id or username>",
196 }
218 }
197
219
198 OUTPUT::
220 OUTPUT::
199
221
200 id : <id_given_in_input>
222 id : <id_given_in_input>
201 result : {
223 result : {
202 "ip_addr_server": <ip_from_clien>",
224 "ip_addr_server": <ip_from_clien>",
203 "user_ips": [
225 "user_ips": [
204 {
226 {
205 "ip_addr": "<ip_with_mask>",
227 "ip_addr": "<ip_with_mask>",
206 "ip_range": ["<start_ip>", "<end_ip>"],
228 "ip_range": ["<start_ip>", "<end_ip>"],
207 },
229 },
208 ...
230 ...
209 ]
231 ]
210 }
232 }
211
233
212 error : null
234 error : null
213
235
214
236
215 get_user
237 get_user
216 --------
238 --------
217
239
218 Get's an user by username or user_id, Returns empty result if user is not found.
240 Get's an user by username or user_id, Returns empty result if user is not found.
219 If userid param is skipped it is set to id of user who is calling this method.
241 If userid param is skipped it is set to id of user who is calling this method.
220 This command can be executed only using api_key belonging to user with admin
242 This command can be executed only using api_key belonging to user with admin
221 rights, or regular users that cannot specify different userid than theirs
243 rights, or regular users that cannot specify different userid than theirs
222
244
223
245
224 INPUT::
246 INPUT::
225
247
226 id : <id_for_response>
248 id : <id_for_response>
227 api_key : "<api_key>"
249 api_key : "<api_key>"
228 method : "get_user"
250 method : "get_user"
229 args : {
251 args : {
230 "userid" : "<username or user_id Optional(=apiuser)>"
252 "userid" : "<username or user_id Optional(=apiuser)>"
231 }
253 }
232
254
233 OUTPUT::
255 OUTPUT::
234
256
235 id : <id_given_in_input>
257 id : <id_given_in_input>
236 result: None if user does not exist or
258 result: None if user does not exist or
237 {
259 {
238 "user_id" : "<user_id>",
260 "user_id" : "<user_id>",
239 "api_key" : "<api_key>",
261 "api_key" : "<api_key>",
240 "username" : "<username>",
262 "username" : "<username>",
241 "firstname": "<firstname>",
263 "firstname": "<firstname>",
242 "lastname" : "<lastname>",
264 "lastname" : "<lastname>",
243 "email" : "<email>",
265 "email" : "<email>",
244 "emails": "<list_of_all_additional_emails>",
266 "emails": "<list_of_all_additional_emails>",
245 "ip_addresses": "<list_of_ip_addresses_for_user>",
267 "ip_addresses": "<list_of_ip_addresses_for_user>",
246 "active" : "<bool>",
268 "active" : "<bool>",
247 "admin" :Β  "<bool>",
269 "admin" :Β  "<bool>",
248 "ldap_dn" : "<ldap_dn>",
270 "ldap_dn" : "<ldap_dn>",
249 "last_login": "<last_login>",
271 "last_login": "<last_login>",
250 "permissions": {
272 "permissions": {
251 "global": ["hg.create.repository",
273 "global": ["hg.create.repository",
252 "repository.read",
274 "repository.read",
253 "hg.register.manual_activate"],
275 "hg.register.manual_activate"],
254 "repositories": {"repo1": "repository.none"},
276 "repositories": {"repo1": "repository.none"},
255 "repositories_groups": {"Group1": "group.read"}
277 "repositories_groups": {"Group1": "group.read"}
256 },
278 },
257 }
279 }
258
280
259 error: null
281 error: null
260
282
261
283
262 get_users
284 get_users
263 ---------
285 ---------
264
286
265 Lists all existing users. This command can be executed only using api_key
287 Lists all existing users. This command can be executed only using api_key
266 belonging to user with admin rights.
288 belonging to user with admin rights.
267
289
268
290
269 INPUT::
291 INPUT::
270
292
271 id : <id_for_response>
293 id : <id_for_response>
272 api_key : "<api_key>"
294 api_key : "<api_key>"
273 method : "get_users"
295 method : "get_users"
274 args : { }
296 args : { }
275
297
276 OUTPUT::
298 OUTPUT::
277
299
278 id : <id_given_in_input>
300 id : <id_given_in_input>
279 result: [
301 result: [
280 {
302 {
281 "user_id" : "<user_id>",
303 "user_id" : "<user_id>",
282 "username" : "<username>",
304 "username" : "<username>",
283 "firstname": "<firstname>",
305 "firstname": "<firstname>",
284 "lastname" : "<lastname>",
306 "lastname" : "<lastname>",
285 "email" : "<email>",
307 "email" : "<email>",
286 "emails": "<list_of_all_additional_emails>",
308 "emails": "<list_of_all_additional_emails>",
287 "ip_addresses": "<list_of_ip_addresses_for_user>",
309 "ip_addresses": "<list_of_ip_addresses_for_user>",
288 "active" : "<bool>",
310 "active" : "<bool>",
289 "admin" :Β  "<bool>",
311 "admin" :Β  "<bool>",
290 "ldap_dn" : "<ldap_dn>",
312 "ldap_dn" : "<ldap_dn>",
291 "last_login": "<last_login>",
313 "last_login": "<last_login>",
292 },
314 },
293 …
315 …
294 ]
316 ]
295 error: null
317 error: null
296
318
297
319
298 create_user
320 create_user
299 -----------
321 -----------
300
322
301 Creates new user. This command can
323 Creates new user. This command can
302 be executed only using api_key belonging to user with admin rights.
324 be executed only using api_key belonging to user with admin rights.
303
325
304
326
305 INPUT::
327 INPUT::
306
328
307 id : <id_for_response>
329 id : <id_for_response>
308 api_key : "<api_key>"
330 api_key : "<api_key>"
309 method : "create_user"
331 method : "create_user"
310 args : {
332 args : {
311 "username" : "<username>",
333 "username" : "<username>",
312 "email" : "<useremail>",
334 "email" : "<useremail>",
313 "password" : "<password>",
335 "password" : "<password>",
314 "firstname" : "<firstname> = Optional(None)",
336 "firstname" : "<firstname> = Optional(None)",
315 "lastname" : "<lastname> = Optional(None)",
337 "lastname" : "<lastname> = Optional(None)",
316 "active" : "<bool> = Optional(True)",
338 "active" : "<bool> = Optional(True)",
317 "admin" : "<bool> = Optional(False)",
339 "admin" : "<bool> = Optional(False)",
318 "ldap_dn" : "<ldap_dn> = Optional(None)"
340 "ldap_dn" : "<ldap_dn> = Optional(None)"
319 }
341 }
320
342
321 OUTPUT::
343 OUTPUT::
322
344
323 id : <id_given_in_input>
345 id : <id_given_in_input>
324 result: {
346 result: {
325 "msg" : "created new user `<username>`",
347 "msg" : "created new user `<username>`",
326 "user": {
348 "user": {
327 "user_id" : "<user_id>",
349 "user_id" : "<user_id>",
328 "username" : "<username>",
350 "username" : "<username>",
329 "firstname": "<firstname>",
351 "firstname": "<firstname>",
330 "lastname" : "<lastname>",
352 "lastname" : "<lastname>",
331 "email" : "<email>",
353 "email" : "<email>",
332 "emails": "<list_of_all_additional_emails>",
354 "emails": "<list_of_all_additional_emails>",
333 "active" : "<bool>",
355 "active" : "<bool>",
334 "admin" :Β  "<bool>",
356 "admin" :Β  "<bool>",
335 "ldap_dn" : "<ldap_dn>",
357 "ldap_dn" : "<ldap_dn>",
336 "last_login": "<last_login>",
358 "last_login": "<last_login>",
337 },
359 },
338 }
360 }
339 error: null
361 error: null
340
362
341
363
342 update_user
364 update_user
343 -----------
365 -----------
344
366
345 updates given user if such user exists. This command can
367 updates given user if such user exists. This command can
346 be executed only using api_key belonging to user with admin rights.
368 be executed only using api_key belonging to user with admin rights.
347
369
348
370
349 INPUT::
371 INPUT::
350
372
351 id : <id_for_response>
373 id : <id_for_response>
352 api_key : "<api_key>"
374 api_key : "<api_key>"
353 method : "update_user"
375 method : "update_user"
354 args : {
376 args : {
355 "userid" : "<user_id or username>",
377 "userid" : "<user_id or username>",
356 "username" : "<username> = Optional(None)",
378 "username" : "<username> = Optional(None)",
357 "email" : "<useremail> = Optional(None)",
379 "email" : "<useremail> = Optional(None)",
358 "password" : "<password> = Optional(None)",
380 "password" : "<password> = Optional(None)",
359 "firstname" : "<firstname> = Optional(None)",
381 "firstname" : "<firstname> = Optional(None)",
360 "lastname" : "<lastname> = Optional(None)",
382 "lastname" : "<lastname> = Optional(None)",
361 "active" : "<bool> = Optional(None)",
383 "active" : "<bool> = Optional(None)",
362 "admin" : "<bool> = Optional(None)",
384 "admin" : "<bool> = Optional(None)",
363 "ldap_dn" : "<ldap_dn> = Optional(None)"
385 "ldap_dn" : "<ldap_dn> = Optional(None)"
364 }
386 }
365
387
366 OUTPUT::
388 OUTPUT::
367
389
368 id : <id_given_in_input>
390 id : <id_given_in_input>
369 result: {
391 result: {
370 "msg" : "updated user ID:<userid> <username>",
392 "msg" : "updated user ID:<userid> <username>",
371 "user": {
393 "user": {
372 "user_id" : "<user_id>",
394 "user_id" : "<user_id>",
373 "username" : "<username>",
395 "username" : "<username>",
374 "firstname": "<firstname>",
396 "firstname": "<firstname>",
375 "lastname" : "<lastname>",
397 "lastname" : "<lastname>",
376 "email" : "<email>",
398 "email" : "<email>",
377 "emails": "<list_of_all_additional_emails>",
399 "emails": "<list_of_all_additional_emails>",
378 "active" : "<bool>",
400 "active" : "<bool>",
379 "admin" :Β  "<bool>",
401 "admin" :Β  "<bool>",
380 "ldap_dn" : "<ldap_dn>",
402 "ldap_dn" : "<ldap_dn>",
381 "last_login": "<last_login>",
403 "last_login": "<last_login>",
382 },
404 },
383 }
405 }
384 error: null
406 error: null
385
407
386
408
387 delete_user
409 delete_user
388 -----------
410 -----------
389
411
390
412
391 deletes givenuser if such user exists. This command can
413 deletes givenuser if such user exists. This command can
392 be executed only using api_key belonging to user with admin rights.
414 be executed only using api_key belonging to user with admin rights.
393
415
394
416
395 INPUT::
417 INPUT::
396
418
397 id : <id_for_response>
419 id : <id_for_response>
398 api_key : "<api_key>"
420 api_key : "<api_key>"
399 method : "delete_user"
421 method : "delete_user"
400 args : {
422 args : {
401 "userid" : "<user_id or username>",
423 "userid" : "<user_id or username>",
402 }
424 }
403
425
404 OUTPUT::
426 OUTPUT::
405
427
406 id : <id_given_in_input>
428 id : <id_given_in_input>
407 result: {
429 result: {
408 "msg" : "deleted user ID:<userid> <username>",
430 "msg" : "deleted user ID:<userid> <username>",
409 "user": null
431 "user": null
410 }
432 }
411 error: null
433 error: null
412
434
413
435
414 get_users_group
436 get_users_group
415 ---------------
437 ---------------
416
438
417 Gets an existing users group. This command can be executed only using api_key
439 Gets an existing users group. This command can be executed only using api_key
418 belonging to user with admin rights.
440 belonging to user with admin rights.
419
441
420
442
421 INPUT::
443 INPUT::
422
444
423 id : <id_for_response>
445 id : <id_for_response>
424 api_key : "<api_key>"
446 api_key : "<api_key>"
425 method : "get_users_group"
447 method : "get_users_group"
426 args : {
448 args : {
427 "usersgroupid" : "<users group id or name>"
449 "usersgroupid" : "<users group id or name>"
428 }
450 }
429
451
430 OUTPUT::
452 OUTPUT::
431
453
432 id : <id_given_in_input>
454 id : <id_given_in_input>
433 result : None if group not exist
455 result : None if group not exist
434 {
456 {
435 "users_group_id" : "<id>",
457 "users_group_id" : "<id>",
436 "group_name" : "<groupname>",
458 "group_name" : "<groupname>",
437 "active": "<bool>",
459 "active": "<bool>",
438 "members" : [
460 "members" : [
439 {
461 {
440 "user_id" : "<user_id>",
462 "user_id" : "<user_id>",
441 "username" : "<username>",
463 "username" : "<username>",
442 "firstname": "<firstname>",
464 "firstname": "<firstname>",
443 "lastname" : "<lastname>",
465 "lastname" : "<lastname>",
444 "email" : "<email>",
466 "email" : "<email>",
445 "emails": "<list_of_all_additional_emails>",
467 "emails": "<list_of_all_additional_emails>",
446 "active" : "<bool>",
468 "active" : "<bool>",
447 "admin" :Β  "<bool>",
469 "admin" :Β  "<bool>",
448 "ldap_dn" : "<ldap_dn>",
470 "ldap_dn" : "<ldap_dn>",
449 "last_login": "<last_login>",
471 "last_login": "<last_login>",
450 },
472 },
451 …
473 …
452 ]
474 ]
453 }
475 }
454 error : null
476 error : null
455
477
456
478
457 get_users_groups
479 get_users_groups
458 ----------------
480 ----------------
459
481
460 Lists all existing users groups. This command can be executed only using
482 Lists all existing users groups. This command can be executed only using
461 api_key belonging to user with admin rights.
483 api_key belonging to user with admin rights.
462
484
463
485
464 INPUT::
486 INPUT::
465
487
466 id : <id_for_response>
488 id : <id_for_response>
467 api_key : "<api_key>"
489 api_key : "<api_key>"
468 method : "get_users_groups"
490 method : "get_users_groups"
469 args : { }
491 args : { }
470
492
471 OUTPUT::
493 OUTPUT::
472
494
473 id : <id_given_in_input>
495 id : <id_given_in_input>
474 result : [
496 result : [
475 {
497 {
476 "users_group_id" : "<id>",
498 "users_group_id" : "<id>",
477 "group_name" : "<groupname>",
499 "group_name" : "<groupname>",
478 "active": "<bool>",
500 "active": "<bool>",
479 },
501 },
480 …
502 …
481 ]
503 ]
482 error : null
504 error : null
483
505
484
506
485 create_users_group
507 create_users_group
486 ------------------
508 ------------------
487
509
488 Creates new users group. This command can be executed only using api_key
510 Creates new users group. This command can be executed only using api_key
489 belonging to user with admin rights
511 belonging to user with admin rights
490
512
491
513
492 INPUT::
514 INPUT::
493
515
494 id : <id_for_response>
516 id : <id_for_response>
495 api_key : "<api_key>"
517 api_key : "<api_key>"
496 method : "create_users_group"
518 method : "create_users_group"
497 args: {
519 args: {
498 "group_name": "<groupname>",
520 "group_name": "<groupname>",
499 "active":"<bool> = Optional(True)"
521 "active":"<bool> = Optional(True)"
500 }
522 }
501
523
502 OUTPUT::
524 OUTPUT::
503
525
504 id : <id_given_in_input>
526 id : <id_given_in_input>
505 result: {
527 result: {
506 "msg": "created new users group `<groupname>`",
528 "msg": "created new users group `<groupname>`",
507 "users_group": {
529 "users_group": {
508 "users_group_id" : "<id>",
530 "users_group_id" : "<id>",
509 "group_name" : "<groupname>",
531 "group_name" : "<groupname>",
510 "active": "<bool>",
532 "active": "<bool>",
511 },
533 },
512 }
534 }
513 error: null
535 error: null
514
536
515
537
516 add_user_to_users_group
538 add_user_to_users_group
517 -----------------------
539 -----------------------
518
540
519 Adds a user to a users group. If user exists in that group success will be
541 Adds a user to a users group. If user exists in that group success will be
520 `false`. This command can be executed only using api_key
542 `false`. This command can be executed only using api_key
521 belonging to user with admin rights
543 belonging to user with admin rights
522
544
523
545
524 INPUT::
546 INPUT::
525
547
526 id : <id_for_response>
548 id : <id_for_response>
527 api_key : "<api_key>"
549 api_key : "<api_key>"
528 method : "add_user_users_group"
550 method : "add_user_users_group"
529 args: {
551 args: {
530 "usersgroupid" : "<users group id or name>",
552 "usersgroupid" : "<users group id or name>",
531 "userid" : "<user_id or username>",
553 "userid" : "<user_id or username>",
532 }
554 }
533
555
534 OUTPUT::
556 OUTPUT::
535
557
536 id : <id_given_in_input>
558 id : <id_given_in_input>
537 result: {
559 result: {
538 "success": True|False # depends on if member is in group
560 "success": True|False # depends on if member is in group
539 "msg": "added member `<username>` to users group `<groupname>` |
561 "msg": "added member `<username>` to users group `<groupname>` |
540 User is already in that group"
562 User is already in that group"
541 }
563 }
542 error: null
564 error: null
543
565
544
566
545 remove_user_from_users_group
567 remove_user_from_users_group
546 ----------------------------
568 ----------------------------
547
569
548 Removes a user from a users group. If user is not in given group success will
570 Removes a user from a users group. If user is not in given group success will
549 be `false`. This command can be executed only
571 be `false`. This command can be executed only
550 using api_key belonging to user with admin rights
572 using api_key belonging to user with admin rights
551
573
552
574
553 INPUT::
575 INPUT::
554
576
555 id : <id_for_response>
577 id : <id_for_response>
556 api_key : "<api_key>"
578 api_key : "<api_key>"
557 method : "remove_user_from_users_group"
579 method : "remove_user_from_users_group"
558 args: {
580 args: {
559 "usersgroupid" : "<users group id or name>",
581 "usersgroupid" : "<users group id or name>",
560 "userid" : "<user_id or username>",
582 "userid" : "<user_id or username>",
561 }
583 }
562
584
563 OUTPUT::
585 OUTPUT::
564
586
565 id : <id_given_in_input>
587 id : <id_given_in_input>
566 result: {
588 result: {
567 "success": True|False, # depends on if member is in group
589 "success": True|False, # depends on if member is in group
568 "msg": "removed member <username> from users group <groupname> |
590 "msg": "removed member <username> from users group <groupname> |
569 User wasn't in group"
591 User wasn't in group"
570 }
592 }
571 error: null
593 error: null
572
594
573
595
574 get_repo
596 get_repo
575 --------
597 --------
576
598
577 Gets an existing repository by it's name or repository_id. Members will return
599 Gets an existing repository by it's name or repository_id. Members will return
578 either users_group or user associated to that repository. This command can be
600 either users_group or user associated to that repository. This command can be
579 executed only using api_key belonging to user with admin
601 executed only using api_key belonging to user with admin
580 rights or regular user that have at least read access to repository.
602 rights or regular user that have at least read access to repository.
581
603
582
604
583 INPUT::
605 INPUT::
584
606
585 id : <id_for_response>
607 id : <id_for_response>
586 api_key : "<api_key>"
608 api_key : "<api_key>"
587 method : "get_repo"
609 method : "get_repo"
588 args: {
610 args: {
589 "repoid" : "<reponame or repo_id>"
611 "repoid" : "<reponame or repo_id>"
590 }
612 }
591
613
592 OUTPUT::
614 OUTPUT::
593
615
594 id : <id_given_in_input>
616 id : <id_given_in_input>
595 result: None if repository does not exist or
617 result: None if repository does not exist or
596 {
618 {
597 "repo_id" : "<repo_id>",
619 "repo_id" : "<repo_id>",
598 "repo_name" : "<reponame>"
620 "repo_name" : "<reponame>"
599 "repo_type" : "<repo_type>",
621 "repo_type" : "<repo_type>",
600 "clone_uri" : "<clone_uri>",
622 "clone_uri" : "<clone_uri>",
601 "enable_downloads": "<bool>",
623 "enable_downloads": "<bool>",
602 "enable_locking": "<bool>",
624 "enable_locking": "<bool>",
603 "enable_statistics": "<bool>",
625 "enable_statistics": "<bool>",
604 "private": "<bool>",
626 "private": "<bool>",
605 "created_on" : "<date_time_created>",
627 "created_on" : "<date_time_created>",
606 "description" : "<description>",
628 "description" : "<description>",
607 "landing_rev": "<landing_rev>",
629 "landing_rev": "<landing_rev>",
608 "last_changeset": {
630 "last_changeset": {
609 "author": "<full_author>",
631 "author": "<full_author>",
610 "date": "<date_time_of_commit>",
632 "date": "<date_time_of_commit>",
611 "message": "<commit_message>",
633 "message": "<commit_message>",
612 "raw_id": "<raw_id>",
634 "raw_id": "<raw_id>",
613 "revision": "<numeric_revision>",
635 "revision": "<numeric_revision>",
614 "short_id": "<short_id>"
636 "short_id": "<short_id>"
615 }
637 }
616 "owner": "<repo_owner>",
638 "owner": "<repo_owner>",
617 "fork_of": "<name_of_fork_parent>",
639 "fork_of": "<name_of_fork_parent>",
618 "members" : [
640 "members" : [
619 {
641 {
620 "type": "user",
642 "type": "user",
621 "user_id" : "<user_id>",
643 "user_id" : "<user_id>",
622 "username" : "<username>",
644 "username" : "<username>",
623 "firstname": "<firstname>",
645 "firstname": "<firstname>",
624 "lastname" : "<lastname>",
646 "lastname" : "<lastname>",
625 "email" : "<email>",
647 "email" : "<email>",
626 "emails": "<list_of_all_additional_emails>",
648 "emails": "<list_of_all_additional_emails>",
627 "active" : "<bool>",
649 "active" : "<bool>",
628 "admin" :Β  "<bool>",
650 "admin" :Β  "<bool>",
629 "ldap_dn" : "<ldap_dn>",
651 "ldap_dn" : "<ldap_dn>",
630 "last_login": "<last_login>",
652 "last_login": "<last_login>",
631 "permission" : "repository.(read|write|admin)"
653 "permission" : "repository.(read|write|admin)"
632 },
654 },
633 …
655 …
634 {
656 {
635 "type": "users_group",
657 "type": "users_group",
636 "id" : "<usersgroupid>",
658 "id" : "<usersgroupid>",
637 "name" : "<usersgroupname>",
659 "name" : "<usersgroupname>",
638 "active": "<bool>",
660 "active": "<bool>",
639 "permission" : "repository.(read|write|admin)"
661 "permission" : "repository.(read|write|admin)"
640 },
662 },
641 …
663 …
642 ]
664 ]
643 "followers": [
665 "followers": [
644 {
666 {
645 "user_id" : "<user_id>",
667 "user_id" : "<user_id>",
646 "username" : "<username>",
668 "username" : "<username>",
647 "firstname": "<firstname>",
669 "firstname": "<firstname>",
648 "lastname" : "<lastname>",
670 "lastname" : "<lastname>",
649 "email" : "<email>",
671 "email" : "<email>",
650 "emails": "<list_of_all_additional_emails>",
672 "emails": "<list_of_all_additional_emails>",
651 "ip_addresses": "<list_of_ip_addresses_for_user>",
673 "ip_addresses": "<list_of_ip_addresses_for_user>",
652 "active" : "<bool>",
674 "active" : "<bool>",
653 "admin" :Β  "<bool>",
675 "admin" :Β  "<bool>",
654 "ldap_dn" : "<ldap_dn>",
676 "ldap_dn" : "<ldap_dn>",
655 "last_login": "<last_login>",
677 "last_login": "<last_login>",
656 },
678 },
657 …
679 …
658 ]
680 ]
659 }
681 }
660 error: null
682 error: null
661
683
662
684
663 get_repos
685 get_repos
664 ---------
686 ---------
665
687
666 Lists all existing repositories. This command can be executed only using
688 Lists all existing repositories. This command can be executed only using
667 api_key belonging to user with admin rights or regular user that have
689 api_key belonging to user with admin rights or regular user that have
668 admin, write or read access to repository.
690 admin, write or read access to repository.
669
691
670
692
671 INPUT::
693 INPUT::
672
694
673 id : <id_for_response>
695 id : <id_for_response>
674 api_key : "<api_key>"
696 api_key : "<api_key>"
675 method : "get_repos"
697 method : "get_repos"
676 args: { }
698 args: { }
677
699
678 OUTPUT::
700 OUTPUT::
679
701
680 id : <id_given_in_input>
702 id : <id_given_in_input>
681 result: [
703 result: [
682 {
704 {
683 "repo_id" : "<repo_id>",
705 "repo_id" : "<repo_id>",
684 "repo_name" : "<reponame>"
706 "repo_name" : "<reponame>"
685 "repo_type" : "<repo_type>",
707 "repo_type" : "<repo_type>",
686 "clone_uri" : "<clone_uri>",
708 "clone_uri" : "<clone_uri>",
687 "private": : "<bool>",
709 "private": : "<bool>",
688 "created_on" : "<datetimecreated>",
710 "created_on" : "<datetimecreated>",
689 "description" : "<description>",
711 "description" : "<description>",
690 "landing_rev": "<landing_rev>",
712 "landing_rev": "<landing_rev>",
691 "owner": "<repo_owner>",
713 "owner": "<repo_owner>",
692 "fork_of": "<name_of_fork_parent>",
714 "fork_of": "<name_of_fork_parent>",
693 "enable_downloads": "<bool>",
715 "enable_downloads": "<bool>",
694 "enable_locking": "<bool>",
716 "enable_locking": "<bool>",
695 "enable_statistics": "<bool>",
717 "enable_statistics": "<bool>",
696 },
718 },
697 …
719 …
698 ]
720 ]
699 error: null
721 error: null
700
722
701
723
702 get_repo_nodes
724 get_repo_nodes
703 --------------
725 --------------
704
726
705 returns a list of nodes and it's children in a flat list for a given path
727 returns a list of nodes and it's children in a flat list for a given path
706 at given revision. It's possible to specify ret_type to show only `files` or
728 at given revision. It's possible to specify ret_type to show only `files` or
707 `dirs`. This command can be executed only using api_key belonging to user
729 `dirs`. This command can be executed only using api_key belonging to user
708 with admin rights
730 with admin rights
709
731
710
732
711 INPUT::
733 INPUT::
712
734
713 id : <id_for_response>
735 id : <id_for_response>
714 api_key : "<api_key>"
736 api_key : "<api_key>"
715 method : "get_repo_nodes"
737 method : "get_repo_nodes"
716 args: {
738 args: {
717 "repoid" : "<reponame or repo_id>"
739 "repoid" : "<reponame or repo_id>"
718 "revision" : "<revision>",
740 "revision" : "<revision>",
719 "root_path" : "<root_path>",
741 "root_path" : "<root_path>",
720 "ret_type" : "<ret_type> = Optional('all')"
742 "ret_type" : "<ret_type> = Optional('all')"
721 }
743 }
722
744
723 OUTPUT::
745 OUTPUT::
724
746
725 id : <id_given_in_input>
747 id : <id_given_in_input>
726 result: [
748 result: [
727 {
749 {
728 "name" : "<name>"
750 "name" : "<name>"
729 "type" : "<type>",
751 "type" : "<type>",
730 },
752 },
731 …
753 …
732 ]
754 ]
733 error: null
755 error: null
734
756
735
757
736 create_repo
758 create_repo
737 -----------
759 -----------
738
760
739 Creates a repository. If repository name contains "/", all needed repository
761 Creates a repository. If repository name contains "/", all needed repository
740 groups will be created. For example "foo/bar/baz" will create groups
762 groups will be created. For example "foo/bar/baz" will create groups
741 "foo", "bar" (with "foo" as parent), and create "baz" repository with
763 "foo", "bar" (with "foo" as parent), and create "baz" repository with
742 "bar" as group. This command can be executed only using api_key belonging to user with admin
764 "bar" as group. This command can be executed only using api_key belonging to user with admin
743 rights or regular user that have create repository permission. Regular users
765 rights or regular user that have create repository permission. Regular users
744 cannot specify owner parameter
766 cannot specify owner parameter
745
767
746
768
747 INPUT::
769 INPUT::
748
770
749 id : <id_for_response>
771 id : <id_for_response>
750 api_key : "<api_key>"
772 api_key : "<api_key>"
751 method : "create_repo"
773 method : "create_repo"
752 args: {
774 args: {
753 "repo_name" : "<reponame>",
775 "repo_name" : "<reponame>",
754 "owner" : "<onwer_name_or_id = Optional(=apiuser)>",
776 "owner" : "<onwer_name_or_id = Optional(=apiuser)>",
755 "repo_type" : "<repo_type> = Optional('hg')",
777 "repo_type" : "<repo_type> = Optional('hg')",
756 "description" : "<description> = Optional('')",
778 "description" : "<description> = Optional('')",
757 "private" : "<bool> = Optional(False)",
779 "private" : "<bool> = Optional(False)",
758 "clone_uri" : "<clone_uri> = Optional(None)",
780 "clone_uri" : "<clone_uri> = Optional(None)",
759 "landing_rev" : "<landing_rev> = Optional('tip')",
781 "landing_rev" : "<landing_rev> = Optional('tip')",
760 "enable_downloads": "<bool> = Optional(False)",
782 "enable_downloads": "<bool> = Optional(False)",
761 "enable_locking": "<bool> = Optional(False)",
783 "enable_locking": "<bool> = Optional(False)",
762 "enable_statistics": "<bool> = Optional(False)",
784 "enable_statistics": "<bool> = Optional(False)",
763 }
785 }
764
786
765 OUTPUT::
787 OUTPUT::
766
788
767 id : <id_given_in_input>
789 id : <id_given_in_input>
768 result: {
790 result: {
769 "msg": "Created new repository `<reponame>`",
791 "msg": "Created new repository `<reponame>`",
770 "repo": {
792 "repo": {
771 "repo_id" : "<repo_id>",
793 "repo_id" : "<repo_id>",
772 "repo_name" : "<reponame>"
794 "repo_name" : "<reponame>"
773 "repo_type" : "<repo_type>",
795 "repo_type" : "<repo_type>",
774 "clone_uri" : "<clone_uri>",
796 "clone_uri" : "<clone_uri>",
775 "private": : "<bool>",
797 "private": : "<bool>",
776 "created_on" : "<datetimecreated>",
798 "created_on" : "<datetimecreated>",
777 "description" : "<description>",
799 "description" : "<description>",
778 "landing_rev": "<landing_rev>",
800 "landing_rev": "<landing_rev>",
779 "owner": "<username or user_id>",
801 "owner": "<username or user_id>",
780 "fork_of": "<name_of_fork_parent>",
802 "fork_of": "<name_of_fork_parent>",
781 "enable_downloads": "<bool>",
803 "enable_downloads": "<bool>",
782 "enable_locking": "<bool>",
804 "enable_locking": "<bool>",
783 "enable_statistics": "<bool>",
805 "enable_statistics": "<bool>",
784 },
806 },
785 }
807 }
786 error: null
808 error: null
787
809
788
810
789 fork_repo
811 fork_repo
790 ---------
812 ---------
791
813
792 Creates a fork of given repo. In case of using celery this will
814 Creates a fork of given repo. In case of using celery this will
793 immidiatelly return success message, while fork is going to be created
815 immidiatelly return success message, while fork is going to be created
794 asynchronous. This command can be executed only using api_key belonging to
816 asynchronous. This command can be executed only using api_key belonging to
795 user with admin rights or regular user that have fork permission, and at least
817 user with admin rights or regular user that have fork permission, and at least
796 read access to forking repository. Regular users cannot specify owner parameter.
818 read access to forking repository. Regular users cannot specify owner parameter.
797
819
798
820
799 INPUT::
821 INPUT::
800
822
801 id : <id_for_response>
823 id : <id_for_response>
802 api_key : "<api_key>"
824 api_key : "<api_key>"
803 method : "fork_repo"
825 method : "fork_repo"
804 args: {
826 args: {
805 "repoid" : "<reponame or repo_id>",
827 "repoid" : "<reponame or repo_id>",
806 "fork_name": "<forkname>",
828 "fork_name": "<forkname>",
807 "owner": "<username or user_id = Optional(=apiuser)>",
829 "owner": "<username or user_id = Optional(=apiuser)>",
808 "description": "<description>",
830 "description": "<description>",
809 "copy_permissions": "<bool>",
831 "copy_permissions": "<bool>",
810 "private": "<bool>",
832 "private": "<bool>",
811 "landing_rev": "<landing_rev>"
833 "landing_rev": "<landing_rev>"
812
834
813 }
835 }
814
836
815 OUTPUT::
837 OUTPUT::
816
838
817 id : <id_given_in_input>
839 id : <id_given_in_input>
818 result: {
840 result: {
819 "msg": "Created fork of `<reponame>` as `<forkname>`",
841 "msg": "Created fork of `<reponame>` as `<forkname>`",
820 "success": true
842 "success": true
821 }
843 }
822 error: null
844 error: null
823
845
824
846
825 delete_repo
847 delete_repo
826 -----------
848 -----------
827
849
828 Deletes a repository. This command can be executed only using api_key belonging to user with admin
850 Deletes a repository. This command can be executed only using api_key belonging to user with admin
829 rights or regular user that have admin access to repository.
851 rights or regular user that have admin access to repository.
830
852
831
853
832 INPUT::
854 INPUT::
833
855
834 id : <id_for_response>
856 id : <id_for_response>
835 api_key : "<api_key>"
857 api_key : "<api_key>"
836 method : "delete_repo"
858 method : "delete_repo"
837 args: {
859 args: {
838 "repoid" : "<reponame or repo_id>"
860 "repoid" : "<reponame or repo_id>"
839 }
861 }
840
862
841 OUTPUT::
863 OUTPUT::
842
864
843 id : <id_given_in_input>
865 id : <id_given_in_input>
844 result: {
866 result: {
845 "msg": "Deleted repository `<reponame>`",
867 "msg": "Deleted repository `<reponame>`",
846 "success": true
868 "success": true
847 }
869 }
848 error: null
870 error: null
849
871
850
872
851 grant_user_permission
873 grant_user_permission
852 ---------------------
874 ---------------------
853
875
854 Grant permission for user on given repository, or update existing one
876 Grant permission for user on given repository, or update existing one
855 if found. This command can be executed only using api_key belonging to user
877 if found. This command can be executed only using api_key belonging to user
856 with admin rights.
878 with admin rights.
857
879
858
880
859 INPUT::
881 INPUT::
860
882
861 id : <id_for_response>
883 id : <id_for_response>
862 api_key : "<api_key>"
884 api_key : "<api_key>"
863 method : "grant_user_permission"
885 method : "grant_user_permission"
864 args: {
886 args: {
865 "repoid" : "<reponame or repo_id>"
887 "repoid" : "<reponame or repo_id>"
866 "userid" : "<username or user_id>"
888 "userid" : "<username or user_id>"
867 "perm" : "(repository.(none|read|write|admin))",
889 "perm" : "(repository.(none|read|write|admin))",
868 }
890 }
869
891
870 OUTPUT::
892 OUTPUT::
871
893
872 id : <id_given_in_input>
894 id : <id_given_in_input>
873 result: {
895 result: {
874 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
896 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
875 "success": true
897 "success": true
876 }
898 }
877 error: null
899 error: null
878
900
879
901
880 revoke_user_permission
902 revoke_user_permission
881 ----------------------
903 ----------------------
882
904
883 Revoke permission for user on given repository. This command can be executed
905 Revoke permission for user on given repository. This command can be executed
884 only using api_key belonging to user with admin rights.
906 only using api_key belonging to user with admin rights.
885
907
886
908
887 INPUT::
909 INPUT::
888
910
889 id : <id_for_response>
911 id : <id_for_response>
890 api_key : "<api_key>"
912 api_key : "<api_key>"
891 method : "revoke_user_permission"
913 method : "revoke_user_permission"
892 args: {
914 args: {
893 "repoid" : "<reponame or repo_id>"
915 "repoid" : "<reponame or repo_id>"
894 "userid" : "<username or user_id>"
916 "userid" : "<username or user_id>"
895 }
917 }
896
918
897 OUTPUT::
919 OUTPUT::
898
920
899 id : <id_given_in_input>
921 id : <id_given_in_input>
900 result: {
922 result: {
901 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
923 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
902 "success": true
924 "success": true
903 }
925 }
904 error: null
926 error: null
905
927
906
928
907 grant_users_group_permission
929 grant_users_group_permission
908 ----------------------------
930 ----------------------------
909
931
910 Grant permission for users group on given repository, or update
932 Grant permission for users group on given repository, or update
911 existing one if found. This command can be executed only using
933 existing one if found. This command can be executed only using
912 api_key belonging to user with admin rights.
934 api_key belonging to user with admin rights.
913
935
914
936
915 INPUT::
937 INPUT::
916
938
917 id : <id_for_response>
939 id : <id_for_response>
918 api_key : "<api_key>"
940 api_key : "<api_key>"
919 method : "grant_users_group_permission"
941 method : "grant_users_group_permission"
920 args: {
942 args: {
921 "repoid" : "<reponame or repo_id>"
943 "repoid" : "<reponame or repo_id>"
922 "usersgroupid" : "<users group id or name>"
944 "usersgroupid" : "<users group id or name>"
923 "perm" : "(repository.(none|read|write|admin))",
945 "perm" : "(repository.(none|read|write|admin))",
924 }
946 }
925
947
926 OUTPUT::
948 OUTPUT::
927
949
928 id : <id_given_in_input>
950 id : <id_given_in_input>
929 result: {
951 result: {
930 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
952 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
931 "success": true
953 "success": true
932 }
954 }
933 error: null
955 error: null
934
956
935
957
936 revoke_users_group_permission
958 revoke_users_group_permission
937 -----------------------------
959 -----------------------------
938
960
939 Revoke permission for users group on given repository.This command can be
961 Revoke permission for users group on given repository.This command can be
940 executed only using api_key belonging to user with admin rights.
962 executed only using api_key belonging to user with admin rights.
941
963
942 INPUT::
964 INPUT::
943
965
944 id : <id_for_response>
966 id : <id_for_response>
945 api_key : "<api_key>"
967 api_key : "<api_key>"
946 method : "revoke_users_group_permission"
968 method : "revoke_users_group_permission"
947 args: {
969 args: {
948 "repoid" : "<reponame or repo_id>"
970 "repoid" : "<reponame or repo_id>"
949 "usersgroupid" : "<users group id or name>"
971 "usersgroupid" : "<users group id or name>"
950 }
972 }
951
973
952 OUTPUT::
974 OUTPUT::
953
975
954 id : <id_given_in_input>
976 id : <id_given_in_input>
955 result: {
977 result: {
956 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
978 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
957 "success": true
979 "success": true
958 }
980 }
959 error: null
981 error: null
@@ -1,932 +1,958 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.api
3 rhodecode.controllers.api
4 ~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 API controller for RhodeCode
6 API controller for RhodeCode
7
7
8 :created_on: Aug 20, 2011
8 :created_on: Aug 20, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software; you can redistribute it and/or
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import traceback
28 import traceback
29 import logging
29 import logging
30 from pylons.controllers.util import abort
30 from pylons.controllers.util import abort
31
31
32 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
32 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
33 from rhodecode.lib.auth import PasswordGenerator, AuthUser, \
33 from rhodecode.lib.auth import PasswordGenerator, AuthUser, \
34 HasPermissionAllDecorator, HasPermissionAnyDecorator, \
34 HasPermissionAllDecorator, HasPermissionAnyDecorator, \
35 HasPermissionAnyApi, HasRepoPermissionAnyApi
35 HasPermissionAnyApi, HasRepoPermissionAnyApi
36 from rhodecode.lib.utils import map_groups, repo2db_mapper
36 from rhodecode.lib.utils import map_groups, repo2db_mapper
37 from rhodecode.model.meta import Session
37 from rhodecode.model.meta import Session
38 from rhodecode.model.scm import ScmModel
38 from rhodecode.model.scm import ScmModel
39 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.repo import RepoModel
40 from rhodecode.model.user import UserModel
40 from rhodecode.model.user import UserModel
41 from rhodecode.model.users_group import UsersGroupModel
41 from rhodecode.model.users_group import UsersGroupModel
42 from rhodecode.model.permission import PermissionModel
42 from rhodecode.model.permission import PermissionModel
43 from rhodecode.model.db import Repository, RhodeCodeSetting, UserIpMap
43 from rhodecode.model.db import Repository, RhodeCodeSetting, UserIpMap
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 class OptionalAttr(object):
48 class OptionalAttr(object):
49 """
49 """
50 Special Optional Option that defines other attribute
50 Special Optional Option that defines other attribute
51 """
51 """
52 def __init__(self, attr_name):
52 def __init__(self, attr_name):
53 self.attr_name = attr_name
53 self.attr_name = attr_name
54
54
55 def __repr__(self):
55 def __repr__(self):
56 return '<OptionalAttr:%s>' % self.attr_name
56 return '<OptionalAttr:%s>' % self.attr_name
57
57
58 def __call__(self):
58 def __call__(self):
59 return self
59 return self
60 #alias
60 #alias
61 OAttr = OptionalAttr
61 OAttr = OptionalAttr
62
62
63
63
64 class Optional(object):
64 class Optional(object):
65 """
65 """
66 Defines an optional parameter::
66 Defines an optional parameter::
67
67
68 param = param.getval() if isinstance(param, Optional) else param
68 param = param.getval() if isinstance(param, Optional) else param
69 param = param() if isinstance(param, Optional) else param
69 param = param() if isinstance(param, Optional) else param
70
70
71 is equivalent of::
71 is equivalent of::
72
72
73 param = Optional.extract(param)
73 param = Optional.extract(param)
74
74
75 """
75 """
76 def __init__(self, type_):
76 def __init__(self, type_):
77 self.type_ = type_
77 self.type_ = type_
78
78
79 def __repr__(self):
79 def __repr__(self):
80 return '<Optional:%s>' % self.type_.__repr__()
80 return '<Optional:%s>' % self.type_.__repr__()
81
81
82 def __call__(self):
82 def __call__(self):
83 return self.getval()
83 return self.getval()
84
84
85 def getval(self):
85 def getval(self):
86 """
86 """
87 returns value from this Optional instance
87 returns value from this Optional instance
88 """
88 """
89 return self.type_
89 return self.type_
90
90
91 @classmethod
91 @classmethod
92 def extract(cls, val):
92 def extract(cls, val):
93 if isinstance(val, cls):
93 if isinstance(val, cls):
94 return val.getval()
94 return val.getval()
95 return val
95 return val
96
96
97
97
98 def get_user_or_error(userid):
98 def get_user_or_error(userid):
99 """
99 """
100 Get user by id or name or return JsonRPCError if not found
100 Get user by id or name or return JsonRPCError if not found
101
101
102 :param userid:
102 :param userid:
103 """
103 """
104 user = UserModel().get_user(userid)
104 user = UserModel().get_user(userid)
105 if user is None:
105 if user is None:
106 raise JSONRPCError("user `%s` does not exist" % userid)
106 raise JSONRPCError("user `%s` does not exist" % userid)
107 return user
107 return user
108
108
109
109
110 def get_repo_or_error(repoid):
110 def get_repo_or_error(repoid):
111 """
111 """
112 Get repo by id or name or return JsonRPCError if not found
112 Get repo by id or name or return JsonRPCError if not found
113
113
114 :param userid:
114 :param userid:
115 """
115 """
116 repo = RepoModel().get_repo(repoid)
116 repo = RepoModel().get_repo(repoid)
117 if repo is None:
117 if repo is None:
118 raise JSONRPCError('repository `%s` does not exist' % (repoid))
118 raise JSONRPCError('repository `%s` does not exist' % (repoid))
119 return repo
119 return repo
120
120
121
121
122 def get_users_group_or_error(usersgroupid):
122 def get_users_group_or_error(usersgroupid):
123 """
123 """
124 Get users group by id or name or return JsonRPCError if not found
124 Get users group by id or name or return JsonRPCError if not found
125
125
126 :param userid:
126 :param userid:
127 """
127 """
128 users_group = UsersGroupModel().get_group(usersgroupid)
128 users_group = UsersGroupModel().get_group(usersgroupid)
129 if users_group is None:
129 if users_group is None:
130 raise JSONRPCError('users group `%s` does not exist' % usersgroupid)
130 raise JSONRPCError('users group `%s` does not exist' % usersgroupid)
131 return users_group
131 return users_group
132
132
133
133
134 def get_perm_or_error(permid):
134 def get_perm_or_error(permid):
135 """
135 """
136 Get permission by id or name or return JsonRPCError if not found
136 Get permission by id or name or return JsonRPCError if not found
137
137
138 :param userid:
138 :param userid:
139 """
139 """
140 perm = PermissionModel().get_permission_by_name(permid)
140 perm = PermissionModel().get_permission_by_name(permid)
141 if perm is None:
141 if perm is None:
142 raise JSONRPCError('permission `%s` does not exist' % (permid))
142 raise JSONRPCError('permission `%s` does not exist' % (permid))
143 return perm
143 return perm
144
144
145
145
146 class ApiController(JSONRPCController):
146 class ApiController(JSONRPCController):
147 """
147 """
148 API Controller
148 API Controller
149
149
150
150
151 Each method needs to have USER as argument this is then based on given
151 Each method needs to have USER as argument this is then based on given
152 API_KEY propagated as instance of user object
152 API_KEY propagated as instance of user object
153
153
154 Preferably this should be first argument also
154 Preferably this should be first argument also
155
155
156
156
157 Each function should also **raise** JSONRPCError for any
157 Each function should also **raise** JSONRPCError for any
158 errors that happens
158 errors that happens
159
159
160 """
160 """
161
161
162 @HasPermissionAllDecorator('hg.admin')
162 @HasPermissionAllDecorator('hg.admin')
163 def pull(self, apiuser, repoid):
163 def pull(self, apiuser, repoid):
164 """
164 """
165 Dispatch pull action on given repo
165 Dispatch pull action on given repo
166
166
167 :param apiuser:
167 :param apiuser:
168 :param repoid:
168 :param repoid:
169 """
169 """
170
170
171 repo = get_repo_or_error(repoid)
171 repo = get_repo_or_error(repoid)
172
172
173 try:
173 try:
174 ScmModel().pull_changes(repo.repo_name,
174 ScmModel().pull_changes(repo.repo_name,
175 self.rhodecode_user.username)
175 self.rhodecode_user.username)
176 return 'Pulled from `%s`' % repo.repo_name
176 return 'Pulled from `%s`' % repo.repo_name
177 except Exception:
177 except Exception:
178 log.error(traceback.format_exc())
178 log.error(traceback.format_exc())
179 raise JSONRPCError(
179 raise JSONRPCError(
180 'Unable to pull changes from `%s`' % repo.repo_name
180 'Unable to pull changes from `%s`' % repo.repo_name
181 )
181 )
182
182
183 @HasPermissionAllDecorator('hg.admin')
183 @HasPermissionAllDecorator('hg.admin')
184 def rescan_repos(self, apiuser, remove_obsolete=Optional(False)):
184 def rescan_repos(self, apiuser, remove_obsolete=Optional(False)):
185 """
185 """
186 Dispatch rescan repositories action. If remove_obsolete is set
186 Dispatch rescan repositories action. If remove_obsolete is set
187 than also delete repos that are in database but not in the filesystem.
187 than also delete repos that are in database but not in the filesystem.
188 aka "clean zombies"
188 aka "clean zombies"
189
189
190 :param apiuser:
190 :param apiuser:
191 :param remove_obsolete:
191 :param remove_obsolete:
192 """
192 """
193
193
194 try:
194 try:
195 rm_obsolete = Optional.extract(remove_obsolete)
195 rm_obsolete = Optional.extract(remove_obsolete)
196 added, removed = repo2db_mapper(ScmModel().repo_scan(),
196 added, removed = repo2db_mapper(ScmModel().repo_scan(),
197 remove_obsolete=rm_obsolete)
197 remove_obsolete=rm_obsolete)
198 return {'added': added, 'removed': removed}
198 return {'added': added, 'removed': removed}
199 except Exception:
199 except Exception:
200 log.error(traceback.format_exc())
200 log.error(traceback.format_exc())
201 raise JSONRPCError(
201 raise JSONRPCError(
202 'Error occurred during rescan repositories action'
202 'Error occurred during rescan repositories action'
203 )
203 )
204
204
205 def invalidate_cache(self, apiuser, repoid):
206 """
207 Dispatch cache invalidation action on given repo
208
209 :param apiuser:
210 :param repoid:
211 """
212 repo = get_repo_or_error(repoid)
213 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
214 # check if we have admin permission for this repo !
215 if HasRepoPermissionAnyApi('repository.admin',
216 'repository.write')(user=apiuser,
217 repo_name=repo.repo_name) is False:
218 raise JSONRPCError('repository `%s` does not exist' % (repoid))
219
220 try:
221 invalidated_keys = ScmModel().mark_for_invalidation(repo.repo_name)
222 Session().commit()
223 return ('Cache for repository `%s` was invalidated: '
224 'invalidated cache keys: %s' % (repoid, invalidated_keys))
225 except Exception:
226 log.error(traceback.format_exc())
227 raise JSONRPCError(
228 'Error occurred during cache invalidation action'
229 )
230
205 def lock(self, apiuser, repoid, locked, userid=Optional(OAttr('apiuser'))):
231 def lock(self, apiuser, repoid, locked, userid=Optional(OAttr('apiuser'))):
206 """
232 """
207 Set locking state on particular repository by given user, if
233 Set locking state on particular repository by given user, if
208 this command is runned by non-admin account userid is set to user
234 this command is runned by non-admin account userid is set to user
209 who is calling this method
235 who is calling this method
210
236
211 :param apiuser:
237 :param apiuser:
212 :param repoid:
238 :param repoid:
213 :param userid:
239 :param userid:
214 :param locked:
240 :param locked:
215 """
241 """
216 repo = get_repo_or_error(repoid)
242 repo = get_repo_or_error(repoid)
217 if HasPermissionAnyApi('hg.admin')(user=apiuser):
243 if HasPermissionAnyApi('hg.admin')(user=apiuser):
218 pass
244 pass
219 elif HasRepoPermissionAnyApi('repository.admin',
245 elif HasRepoPermissionAnyApi('repository.admin',
220 'repository.write')(user=apiuser,
246 'repository.write')(user=apiuser,
221 repo_name=repo.repo_name):
247 repo_name=repo.repo_name):
222 #make sure normal user does not pass someone else userid,
248 #make sure normal user does not pass someone else userid,
223 #he is not allowed to do that
249 #he is not allowed to do that
224 if not isinstance(userid, Optional) and userid != apiuser.user_id:
250 if not isinstance(userid, Optional) and userid != apiuser.user_id:
225 raise JSONRPCError(
251 raise JSONRPCError(
226 'userid is not the same as your user'
252 'userid is not the same as your user'
227 )
253 )
228 else:
254 else:
229 raise JSONRPCError('repository `%s` does not exist' % (repoid))
255 raise JSONRPCError('repository `%s` does not exist' % (repoid))
230
256
231 if isinstance(userid, Optional):
257 if isinstance(userid, Optional):
232 userid = apiuser.user_id
258 userid = apiuser.user_id
233 user = get_user_or_error(userid)
259 user = get_user_or_error(userid)
234 locked = bool(locked)
260 locked = bool(locked)
235 try:
261 try:
236 if locked:
262 if locked:
237 Repository.lock(repo, user.user_id)
263 Repository.lock(repo, user.user_id)
238 else:
264 else:
239 Repository.unlock(repo)
265 Repository.unlock(repo)
240
266
241 return ('User `%s` set lock state for repo `%s` to `%s`'
267 return ('User `%s` set lock state for repo `%s` to `%s`'
242 % (user.username, repo.repo_name, locked))
268 % (user.username, repo.repo_name, locked))
243 except Exception:
269 except Exception:
244 log.error(traceback.format_exc())
270 log.error(traceback.format_exc())
245 raise JSONRPCError(
271 raise JSONRPCError(
246 'Error occurred locking repository `%s`' % repo.repo_name
272 'Error occurred locking repository `%s`' % repo.repo_name
247 )
273 )
248
274
249 @HasPermissionAllDecorator('hg.admin')
275 @HasPermissionAllDecorator('hg.admin')
250 def show_ip(self, apiuser, userid):
276 def show_ip(self, apiuser, userid):
251 """
277 """
252 Shows IP address as seen from RhodeCode server, together with all
278 Shows IP address as seen from RhodeCode server, together with all
253 defined IP addresses for given user
279 defined IP addresses for given user
254
280
255 :param apiuser:
281 :param apiuser:
256 :param userid:
282 :param userid:
257 """
283 """
258 user = get_user_or_error(userid)
284 user = get_user_or_error(userid)
259 ips = UserIpMap.query().filter(UserIpMap.user == user).all()
285 ips = UserIpMap.query().filter(UserIpMap.user == user).all()
260 return dict(
286 return dict(
261 ip_addr_server=self.ip_addr,
287 ip_addr_server=self.ip_addr,
262 user_ips=ips
288 user_ips=ips
263 )
289 )
264
290
265 def get_user(self, apiuser, userid=Optional(OAttr('apiuser'))):
291 def get_user(self, apiuser, userid=Optional(OAttr('apiuser'))):
266 """"
292 """"
267 Get a user by username, or userid, if userid is given
293 Get a user by username, or userid, if userid is given
268
294
269 :param apiuser:
295 :param apiuser:
270 :param userid:
296 :param userid:
271 """
297 """
272 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
298 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
273 #make sure normal user does not pass someone else userid,
299 #make sure normal user does not pass someone else userid,
274 #he is not allowed to do that
300 #he is not allowed to do that
275 if not isinstance(userid, Optional) and userid != apiuser.user_id:
301 if not isinstance(userid, Optional) and userid != apiuser.user_id:
276 raise JSONRPCError(
302 raise JSONRPCError(
277 'userid is not the same as your user'
303 'userid is not the same as your user'
278 )
304 )
279
305
280 if isinstance(userid, Optional):
306 if isinstance(userid, Optional):
281 userid = apiuser.user_id
307 userid = apiuser.user_id
282
308
283 user = get_user_or_error(userid)
309 user = get_user_or_error(userid)
284 data = user.get_api_data()
310 data = user.get_api_data()
285 data['permissions'] = AuthUser(user_id=user.user_id).permissions
311 data['permissions'] = AuthUser(user_id=user.user_id).permissions
286 return data
312 return data
287
313
288 @HasPermissionAllDecorator('hg.admin')
314 @HasPermissionAllDecorator('hg.admin')
289 def get_users(self, apiuser):
315 def get_users(self, apiuser):
290 """"
316 """"
291 Get all users
317 Get all users
292
318
293 :param apiuser:
319 :param apiuser:
294 """
320 """
295
321
296 result = []
322 result = []
297 for user in UserModel().get_all():
323 for user in UserModel().get_all():
298 result.append(user.get_api_data())
324 result.append(user.get_api_data())
299 return result
325 return result
300
326
301 @HasPermissionAllDecorator('hg.admin')
327 @HasPermissionAllDecorator('hg.admin')
302 def create_user(self, apiuser, username, email, password,
328 def create_user(self, apiuser, username, email, password,
303 firstname=Optional(None), lastname=Optional(None),
329 firstname=Optional(None), lastname=Optional(None),
304 active=Optional(True), admin=Optional(False),
330 active=Optional(True), admin=Optional(False),
305 ldap_dn=Optional(None)):
331 ldap_dn=Optional(None)):
306 """
332 """
307 Create new user
333 Create new user
308
334
309 :param apiuser:
335 :param apiuser:
310 :param username:
336 :param username:
311 :param email:
337 :param email:
312 :param password:
338 :param password:
313 :param firstname:
339 :param firstname:
314 :param lastname:
340 :param lastname:
315 :param active:
341 :param active:
316 :param admin:
342 :param admin:
317 :param ldap_dn:
343 :param ldap_dn:
318 """
344 """
319
345
320 if UserModel().get_by_username(username):
346 if UserModel().get_by_username(username):
321 raise JSONRPCError("user `%s` already exist" % username)
347 raise JSONRPCError("user `%s` already exist" % username)
322
348
323 if UserModel().get_by_email(email, case_insensitive=True):
349 if UserModel().get_by_email(email, case_insensitive=True):
324 raise JSONRPCError("email `%s` already exist" % email)
350 raise JSONRPCError("email `%s` already exist" % email)
325
351
326 if Optional.extract(ldap_dn):
352 if Optional.extract(ldap_dn):
327 # generate temporary password if ldap_dn
353 # generate temporary password if ldap_dn
328 password = PasswordGenerator().gen_password(length=8)
354 password = PasswordGenerator().gen_password(length=8)
329
355
330 try:
356 try:
331 user = UserModel().create_or_update(
357 user = UserModel().create_or_update(
332 username=Optional.extract(username),
358 username=Optional.extract(username),
333 password=Optional.extract(password),
359 password=Optional.extract(password),
334 email=Optional.extract(email),
360 email=Optional.extract(email),
335 firstname=Optional.extract(firstname),
361 firstname=Optional.extract(firstname),
336 lastname=Optional.extract(lastname),
362 lastname=Optional.extract(lastname),
337 active=Optional.extract(active),
363 active=Optional.extract(active),
338 admin=Optional.extract(admin),
364 admin=Optional.extract(admin),
339 ldap_dn=Optional.extract(ldap_dn)
365 ldap_dn=Optional.extract(ldap_dn)
340 )
366 )
341 Session().commit()
367 Session().commit()
342 return dict(
368 return dict(
343 msg='created new user `%s`' % username,
369 msg='created new user `%s`' % username,
344 user=user.get_api_data()
370 user=user.get_api_data()
345 )
371 )
346 except Exception:
372 except Exception:
347 log.error(traceback.format_exc())
373 log.error(traceback.format_exc())
348 raise JSONRPCError('failed to create user `%s`' % username)
374 raise JSONRPCError('failed to create user `%s`' % username)
349
375
350 @HasPermissionAllDecorator('hg.admin')
376 @HasPermissionAllDecorator('hg.admin')
351 def update_user(self, apiuser, userid, username=Optional(None),
377 def update_user(self, apiuser, userid, username=Optional(None),
352 email=Optional(None), firstname=Optional(None),
378 email=Optional(None), firstname=Optional(None),
353 lastname=Optional(None), active=Optional(None),
379 lastname=Optional(None), active=Optional(None),
354 admin=Optional(None), ldap_dn=Optional(None),
380 admin=Optional(None), ldap_dn=Optional(None),
355 password=Optional(None)):
381 password=Optional(None)):
356 """
382 """
357 Updates given user
383 Updates given user
358
384
359 :param apiuser:
385 :param apiuser:
360 :param userid:
386 :param userid:
361 :param username:
387 :param username:
362 :param email:
388 :param email:
363 :param firstname:
389 :param firstname:
364 :param lastname:
390 :param lastname:
365 :param active:
391 :param active:
366 :param admin:
392 :param admin:
367 :param ldap_dn:
393 :param ldap_dn:
368 :param password:
394 :param password:
369 """
395 """
370
396
371 user = get_user_or_error(userid)
397 user = get_user_or_error(userid)
372
398
373 # call function and store only updated arguments
399 # call function and store only updated arguments
374 updates = {}
400 updates = {}
375
401
376 def store_update(attr, name):
402 def store_update(attr, name):
377 if not isinstance(attr, Optional):
403 if not isinstance(attr, Optional):
378 updates[name] = attr
404 updates[name] = attr
379
405
380 try:
406 try:
381
407
382 store_update(username, 'username')
408 store_update(username, 'username')
383 store_update(password, 'password')
409 store_update(password, 'password')
384 store_update(email, 'email')
410 store_update(email, 'email')
385 store_update(firstname, 'name')
411 store_update(firstname, 'name')
386 store_update(lastname, 'lastname')
412 store_update(lastname, 'lastname')
387 store_update(active, 'active')
413 store_update(active, 'active')
388 store_update(admin, 'admin')
414 store_update(admin, 'admin')
389 store_update(ldap_dn, 'ldap_dn')
415 store_update(ldap_dn, 'ldap_dn')
390
416
391 user = UserModel().update_user(user, **updates)
417 user = UserModel().update_user(user, **updates)
392 Session().commit()
418 Session().commit()
393 return dict(
419 return dict(
394 msg='updated user ID:%s %s' % (user.user_id, user.username),
420 msg='updated user ID:%s %s' % (user.user_id, user.username),
395 user=user.get_api_data()
421 user=user.get_api_data()
396 )
422 )
397 except Exception:
423 except Exception:
398 log.error(traceback.format_exc())
424 log.error(traceback.format_exc())
399 raise JSONRPCError('failed to update user `%s`' % userid)
425 raise JSONRPCError('failed to update user `%s`' % userid)
400
426
401 @HasPermissionAllDecorator('hg.admin')
427 @HasPermissionAllDecorator('hg.admin')
402 def delete_user(self, apiuser, userid):
428 def delete_user(self, apiuser, userid):
403 """"
429 """"
404 Deletes an user
430 Deletes an user
405
431
406 :param apiuser:
432 :param apiuser:
407 :param userid:
433 :param userid:
408 """
434 """
409 user = get_user_or_error(userid)
435 user = get_user_or_error(userid)
410
436
411 try:
437 try:
412 UserModel().delete(userid)
438 UserModel().delete(userid)
413 Session().commit()
439 Session().commit()
414 return dict(
440 return dict(
415 msg='deleted user ID:%s %s' % (user.user_id, user.username),
441 msg='deleted user ID:%s %s' % (user.user_id, user.username),
416 user=None
442 user=None
417 )
443 )
418 except Exception:
444 except Exception:
419 log.error(traceback.format_exc())
445 log.error(traceback.format_exc())
420 raise JSONRPCError('failed to delete ID:%s %s' % (user.user_id,
446 raise JSONRPCError('failed to delete ID:%s %s' % (user.user_id,
421 user.username))
447 user.username))
422
448
423 @HasPermissionAllDecorator('hg.admin')
449 @HasPermissionAllDecorator('hg.admin')
424 def get_users_group(self, apiuser, usersgroupid):
450 def get_users_group(self, apiuser, usersgroupid):
425 """"
451 """"
426 Get users group by name or id
452 Get users group by name or id
427
453
428 :param apiuser:
454 :param apiuser:
429 :param usersgroupid:
455 :param usersgroupid:
430 """
456 """
431 users_group = get_users_group_or_error(usersgroupid)
457 users_group = get_users_group_or_error(usersgroupid)
432
458
433 data = users_group.get_api_data()
459 data = users_group.get_api_data()
434
460
435 members = []
461 members = []
436 for user in users_group.members:
462 for user in users_group.members:
437 user = user.user
463 user = user.user
438 members.append(user.get_api_data())
464 members.append(user.get_api_data())
439 data['members'] = members
465 data['members'] = members
440 return data
466 return data
441
467
442 @HasPermissionAllDecorator('hg.admin')
468 @HasPermissionAllDecorator('hg.admin')
443 def get_users_groups(self, apiuser):
469 def get_users_groups(self, apiuser):
444 """"
470 """"
445 Get all users groups
471 Get all users groups
446
472
447 :param apiuser:
473 :param apiuser:
448 """
474 """
449
475
450 result = []
476 result = []
451 for users_group in UsersGroupModel().get_all():
477 for users_group in UsersGroupModel().get_all():
452 result.append(users_group.get_api_data())
478 result.append(users_group.get_api_data())
453 return result
479 return result
454
480
455 @HasPermissionAllDecorator('hg.admin')
481 @HasPermissionAllDecorator('hg.admin')
456 def create_users_group(self, apiuser, group_name, active=Optional(True)):
482 def create_users_group(self, apiuser, group_name, active=Optional(True)):
457 """
483 """
458 Creates an new usergroup
484 Creates an new usergroup
459
485
460 :param apiuser:
486 :param apiuser:
461 :param group_name:
487 :param group_name:
462 :param active:
488 :param active:
463 """
489 """
464
490
465 if UsersGroupModel().get_by_name(group_name):
491 if UsersGroupModel().get_by_name(group_name):
466 raise JSONRPCError("users group `%s` already exist" % group_name)
492 raise JSONRPCError("users group `%s` already exist" % group_name)
467
493
468 try:
494 try:
469 active = Optional.extract(active)
495 active = Optional.extract(active)
470 ug = UsersGroupModel().create(name=group_name, active=active)
496 ug = UsersGroupModel().create(name=group_name, active=active)
471 Session().commit()
497 Session().commit()
472 return dict(
498 return dict(
473 msg='created new users group `%s`' % group_name,
499 msg='created new users group `%s`' % group_name,
474 users_group=ug.get_api_data()
500 users_group=ug.get_api_data()
475 )
501 )
476 except Exception:
502 except Exception:
477 log.error(traceback.format_exc())
503 log.error(traceback.format_exc())
478 raise JSONRPCError('failed to create group `%s`' % group_name)
504 raise JSONRPCError('failed to create group `%s`' % group_name)
479
505
480 @HasPermissionAllDecorator('hg.admin')
506 @HasPermissionAllDecorator('hg.admin')
481 def add_user_to_users_group(self, apiuser, usersgroupid, userid):
507 def add_user_to_users_group(self, apiuser, usersgroupid, userid):
482 """"
508 """"
483 Add a user to a users group
509 Add a user to a users group
484
510
485 :param apiuser:
511 :param apiuser:
486 :param usersgroupid:
512 :param usersgroupid:
487 :param userid:
513 :param userid:
488 """
514 """
489 user = get_user_or_error(userid)
515 user = get_user_or_error(userid)
490 users_group = get_users_group_or_error(usersgroupid)
516 users_group = get_users_group_or_error(usersgroupid)
491
517
492 try:
518 try:
493 ugm = UsersGroupModel().add_user_to_group(users_group, user)
519 ugm = UsersGroupModel().add_user_to_group(users_group, user)
494 success = True if ugm != True else False
520 success = True if ugm != True else False
495 msg = 'added member `%s` to users group `%s`' % (
521 msg = 'added member `%s` to users group `%s`' % (
496 user.username, users_group.users_group_name
522 user.username, users_group.users_group_name
497 )
523 )
498 msg = msg if success else 'User is already in that group'
524 msg = msg if success else 'User is already in that group'
499 Session().commit()
525 Session().commit()
500
526
501 return dict(
527 return dict(
502 success=success,
528 success=success,
503 msg=msg
529 msg=msg
504 )
530 )
505 except Exception:
531 except Exception:
506 log.error(traceback.format_exc())
532 log.error(traceback.format_exc())
507 raise JSONRPCError(
533 raise JSONRPCError(
508 'failed to add member to users group `%s`' % (
534 'failed to add member to users group `%s`' % (
509 users_group.users_group_name
535 users_group.users_group_name
510 )
536 )
511 )
537 )
512
538
513 @HasPermissionAllDecorator('hg.admin')
539 @HasPermissionAllDecorator('hg.admin')
514 def remove_user_from_users_group(self, apiuser, usersgroupid, userid):
540 def remove_user_from_users_group(self, apiuser, usersgroupid, userid):
515 """
541 """
516 Remove user from a group
542 Remove user from a group
517
543
518 :param apiuser:
544 :param apiuser:
519 :param usersgroupid:
545 :param usersgroupid:
520 :param userid:
546 :param userid:
521 """
547 """
522 user = get_user_or_error(userid)
548 user = get_user_or_error(userid)
523 users_group = get_users_group_or_error(usersgroupid)
549 users_group = get_users_group_or_error(usersgroupid)
524
550
525 try:
551 try:
526 success = UsersGroupModel().remove_user_from_group(users_group,
552 success = UsersGroupModel().remove_user_from_group(users_group,
527 user)
553 user)
528 msg = 'removed member `%s` from users group `%s`' % (
554 msg = 'removed member `%s` from users group `%s`' % (
529 user.username, users_group.users_group_name
555 user.username, users_group.users_group_name
530 )
556 )
531 msg = msg if success else "User wasn't in group"
557 msg = msg if success else "User wasn't in group"
532 Session().commit()
558 Session().commit()
533 return dict(success=success, msg=msg)
559 return dict(success=success, msg=msg)
534 except Exception:
560 except Exception:
535 log.error(traceback.format_exc())
561 log.error(traceback.format_exc())
536 raise JSONRPCError(
562 raise JSONRPCError(
537 'failed to remove member from users group `%s`' % (
563 'failed to remove member from users group `%s`' % (
538 users_group.users_group_name
564 users_group.users_group_name
539 )
565 )
540 )
566 )
541
567
542 def get_repo(self, apiuser, repoid):
568 def get_repo(self, apiuser, repoid):
543 """"
569 """"
544 Get repository by name
570 Get repository by name
545
571
546 :param apiuser:
572 :param apiuser:
547 :param repoid:
573 :param repoid:
548 """
574 """
549 repo = get_repo_or_error(repoid)
575 repo = get_repo_or_error(repoid)
550
576
551 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
577 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
552 # check if we have admin permission for this repo !
578 # check if we have admin permission for this repo !
553 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
579 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
554 repo_name=repo.repo_name) is False:
580 repo_name=repo.repo_name) is False:
555 raise JSONRPCError('repository `%s` does not exist' % (repoid))
581 raise JSONRPCError('repository `%s` does not exist' % (repoid))
556
582
557 members = []
583 members = []
558 followers = []
584 followers = []
559 for user in repo.repo_to_perm:
585 for user in repo.repo_to_perm:
560 perm = user.permission.permission_name
586 perm = user.permission.permission_name
561 user = user.user
587 user = user.user
562 user_data = user.get_api_data()
588 user_data = user.get_api_data()
563 user_data['type'] = "user"
589 user_data['type'] = "user"
564 user_data['permission'] = perm
590 user_data['permission'] = perm
565 members.append(user_data)
591 members.append(user_data)
566
592
567 for users_group in repo.users_group_to_perm:
593 for users_group in repo.users_group_to_perm:
568 perm = users_group.permission.permission_name
594 perm = users_group.permission.permission_name
569 users_group = users_group.users_group
595 users_group = users_group.users_group
570 users_group_data = users_group.get_api_data()
596 users_group_data = users_group.get_api_data()
571 users_group_data['type'] = "users_group"
597 users_group_data['type'] = "users_group"
572 users_group_data['permission'] = perm
598 users_group_data['permission'] = perm
573 members.append(users_group_data)
599 members.append(users_group_data)
574
600
575 for user in repo.followers:
601 for user in repo.followers:
576 followers.append(user.user.get_api_data())
602 followers.append(user.user.get_api_data())
577
603
578 data = repo.get_api_data()
604 data = repo.get_api_data()
579 data['members'] = members
605 data['members'] = members
580 data['followers'] = followers
606 data['followers'] = followers
581 return data
607 return data
582
608
583 def get_repos(self, apiuser):
609 def get_repos(self, apiuser):
584 """"
610 """"
585 Get all repositories
611 Get all repositories
586
612
587 :param apiuser:
613 :param apiuser:
588 """
614 """
589 result = []
615 result = []
590 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
616 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
591 repos = RepoModel().get_all_user_repos(user=apiuser)
617 repos = RepoModel().get_all_user_repos(user=apiuser)
592 else:
618 else:
593 repos = RepoModel().get_all()
619 repos = RepoModel().get_all()
594
620
595 for repo in repos:
621 for repo in repos:
596 result.append(repo.get_api_data())
622 result.append(repo.get_api_data())
597 return result
623 return result
598
624
599 @HasPermissionAllDecorator('hg.admin')
625 @HasPermissionAllDecorator('hg.admin')
600 def get_repo_nodes(self, apiuser, repoid, revision, root_path,
626 def get_repo_nodes(self, apiuser, repoid, revision, root_path,
601 ret_type='all'):
627 ret_type='all'):
602 """
628 """
603 returns a list of nodes and it's children
629 returns a list of nodes and it's children
604 for a given path at given revision. It's possible to specify ret_type
630 for a given path at given revision. It's possible to specify ret_type
605 to show only files or dirs
631 to show only files or dirs
606
632
607 :param apiuser:
633 :param apiuser:
608 :param repoid: name or id of repository
634 :param repoid: name or id of repository
609 :param revision: revision for which listing should be done
635 :param revision: revision for which listing should be done
610 :param root_path: path from which start displaying
636 :param root_path: path from which start displaying
611 :param ret_type: return type 'all|files|dirs' nodes
637 :param ret_type: return type 'all|files|dirs' nodes
612 """
638 """
613 repo = get_repo_or_error(repoid)
639 repo = get_repo_or_error(repoid)
614 try:
640 try:
615 _d, _f = ScmModel().get_nodes(repo, revision, root_path,
641 _d, _f = ScmModel().get_nodes(repo, revision, root_path,
616 flat=False)
642 flat=False)
617 _map = {
643 _map = {
618 'all': _d + _f,
644 'all': _d + _f,
619 'files': _f,
645 'files': _f,
620 'dirs': _d,
646 'dirs': _d,
621 }
647 }
622 return _map[ret_type]
648 return _map[ret_type]
623 except KeyError:
649 except KeyError:
624 raise JSONRPCError('ret_type must be one of %s' % _map.keys())
650 raise JSONRPCError('ret_type must be one of %s' % _map.keys())
625 except Exception:
651 except Exception:
626 log.error(traceback.format_exc())
652 log.error(traceback.format_exc())
627 raise JSONRPCError(
653 raise JSONRPCError(
628 'failed to get repo: `%s` nodes' % repo.repo_name
654 'failed to get repo: `%s` nodes' % repo.repo_name
629 )
655 )
630
656
631 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
657 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
632 def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')),
658 def create_repo(self, apiuser, repo_name, owner=Optional(OAttr('apiuser')),
633 repo_type=Optional('hg'),
659 repo_type=Optional('hg'),
634 description=Optional(''), private=Optional(False),
660 description=Optional(''), private=Optional(False),
635 clone_uri=Optional(None), landing_rev=Optional('tip'),
661 clone_uri=Optional(None), landing_rev=Optional('tip'),
636 enable_statistics=Optional(False),
662 enable_statistics=Optional(False),
637 enable_locking=Optional(False),
663 enable_locking=Optional(False),
638 enable_downloads=Optional(False)):
664 enable_downloads=Optional(False)):
639 """
665 """
640 Create repository, if clone_url is given it makes a remote clone
666 Create repository, if clone_url is given it makes a remote clone
641 if repo_name is within a group name the groups will be created
667 if repo_name is within a group name the groups will be created
642 automatically if they aren't present
668 automatically if they aren't present
643
669
644 :param apiuser:
670 :param apiuser:
645 :param repo_name:
671 :param repo_name:
646 :param onwer:
672 :param onwer:
647 :param repo_type:
673 :param repo_type:
648 :param description:
674 :param description:
649 :param private:
675 :param private:
650 :param clone_uri:
676 :param clone_uri:
651 :param landing_rev:
677 :param landing_rev:
652 """
678 """
653 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
679 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
654 if not isinstance(owner, Optional):
680 if not isinstance(owner, Optional):
655 #forbid setting owner for non-admins
681 #forbid setting owner for non-admins
656 raise JSONRPCError(
682 raise JSONRPCError(
657 'Only RhodeCode admin can specify `owner` param'
683 'Only RhodeCode admin can specify `owner` param'
658 )
684 )
659 if isinstance(owner, Optional):
685 if isinstance(owner, Optional):
660 owner = apiuser.user_id
686 owner = apiuser.user_id
661
687
662 owner = get_user_or_error(owner)
688 owner = get_user_or_error(owner)
663
689
664 if RepoModel().get_by_repo_name(repo_name):
690 if RepoModel().get_by_repo_name(repo_name):
665 raise JSONRPCError("repo `%s` already exist" % repo_name)
691 raise JSONRPCError("repo `%s` already exist" % repo_name)
666
692
667 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
693 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
668 if isinstance(private, Optional):
694 if isinstance(private, Optional):
669 private = defs.get('repo_private') or Optional.extract(private)
695 private = defs.get('repo_private') or Optional.extract(private)
670 if isinstance(repo_type, Optional):
696 if isinstance(repo_type, Optional):
671 repo_type = defs.get('repo_type')
697 repo_type = defs.get('repo_type')
672 if isinstance(enable_statistics, Optional):
698 if isinstance(enable_statistics, Optional):
673 enable_statistics = defs.get('repo_enable_statistics')
699 enable_statistics = defs.get('repo_enable_statistics')
674 if isinstance(enable_locking, Optional):
700 if isinstance(enable_locking, Optional):
675 enable_locking = defs.get('repo_enable_locking')
701 enable_locking = defs.get('repo_enable_locking')
676 if isinstance(enable_downloads, Optional):
702 if isinstance(enable_downloads, Optional):
677 enable_downloads = defs.get('repo_enable_downloads')
703 enable_downloads = defs.get('repo_enable_downloads')
678
704
679 clone_uri = Optional.extract(clone_uri)
705 clone_uri = Optional.extract(clone_uri)
680 description = Optional.extract(description)
706 description = Optional.extract(description)
681 landing_rev = Optional.extract(landing_rev)
707 landing_rev = Optional.extract(landing_rev)
682
708
683 try:
709 try:
684 # create structure of groups and return the last group
710 # create structure of groups and return the last group
685 group = map_groups(repo_name)
711 group = map_groups(repo_name)
686
712
687 repo = RepoModel().create_repo(
713 repo = RepoModel().create_repo(
688 repo_name=repo_name,
714 repo_name=repo_name,
689 repo_type=repo_type,
715 repo_type=repo_type,
690 description=description,
716 description=description,
691 owner=owner,
717 owner=owner,
692 private=private,
718 private=private,
693 clone_uri=clone_uri,
719 clone_uri=clone_uri,
694 repos_group=group,
720 repos_group=group,
695 landing_rev=landing_rev,
721 landing_rev=landing_rev,
696 enable_statistics=enable_statistics,
722 enable_statistics=enable_statistics,
697 enable_downloads=enable_downloads,
723 enable_downloads=enable_downloads,
698 enable_locking=enable_locking
724 enable_locking=enable_locking
699 )
725 )
700
726
701 Session().commit()
727 Session().commit()
702 return dict(
728 return dict(
703 msg="Created new repository `%s`" % (repo.repo_name),
729 msg="Created new repository `%s`" % (repo.repo_name),
704 repo=repo.get_api_data()
730 repo=repo.get_api_data()
705 )
731 )
706 except Exception:
732 except Exception:
707 log.error(traceback.format_exc())
733 log.error(traceback.format_exc())
708 raise JSONRPCError('failed to create repository `%s`' % repo_name)
734 raise JSONRPCError('failed to create repository `%s`' % repo_name)
709
735
710 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
736 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
711 def fork_repo(self, apiuser, repoid, fork_name, owner=Optional(OAttr('apiuser')),
737 def fork_repo(self, apiuser, repoid, fork_name, owner=Optional(OAttr('apiuser')),
712 description=Optional(''), copy_permissions=Optional(False),
738 description=Optional(''), copy_permissions=Optional(False),
713 private=Optional(False), landing_rev=Optional('tip')):
739 private=Optional(False), landing_rev=Optional('tip')):
714 repo = get_repo_or_error(repoid)
740 repo = get_repo_or_error(repoid)
715 repo_name = repo.repo_name
741 repo_name = repo.repo_name
716
742
717 _repo = RepoModel().get_by_repo_name(fork_name)
743 _repo = RepoModel().get_by_repo_name(fork_name)
718 if _repo:
744 if _repo:
719 type_ = 'fork' if _repo.fork else 'repo'
745 type_ = 'fork' if _repo.fork else 'repo'
720 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
746 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
721
747
722 if HasPermissionAnyApi('hg.admin')(user=apiuser):
748 if HasPermissionAnyApi('hg.admin')(user=apiuser):
723 pass
749 pass
724 elif HasRepoPermissionAnyApi('repository.admin',
750 elif HasRepoPermissionAnyApi('repository.admin',
725 'repository.write',
751 'repository.write',
726 'repository.read')(user=apiuser,
752 'repository.read')(user=apiuser,
727 repo_name=repo.repo_name):
753 repo_name=repo.repo_name):
728 if not isinstance(owner, Optional):
754 if not isinstance(owner, Optional):
729 #forbid setting owner for non-admins
755 #forbid setting owner for non-admins
730 raise JSONRPCError(
756 raise JSONRPCError(
731 'Only RhodeCode admin can specify `owner` param'
757 'Only RhodeCode admin can specify `owner` param'
732 )
758 )
733 else:
759 else:
734 raise JSONRPCError('repository `%s` does not exist' % (repoid))
760 raise JSONRPCError('repository `%s` does not exist' % (repoid))
735
761
736 if isinstance(owner, Optional):
762 if isinstance(owner, Optional):
737 owner = apiuser.user_id
763 owner = apiuser.user_id
738
764
739 owner = get_user_or_error(owner)
765 owner = get_user_or_error(owner)
740
766
741 try:
767 try:
742 # create structure of groups and return the last group
768 # create structure of groups and return the last group
743 group = map_groups(fork_name)
769 group = map_groups(fork_name)
744
770
745 form_data = dict(
771 form_data = dict(
746 repo_name=fork_name,
772 repo_name=fork_name,
747 repo_name_full=fork_name,
773 repo_name_full=fork_name,
748 repo_group=group,
774 repo_group=group,
749 repo_type=repo.repo_type,
775 repo_type=repo.repo_type,
750 description=Optional.extract(description),
776 description=Optional.extract(description),
751 private=Optional.extract(private),
777 private=Optional.extract(private),
752 copy_permissions=Optional.extract(copy_permissions),
778 copy_permissions=Optional.extract(copy_permissions),
753 landing_rev=Optional.extract(landing_rev),
779 landing_rev=Optional.extract(landing_rev),
754 update_after_clone=False,
780 update_after_clone=False,
755 fork_parent_id=repo.repo_id,
781 fork_parent_id=repo.repo_id,
756 )
782 )
757 RepoModel().create_fork(form_data, cur_user=owner)
783 RepoModel().create_fork(form_data, cur_user=owner)
758 return dict(
784 return dict(
759 msg='Created fork of `%s` as `%s`' % (repo.repo_name,
785 msg='Created fork of `%s` as `%s`' % (repo.repo_name,
760 fork_name),
786 fork_name),
761 success=True # cannot return the repo data here since fork
787 success=True # cannot return the repo data here since fork
762 # cann be done async
788 # cann be done async
763 )
789 )
764 except Exception:
790 except Exception:
765 log.error(traceback.format_exc())
791 log.error(traceback.format_exc())
766 raise JSONRPCError(
792 raise JSONRPCError(
767 'failed to fork repository `%s` as `%s`' % (repo_name,
793 'failed to fork repository `%s` as `%s`' % (repo_name,
768 fork_name)
794 fork_name)
769 )
795 )
770
796
771 def delete_repo(self, apiuser, repoid):
797 def delete_repo(self, apiuser, repoid):
772 """
798 """
773 Deletes a given repository
799 Deletes a given repository
774
800
775 :param apiuser:
801 :param apiuser:
776 :param repoid:
802 :param repoid:
777 """
803 """
778 repo = get_repo_or_error(repoid)
804 repo = get_repo_or_error(repoid)
779
805
780 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
806 if HasPermissionAnyApi('hg.admin')(user=apiuser) is False:
781 # check if we have admin permission for this repo !
807 # check if we have admin permission for this repo !
782 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
808 if HasRepoPermissionAnyApi('repository.admin')(user=apiuser,
783 repo_name=repo.repo_name) is False:
809 repo_name=repo.repo_name) is False:
784 raise JSONRPCError('repository `%s` does not exist' % (repoid))
810 raise JSONRPCError('repository `%s` does not exist' % (repoid))
785
811
786 try:
812 try:
787 RepoModel().delete(repo)
813 RepoModel().delete(repo)
788 Session().commit()
814 Session().commit()
789 return dict(
815 return dict(
790 msg='Deleted repository `%s`' % repo.repo_name,
816 msg='Deleted repository `%s`' % repo.repo_name,
791 success=True
817 success=True
792 )
818 )
793 except Exception:
819 except Exception:
794 log.error(traceback.format_exc())
820 log.error(traceback.format_exc())
795 raise JSONRPCError(
821 raise JSONRPCError(
796 'failed to delete repository `%s`' % repo.repo_name
822 'failed to delete repository `%s`' % repo.repo_name
797 )
823 )
798
824
799 @HasPermissionAllDecorator('hg.admin')
825 @HasPermissionAllDecorator('hg.admin')
800 def grant_user_permission(self, apiuser, repoid, userid, perm):
826 def grant_user_permission(self, apiuser, repoid, userid, perm):
801 """
827 """
802 Grant permission for user on given repository, or update existing one
828 Grant permission for user on given repository, or update existing one
803 if found
829 if found
804
830
805 :param repoid:
831 :param repoid:
806 :param userid:
832 :param userid:
807 :param perm:
833 :param perm:
808 """
834 """
809 repo = get_repo_or_error(repoid)
835 repo = get_repo_or_error(repoid)
810 user = get_user_or_error(userid)
836 user = get_user_or_error(userid)
811 perm = get_perm_or_error(perm)
837 perm = get_perm_or_error(perm)
812
838
813 try:
839 try:
814
840
815 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
841 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
816
842
817 Session().commit()
843 Session().commit()
818 return dict(
844 return dict(
819 msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
845 msg='Granted perm: `%s` for user: `%s` in repo: `%s`' % (
820 perm.permission_name, user.username, repo.repo_name
846 perm.permission_name, user.username, repo.repo_name
821 ),
847 ),
822 success=True
848 success=True
823 )
849 )
824 except Exception:
850 except Exception:
825 log.error(traceback.format_exc())
851 log.error(traceback.format_exc())
826 raise JSONRPCError(
852 raise JSONRPCError(
827 'failed to edit permission for user: `%s` in repo: `%s`' % (
853 'failed to edit permission for user: `%s` in repo: `%s`' % (
828 userid, repoid
854 userid, repoid
829 )
855 )
830 )
856 )
831
857
832 @HasPermissionAllDecorator('hg.admin')
858 @HasPermissionAllDecorator('hg.admin')
833 def revoke_user_permission(self, apiuser, repoid, userid):
859 def revoke_user_permission(self, apiuser, repoid, userid):
834 """
860 """
835 Revoke permission for user on given repository
861 Revoke permission for user on given repository
836
862
837 :param apiuser:
863 :param apiuser:
838 :param repoid:
864 :param repoid:
839 :param userid:
865 :param userid:
840 """
866 """
841
867
842 repo = get_repo_or_error(repoid)
868 repo = get_repo_or_error(repoid)
843 user = get_user_or_error(userid)
869 user = get_user_or_error(userid)
844 try:
870 try:
845
871
846 RepoModel().revoke_user_permission(repo=repo, user=user)
872 RepoModel().revoke_user_permission(repo=repo, user=user)
847
873
848 Session().commit()
874 Session().commit()
849 return dict(
875 return dict(
850 msg='Revoked perm for user: `%s` in repo: `%s`' % (
876 msg='Revoked perm for user: `%s` in repo: `%s`' % (
851 user.username, repo.repo_name
877 user.username, repo.repo_name
852 ),
878 ),
853 success=True
879 success=True
854 )
880 )
855 except Exception:
881 except Exception:
856 log.error(traceback.format_exc())
882 log.error(traceback.format_exc())
857 raise JSONRPCError(
883 raise JSONRPCError(
858 'failed to edit permission for user: `%s` in repo: `%s`' % (
884 'failed to edit permission for user: `%s` in repo: `%s`' % (
859 userid, repoid
885 userid, repoid
860 )
886 )
861 )
887 )
862
888
863 @HasPermissionAllDecorator('hg.admin')
889 @HasPermissionAllDecorator('hg.admin')
864 def grant_users_group_permission(self, apiuser, repoid, usersgroupid,
890 def grant_users_group_permission(self, apiuser, repoid, usersgroupid,
865 perm):
891 perm):
866 """
892 """
867 Grant permission for users group on given repository, or update
893 Grant permission for users group on given repository, or update
868 existing one if found
894 existing one if found
869
895
870 :param apiuser:
896 :param apiuser:
871 :param repoid:
897 :param repoid:
872 :param usersgroupid:
898 :param usersgroupid:
873 :param perm:
899 :param perm:
874 """
900 """
875 repo = get_repo_or_error(repoid)
901 repo = get_repo_or_error(repoid)
876 perm = get_perm_or_error(perm)
902 perm = get_perm_or_error(perm)
877 users_group = get_users_group_or_error(usersgroupid)
903 users_group = get_users_group_or_error(usersgroupid)
878
904
879 try:
905 try:
880 RepoModel().grant_users_group_permission(repo=repo,
906 RepoModel().grant_users_group_permission(repo=repo,
881 group_name=users_group,
907 group_name=users_group,
882 perm=perm)
908 perm=perm)
883
909
884 Session().commit()
910 Session().commit()
885 return dict(
911 return dict(
886 msg='Granted perm: `%s` for users group: `%s` in '
912 msg='Granted perm: `%s` for users group: `%s` in '
887 'repo: `%s`' % (
913 'repo: `%s`' % (
888 perm.permission_name, users_group.users_group_name,
914 perm.permission_name, users_group.users_group_name,
889 repo.repo_name
915 repo.repo_name
890 ),
916 ),
891 success=True
917 success=True
892 )
918 )
893 except Exception:
919 except Exception:
894 log.error(traceback.format_exc())
920 log.error(traceback.format_exc())
895 raise JSONRPCError(
921 raise JSONRPCError(
896 'failed to edit permission for users group: `%s` in '
922 'failed to edit permission for users group: `%s` in '
897 'repo: `%s`' % (
923 'repo: `%s`' % (
898 usersgroupid, repo.repo_name
924 usersgroupid, repo.repo_name
899 )
925 )
900 )
926 )
901
927
902 @HasPermissionAllDecorator('hg.admin')
928 @HasPermissionAllDecorator('hg.admin')
903 def revoke_users_group_permission(self, apiuser, repoid, usersgroupid):
929 def revoke_users_group_permission(self, apiuser, repoid, usersgroupid):
904 """
930 """
905 Revoke permission for users group on given repository
931 Revoke permission for users group on given repository
906
932
907 :param apiuser:
933 :param apiuser:
908 :param repoid:
934 :param repoid:
909 :param usersgroupid:
935 :param usersgroupid:
910 """
936 """
911 repo = get_repo_or_error(repoid)
937 repo = get_repo_or_error(repoid)
912 users_group = get_users_group_or_error(usersgroupid)
938 users_group = get_users_group_or_error(usersgroupid)
913
939
914 try:
940 try:
915 RepoModel().revoke_users_group_permission(repo=repo,
941 RepoModel().revoke_users_group_permission(repo=repo,
916 group_name=users_group)
942 group_name=users_group)
917
943
918 Session().commit()
944 Session().commit()
919 return dict(
945 return dict(
920 msg='Revoked perm for users group: `%s` in repo: `%s`' % (
946 msg='Revoked perm for users group: `%s` in repo: `%s`' % (
921 users_group.users_group_name, repo.repo_name
947 users_group.users_group_name, repo.repo_name
922 ),
948 ),
923 success=True
949 success=True
924 )
950 )
925 except Exception:
951 except Exception:
926 log.error(traceback.format_exc())
952 log.error(traceback.format_exc())
927 raise JSONRPCError(
953 raise JSONRPCError(
928 'failed to edit permission for users group: `%s` in '
954 'failed to edit permission for users group: `%s` in '
929 'repo: `%s`' % (
955 'repo: `%s`' % (
930 users_group.users_group_name, repo.repo_name
956 users_group.users_group_name, repo.repo_name
931 )
957 )
932 )
958 )
@@ -1,1275 +1,1294 b''
1 from __future__ import with_statement
1 from __future__ import with_statement
2 import random
2 import random
3 import mock
3 import mock
4
4
5 from rhodecode.tests import *
5 from rhodecode.tests import *
6 from rhodecode.lib.compat import json
6 from rhodecode.lib.compat import json
7 from rhodecode.lib.auth import AuthUser
7 from rhodecode.lib.auth import AuthUser
8 from rhodecode.model.user import UserModel
8 from rhodecode.model.user import UserModel
9 from rhodecode.model.users_group import UsersGroupModel
9 from rhodecode.model.users_group import UsersGroupModel
10 from rhodecode.model.repo import RepoModel
10 from rhodecode.model.repo import RepoModel
11 from rhodecode.model.meta import Session
11 from rhodecode.model.meta import Session
12 from rhodecode.model.scm import ScmModel
12 from rhodecode.model.scm import ScmModel
13 from rhodecode.model.db import Repository
13 from rhodecode.model.db import Repository
14
14
15 API_URL = '/_admin/api'
15 API_URL = '/_admin/api'
16
16
17
17
18 def _build_data(apikey, method, **kw):
18 def _build_data(apikey, method, **kw):
19 """
19 """
20 Builds API data with given random ID
20 Builds API data with given random ID
21
21
22 :param random_id:
22 :param random_id:
23 :type random_id:
23 :type random_id:
24 """
24 """
25 random_id = random.randrange(1, 9999)
25 random_id = random.randrange(1, 9999)
26 return random_id, json.dumps({
26 return random_id, json.dumps({
27 "id": random_id,
27 "id": random_id,
28 "api_key": apikey,
28 "api_key": apikey,
29 "method": method,
29 "method": method,
30 "args": kw
30 "args": kw
31 })
31 })
32
32
33 jsonify = lambda obj: json.loads(json.dumps(obj))
33 jsonify = lambda obj: json.loads(json.dumps(obj))
34
34
35
35
36 def crash(*args, **kwargs):
36 def crash(*args, **kwargs):
37 raise Exception('Total Crash !')
37 raise Exception('Total Crash !')
38
38
39
39
40 def api_call(test_obj, params):
40 def api_call(test_obj, params):
41 response = test_obj.app.post(API_URL, content_type='application/json',
41 response = test_obj.app.post(API_URL, content_type='application/json',
42 params=params)
42 params=params)
43 return response
43 return response
44
44
45
45
46 TEST_USERS_GROUP = 'test_users_group'
46 TEST_USERS_GROUP = 'test_users_group'
47
47
48
48
49 def make_users_group(name=TEST_USERS_GROUP):
49 def make_users_group(name=TEST_USERS_GROUP):
50 gr = UsersGroupModel().create(name=name)
50 gr = UsersGroupModel().create(name=name)
51 UsersGroupModel().add_user_to_group(users_group=gr,
51 UsersGroupModel().add_user_to_group(users_group=gr,
52 user=TEST_USER_ADMIN_LOGIN)
52 user=TEST_USER_ADMIN_LOGIN)
53 Session().commit()
53 Session().commit()
54 return gr
54 return gr
55
55
56
56
57 def destroy_users_group(name=TEST_USERS_GROUP):
57 def destroy_users_group(name=TEST_USERS_GROUP):
58 UsersGroupModel().delete(users_group=name, force=True)
58 UsersGroupModel().delete(users_group=name, force=True)
59 Session().commit()
59 Session().commit()
60
60
61
61
62 def create_repo(repo_name, repo_type, owner=None):
62 def create_repo(repo_name, repo_type, owner=None):
63 # create new repo
63 # create new repo
64 form_data = _get_repo_create_params(
64 form_data = _get_repo_create_params(
65 repo_name_full=repo_name,
65 repo_name_full=repo_name,
66 repo_description='description %s' % repo_name,
66 repo_description='description %s' % repo_name,
67 )
67 )
68 cur_user = UserModel().get_by_username(owner or TEST_USER_ADMIN_LOGIN)
68 cur_user = UserModel().get_by_username(owner or TEST_USER_ADMIN_LOGIN)
69 r = RepoModel().create(form_data, cur_user)
69 r = RepoModel().create(form_data, cur_user)
70 Session().commit()
70 Session().commit()
71 return r
71 return r
72
72
73
73
74 def create_fork(fork_name, fork_type, fork_of):
74 def create_fork(fork_name, fork_type, fork_of):
75 fork = RepoModel(Session())._get_repo(fork_of)
75 fork = RepoModel(Session())._get_repo(fork_of)
76 r = create_repo(fork_name, fork_type)
76 r = create_repo(fork_name, fork_type)
77 r.fork = fork
77 r.fork = fork
78 Session().add(r)
78 Session().add(r)
79 Session().commit()
79 Session().commit()
80 return r
80 return r
81
81
82
82
83 def destroy_repo(repo_name):
83 def destroy_repo(repo_name):
84 RepoModel().delete(repo_name)
84 RepoModel().delete(repo_name)
85 Session().commit()
85 Session().commit()
86
86
87
87
88 class BaseTestApi(object):
88 class BaseTestApi(object):
89 REPO = None
89 REPO = None
90 REPO_TYPE = None
90 REPO_TYPE = None
91
91
92 @classmethod
92 @classmethod
93 def setUpClass(self):
93 def setUpClass(self):
94 self.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
94 self.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
95 self.apikey = self.usr.api_key
95 self.apikey = self.usr.api_key
96 self.test_user = UserModel().create_or_update(
96 self.test_user = UserModel().create_or_update(
97 username='test-api',
97 username='test-api',
98 password='test',
98 password='test',
99 email='test@api.rhodecode.org',
99 email='test@api.rhodecode.org',
100 firstname='first',
100 firstname='first',
101 lastname='last'
101 lastname='last'
102 )
102 )
103 Session().commit()
103 Session().commit()
104 self.TEST_USER_LOGIN = self.test_user.username
104 self.TEST_USER_LOGIN = self.test_user.username
105 self.apikey_regular = self.test_user.api_key
105 self.apikey_regular = self.test_user.api_key
106
106
107 @classmethod
107 @classmethod
108 def teardownClass(self):
108 def teardownClass(self):
109 pass
109 pass
110
110
111 def setUp(self):
111 def setUp(self):
112 self.maxDiff = None
112 self.maxDiff = None
113 make_users_group()
113 make_users_group()
114
114
115 def tearDown(self):
115 def tearDown(self):
116 destroy_users_group()
116 destroy_users_group()
117
117
118 def _compare_ok(self, id_, expected, given):
118 def _compare_ok(self, id_, expected, given):
119 expected = jsonify({
119 expected = jsonify({
120 'id': id_,
120 'id': id_,
121 'error': None,
121 'error': None,
122 'result': expected
122 'result': expected
123 })
123 })
124 given = json.loads(given)
124 given = json.loads(given)
125 self.assertEqual(expected, given)
125 self.assertEqual(expected, given)
126
126
127 def _compare_error(self, id_, expected, given):
127 def _compare_error(self, id_, expected, given):
128 expected = jsonify({
128 expected = jsonify({
129 'id': id_,
129 'id': id_,
130 'error': expected,
130 'error': expected,
131 'result': None
131 'result': None
132 })
132 })
133 given = json.loads(given)
133 given = json.loads(given)
134 self.assertEqual(expected, given)
134 self.assertEqual(expected, given)
135
135
136 # def test_Optional(self):
136 # def test_Optional(self):
137 # from rhodecode.controllers.api.api import Optional
137 # from rhodecode.controllers.api.api import Optional
138 # option1 = Optional(None)
138 # option1 = Optional(None)
139 # self.assertEqual('<Optional:%s>' % None, repr(option1))
139 # self.assertEqual('<Optional:%s>' % None, repr(option1))
140 #
140 #
141 # self.assertEqual(1, Optional.extract(Optional(1)))
141 # self.assertEqual(1, Optional.extract(Optional(1)))
142 # self.assertEqual('trololo', Optional.extract('trololo'))
142 # self.assertEqual('trololo', Optional.extract('trololo'))
143
143
144 def test_api_wrong_key(self):
144 def test_api_wrong_key(self):
145 id_, params = _build_data('trololo', 'get_user')
145 id_, params = _build_data('trololo', 'get_user')
146 response = api_call(self, params)
146 response = api_call(self, params)
147
147
148 expected = 'Invalid API KEY'
148 expected = 'Invalid API KEY'
149 self._compare_error(id_, expected, given=response.body)
149 self._compare_error(id_, expected, given=response.body)
150
150
151 def test_api_missing_non_optional_param(self):
151 def test_api_missing_non_optional_param(self):
152 id_, params = _build_data(self.apikey, 'get_repo')
152 id_, params = _build_data(self.apikey, 'get_repo')
153 response = api_call(self, params)
153 response = api_call(self, params)
154
154
155 expected = 'Missing non optional `repoid` arg in JSON DATA'
155 expected = 'Missing non optional `repoid` arg in JSON DATA'
156 self._compare_error(id_, expected, given=response.body)
156 self._compare_error(id_, expected, given=response.body)
157
157
158 def test_api_missing_non_optional_param_args_null(self):
158 def test_api_missing_non_optional_param_args_null(self):
159 id_, params = _build_data(self.apikey, 'get_repo')
159 id_, params = _build_data(self.apikey, 'get_repo')
160 params = params.replace('"args": {}', '"args": null')
160 params = params.replace('"args": {}', '"args": null')
161 response = api_call(self, params)
161 response = api_call(self, params)
162
162
163 expected = 'Missing non optional `repoid` arg in JSON DATA'
163 expected = 'Missing non optional `repoid` arg in JSON DATA'
164 self._compare_error(id_, expected, given=response.body)
164 self._compare_error(id_, expected, given=response.body)
165
165
166 def test_api_missing_non_optional_param_args_bad(self):
166 def test_api_missing_non_optional_param_args_bad(self):
167 id_, params = _build_data(self.apikey, 'get_repo')
167 id_, params = _build_data(self.apikey, 'get_repo')
168 params = params.replace('"args": {}', '"args": 1')
168 params = params.replace('"args": {}', '"args": 1')
169 response = api_call(self, params)
169 response = api_call(self, params)
170
170
171 expected = 'Missing non optional `repoid` arg in JSON DATA'
171 expected = 'Missing non optional `repoid` arg in JSON DATA'
172 self._compare_error(id_, expected, given=response.body)
172 self._compare_error(id_, expected, given=response.body)
173
173
174 def test_api_args_is_null(self):
174 def test_api_args_is_null(self):
175 id_, params = _build_data(self.apikey, 'get_users',)
175 id_, params = _build_data(self.apikey, 'get_users',)
176 params = params.replace('"args": {}', '"args": null')
176 params = params.replace('"args": {}', '"args": null')
177 response = api_call(self, params)
177 response = api_call(self, params)
178 self.assertEqual(response.status, '200 OK')
178 self.assertEqual(response.status, '200 OK')
179
179
180 def test_api_args_is_bad(self):
180 def test_api_args_is_bad(self):
181 id_, params = _build_data(self.apikey, 'get_users',)
181 id_, params = _build_data(self.apikey, 'get_users',)
182 params = params.replace('"args": {}', '"args": 1')
182 params = params.replace('"args": {}', '"args": 1')
183 response = api_call(self, params)
183 response = api_call(self, params)
184 self.assertEqual(response.status, '200 OK')
184 self.assertEqual(response.status, '200 OK')
185
185
186 def test_api_get_users(self):
186 def test_api_get_users(self):
187 id_, params = _build_data(self.apikey, 'get_users',)
187 id_, params = _build_data(self.apikey, 'get_users',)
188 response = api_call(self, params)
188 response = api_call(self, params)
189 ret_all = []
189 ret_all = []
190 for usr in UserModel().get_all():
190 for usr in UserModel().get_all():
191 ret = usr.get_api_data()
191 ret = usr.get_api_data()
192 ret_all.append(jsonify(ret))
192 ret_all.append(jsonify(ret))
193 expected = ret_all
193 expected = ret_all
194 self._compare_ok(id_, expected, given=response.body)
194 self._compare_ok(id_, expected, given=response.body)
195
195
196 def test_api_get_user(self):
196 def test_api_get_user(self):
197 id_, params = _build_data(self.apikey, 'get_user',
197 id_, params = _build_data(self.apikey, 'get_user',
198 userid=TEST_USER_ADMIN_LOGIN)
198 userid=TEST_USER_ADMIN_LOGIN)
199 response = api_call(self, params)
199 response = api_call(self, params)
200
200
201 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
201 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
202 ret = usr.get_api_data()
202 ret = usr.get_api_data()
203 ret['permissions'] = AuthUser(usr.user_id).permissions
203 ret['permissions'] = AuthUser(usr.user_id).permissions
204
204
205 expected = ret
205 expected = ret
206 self._compare_ok(id_, expected, given=response.body)
206 self._compare_ok(id_, expected, given=response.body)
207
207
208 def test_api_get_user_that_does_not_exist(self):
208 def test_api_get_user_that_does_not_exist(self):
209 id_, params = _build_data(self.apikey, 'get_user',
209 id_, params = _build_data(self.apikey, 'get_user',
210 userid='trololo')
210 userid='trololo')
211 response = api_call(self, params)
211 response = api_call(self, params)
212
212
213 expected = "user `%s` does not exist" % 'trololo'
213 expected = "user `%s` does not exist" % 'trololo'
214 self._compare_error(id_, expected, given=response.body)
214 self._compare_error(id_, expected, given=response.body)
215
215
216 def test_api_get_user_without_giving_userid(self):
216 def test_api_get_user_without_giving_userid(self):
217 id_, params = _build_data(self.apikey, 'get_user')
217 id_, params = _build_data(self.apikey, 'get_user')
218 response = api_call(self, params)
218 response = api_call(self, params)
219
219
220 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
220 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
221 ret = usr.get_api_data()
221 ret = usr.get_api_data()
222 ret['permissions'] = AuthUser(usr.user_id).permissions
222 ret['permissions'] = AuthUser(usr.user_id).permissions
223
223
224 expected = ret
224 expected = ret
225 self._compare_ok(id_, expected, given=response.body)
225 self._compare_ok(id_, expected, given=response.body)
226
226
227 def test_api_get_user_without_giving_userid_non_admin(self):
227 def test_api_get_user_without_giving_userid_non_admin(self):
228 id_, params = _build_data(self.apikey_regular, 'get_user')
228 id_, params = _build_data(self.apikey_regular, 'get_user')
229 response = api_call(self, params)
229 response = api_call(self, params)
230
230
231 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
231 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
232 ret = usr.get_api_data()
232 ret = usr.get_api_data()
233 ret['permissions'] = AuthUser(usr.user_id).permissions
233 ret['permissions'] = AuthUser(usr.user_id).permissions
234
234
235 expected = ret
235 expected = ret
236 self._compare_ok(id_, expected, given=response.body)
236 self._compare_ok(id_, expected, given=response.body)
237
237
238 def test_api_get_user_with_giving_userid_non_admin(self):
238 def test_api_get_user_with_giving_userid_non_admin(self):
239 id_, params = _build_data(self.apikey_regular, 'get_user',
239 id_, params = _build_data(self.apikey_regular, 'get_user',
240 userid=self.TEST_USER_LOGIN)
240 userid=self.TEST_USER_LOGIN)
241 response = api_call(self, params)
241 response = api_call(self, params)
242
242
243 expected = 'userid is not the same as your user'
243 expected = 'userid is not the same as your user'
244 self._compare_error(id_, expected, given=response.body)
244 self._compare_error(id_, expected, given=response.body)
245
245
246 def test_api_pull(self):
246 def test_api_pull(self):
247 #TODO: issues with rhodecode_extras here.. not sure why !
247 #TODO: issues with rhodecode_extras here.. not sure why !
248 pass
248 pass
249
249
250 # repo_name = 'test_pull'
250 # repo_name = 'test_pull'
251 # r = create_repo(repo_name, self.REPO_TYPE)
251 # r = create_repo(repo_name, self.REPO_TYPE)
252 # r.clone_uri = TEST_self.REPO
252 # r.clone_uri = TEST_self.REPO
253 # Session.add(r)
253 # Session.add(r)
254 # Session.commit()
254 # Session.commit()
255 #
255 #
256 # id_, params = _build_data(self.apikey, 'pull',
256 # id_, params = _build_data(self.apikey, 'pull',
257 # repoid=repo_name,)
257 # repoid=repo_name,)
258 # response = self.app.post(API_URL, content_type='application/json',
258 # response = self.app.post(API_URL, content_type='application/json',
259 # params=params)
259 # params=params)
260 #
260 #
261 # expected = 'Pulled from `%s`' % repo_name
261 # expected = 'Pulled from `%s`' % repo_name
262 # self._compare_ok(id_, expected, given=response.body)
262 # self._compare_ok(id_, expected, given=response.body)
263 #
263 #
264 # destroy_repo(repo_name)
264 # destroy_repo(repo_name)
265
265
266 def test_api_pull_error(self):
266 def test_api_pull_error(self):
267 id_, params = _build_data(self.apikey, 'pull',
267 id_, params = _build_data(self.apikey, 'pull',
268 repoid=self.REPO,)
268 repoid=self.REPO,)
269 response = api_call(self, params)
269 response = api_call(self, params)
270
270
271 expected = 'Unable to pull changes from `%s`' % self.REPO
271 expected = 'Unable to pull changes from `%s`' % self.REPO
272 self._compare_error(id_, expected, given=response.body)
272 self._compare_error(id_, expected, given=response.body)
273
273
274 def test_api_rescan_repos(self):
274 def test_api_rescan_repos(self):
275 id_, params = _build_data(self.apikey, 'rescan_repos')
275 id_, params = _build_data(self.apikey, 'rescan_repos')
276 response = api_call(self, params)
276 response = api_call(self, params)
277
277
278 expected = {'added': [], 'removed': []}
278 expected = {'added': [], 'removed': []}
279 self._compare_ok(id_, expected, given=response.body)
279 self._compare_ok(id_, expected, given=response.body)
280
280
281 @mock.patch.object(ScmModel, 'repo_scan', crash)
281 @mock.patch.object(ScmModel, 'repo_scan', crash)
282 def test_api_rescann_error(self):
282 def test_api_rescann_error(self):
283 id_, params = _build_data(self.apikey, 'rescan_repos',)
283 id_, params = _build_data(self.apikey, 'rescan_repos',)
284 response = api_call(self, params)
284 response = api_call(self, params)
285
285
286 expected = 'Error occurred during rescan repositories action'
286 expected = 'Error occurred during rescan repositories action'
287 self._compare_error(id_, expected, given=response.body)
287 self._compare_error(id_, expected, given=response.body)
288
288
289 def test_api_invalidate_cache(self):
290 id_, params = _build_data(self.apikey, 'invalidate_cache',
291 repoid=self.REPO)
292 response = api_call(self, params)
293
294 expected = ("Cache for repository `%s` was invalidated: "
295 "invalidated cache keys: %s" % (self.REPO,
296 [unicode(self.REPO)]))
297 self._compare_ok(id_, expected, given=response.body)
298
299 @mock.patch.object(ScmModel, 'mark_for_invalidation', crash)
300 def test_api_invalidate_cache_error(self):
301 id_, params = _build_data(self.apikey, 'invalidate_cache',
302 repoid=self.REPO)
303 response = api_call(self, params)
304
305 expected = 'Error occurred during cache invalidation action'
306 self._compare_error(id_, expected, given=response.body)
307
289 def test_api_lock_repo_lock_aquire(self):
308 def test_api_lock_repo_lock_aquire(self):
290 id_, params = _build_data(self.apikey, 'lock',
309 id_, params = _build_data(self.apikey, 'lock',
291 userid=TEST_USER_ADMIN_LOGIN,
310 userid=TEST_USER_ADMIN_LOGIN,
292 repoid=self.REPO,
311 repoid=self.REPO,
293 locked=True)
312 locked=True)
294 response = api_call(self, params)
313 response = api_call(self, params)
295 expected = ('User `%s` set lock state for repo `%s` to `%s`'
314 expected = ('User `%s` set lock state for repo `%s` to `%s`'
296 % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
315 % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
297 self._compare_ok(id_, expected, given=response.body)
316 self._compare_ok(id_, expected, given=response.body)
298
317
299 def test_api_lock_repo_lock_aquire_by_non_admin(self):
318 def test_api_lock_repo_lock_aquire_by_non_admin(self):
300 repo_name = 'api_delete_me'
319 repo_name = 'api_delete_me'
301 create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN)
320 create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN)
302 try:
321 try:
303 id_, params = _build_data(self.apikey_regular, 'lock',
322 id_, params = _build_data(self.apikey_regular, 'lock',
304 repoid=repo_name,
323 repoid=repo_name,
305 locked=True)
324 locked=True)
306 response = api_call(self, params)
325 response = api_call(self, params)
307 expected = ('User `%s` set lock state for repo `%s` to `%s`'
326 expected = ('User `%s` set lock state for repo `%s` to `%s`'
308 % (self.TEST_USER_LOGIN, repo_name, True))
327 % (self.TEST_USER_LOGIN, repo_name, True))
309 self._compare_ok(id_, expected, given=response.body)
328 self._compare_ok(id_, expected, given=response.body)
310 finally:
329 finally:
311 destroy_repo(repo_name)
330 destroy_repo(repo_name)
312
331
313 def test_api_lock_repo_lock_aquire_non_admin_with_userid(self):
332 def test_api_lock_repo_lock_aquire_non_admin_with_userid(self):
314 repo_name = 'api_delete_me'
333 repo_name = 'api_delete_me'
315 create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN)
334 create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN)
316 try:
335 try:
317 id_, params = _build_data(self.apikey_regular, 'lock',
336 id_, params = _build_data(self.apikey_regular, 'lock',
318 userid=TEST_USER_ADMIN_LOGIN,
337 userid=TEST_USER_ADMIN_LOGIN,
319 repoid=repo_name,
338 repoid=repo_name,
320 locked=True)
339 locked=True)
321 response = api_call(self, params)
340 response = api_call(self, params)
322 expected = 'userid is not the same as your user'
341 expected = 'userid is not the same as your user'
323 self._compare_error(id_, expected, given=response.body)
342 self._compare_error(id_, expected, given=response.body)
324 finally:
343 finally:
325 destroy_repo(repo_name)
344 destroy_repo(repo_name)
326
345
327 def test_api_lock_repo_lock_aquire_non_admin_not_his_repo(self):
346 def test_api_lock_repo_lock_aquire_non_admin_not_his_repo(self):
328 id_, params = _build_data(self.apikey_regular, 'lock',
347 id_, params = _build_data(self.apikey_regular, 'lock',
329 repoid=self.REPO,
348 repoid=self.REPO,
330 locked=True)
349 locked=True)
331 response = api_call(self, params)
350 response = api_call(self, params)
332 expected = 'repository `%s` does not exist' % (self.REPO)
351 expected = 'repository `%s` does not exist' % (self.REPO)
333 self._compare_error(id_, expected, given=response.body)
352 self._compare_error(id_, expected, given=response.body)
334
353
335 def test_api_lock_repo_lock_release(self):
354 def test_api_lock_repo_lock_release(self):
336 id_, params = _build_data(self.apikey, 'lock',
355 id_, params = _build_data(self.apikey, 'lock',
337 userid=TEST_USER_ADMIN_LOGIN,
356 userid=TEST_USER_ADMIN_LOGIN,
338 repoid=self.REPO,
357 repoid=self.REPO,
339 locked=False)
358 locked=False)
340 response = api_call(self, params)
359 response = api_call(self, params)
341 expected = ('User `%s` set lock state for repo `%s` to `%s`'
360 expected = ('User `%s` set lock state for repo `%s` to `%s`'
342 % (TEST_USER_ADMIN_LOGIN, self.REPO, False))
361 % (TEST_USER_ADMIN_LOGIN, self.REPO, False))
343 self._compare_ok(id_, expected, given=response.body)
362 self._compare_ok(id_, expected, given=response.body)
344
363
345 def test_api_lock_repo_lock_aquire_optional_userid(self):
364 def test_api_lock_repo_lock_aquire_optional_userid(self):
346 id_, params = _build_data(self.apikey, 'lock',
365 id_, params = _build_data(self.apikey, 'lock',
347 repoid=self.REPO,
366 repoid=self.REPO,
348 locked=True)
367 locked=True)
349 response = api_call(self, params)
368 response = api_call(self, params)
350 expected = ('User `%s` set lock state for repo `%s` to `%s`'
369 expected = ('User `%s` set lock state for repo `%s` to `%s`'
351 % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
370 % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
352 self._compare_ok(id_, expected, given=response.body)
371 self._compare_ok(id_, expected, given=response.body)
353
372
354 @mock.patch.object(Repository, 'lock', crash)
373 @mock.patch.object(Repository, 'lock', crash)
355 def test_api_lock_error(self):
374 def test_api_lock_error(self):
356 id_, params = _build_data(self.apikey, 'lock',
375 id_, params = _build_data(self.apikey, 'lock',
357 userid=TEST_USER_ADMIN_LOGIN,
376 userid=TEST_USER_ADMIN_LOGIN,
358 repoid=self.REPO,
377 repoid=self.REPO,
359 locked=True)
378 locked=True)
360 response = api_call(self, params)
379 response = api_call(self, params)
361
380
362 expected = 'Error occurred locking repository `%s`' % self.REPO
381 expected = 'Error occurred locking repository `%s`' % self.REPO
363 self._compare_error(id_, expected, given=response.body)
382 self._compare_error(id_, expected, given=response.body)
364
383
365 def test_api_create_existing_user(self):
384 def test_api_create_existing_user(self):
366 id_, params = _build_data(self.apikey, 'create_user',
385 id_, params = _build_data(self.apikey, 'create_user',
367 username=TEST_USER_ADMIN_LOGIN,
386 username=TEST_USER_ADMIN_LOGIN,
368 email='test@foo.com',
387 email='test@foo.com',
369 password='trololo')
388 password='trololo')
370 response = api_call(self, params)
389 response = api_call(self, params)
371
390
372 expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN
391 expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN
373 self._compare_error(id_, expected, given=response.body)
392 self._compare_error(id_, expected, given=response.body)
374
393
375 def test_api_create_user_with_existing_email(self):
394 def test_api_create_user_with_existing_email(self):
376 id_, params = _build_data(self.apikey, 'create_user',
395 id_, params = _build_data(self.apikey, 'create_user',
377 username=TEST_USER_ADMIN_LOGIN + 'new',
396 username=TEST_USER_ADMIN_LOGIN + 'new',
378 email=TEST_USER_REGULAR_EMAIL,
397 email=TEST_USER_REGULAR_EMAIL,
379 password='trololo')
398 password='trololo')
380 response = api_call(self, params)
399 response = api_call(self, params)
381
400
382 expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL
401 expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL
383 self._compare_error(id_, expected, given=response.body)
402 self._compare_error(id_, expected, given=response.body)
384
403
385 def test_api_create_user(self):
404 def test_api_create_user(self):
386 username = 'test_new_api_user'
405 username = 'test_new_api_user'
387 email = username + "@foo.com"
406 email = username + "@foo.com"
388
407
389 id_, params = _build_data(self.apikey, 'create_user',
408 id_, params = _build_data(self.apikey, 'create_user',
390 username=username,
409 username=username,
391 email=email,
410 email=email,
392 password='trololo')
411 password='trololo')
393 response = api_call(self, params)
412 response = api_call(self, params)
394
413
395 usr = UserModel().get_by_username(username)
414 usr = UserModel().get_by_username(username)
396 ret = dict(
415 ret = dict(
397 msg='created new user `%s`' % username,
416 msg='created new user `%s`' % username,
398 user=jsonify(usr.get_api_data())
417 user=jsonify(usr.get_api_data())
399 )
418 )
400
419
401 expected = ret
420 expected = ret
402 self._compare_ok(id_, expected, given=response.body)
421 self._compare_ok(id_, expected, given=response.body)
403
422
404 UserModel().delete(usr.user_id)
423 UserModel().delete(usr.user_id)
405 Session().commit()
424 Session().commit()
406
425
407 @mock.patch.object(UserModel, 'create_or_update', crash)
426 @mock.patch.object(UserModel, 'create_or_update', crash)
408 def test_api_create_user_when_exception_happened(self):
427 def test_api_create_user_when_exception_happened(self):
409
428
410 username = 'test_new_api_user'
429 username = 'test_new_api_user'
411 email = username + "@foo.com"
430 email = username + "@foo.com"
412
431
413 id_, params = _build_data(self.apikey, 'create_user',
432 id_, params = _build_data(self.apikey, 'create_user',
414 username=username,
433 username=username,
415 email=email,
434 email=email,
416 password='trololo')
435 password='trololo')
417 response = api_call(self, params)
436 response = api_call(self, params)
418 expected = 'failed to create user `%s`' % username
437 expected = 'failed to create user `%s`' % username
419 self._compare_error(id_, expected, given=response.body)
438 self._compare_error(id_, expected, given=response.body)
420
439
421 def test_api_delete_user(self):
440 def test_api_delete_user(self):
422 usr = UserModel().create_or_update(username=u'test_user',
441 usr = UserModel().create_or_update(username=u'test_user',
423 password=u'qweqwe',
442 password=u'qweqwe',
424 email=u'u232@rhodecode.org',
443 email=u'u232@rhodecode.org',
425 firstname=u'u1', lastname=u'u1')
444 firstname=u'u1', lastname=u'u1')
426 Session().commit()
445 Session().commit()
427 username = usr.username
446 username = usr.username
428 email = usr.email
447 email = usr.email
429 usr_id = usr.user_id
448 usr_id = usr.user_id
430 ## DELETE THIS USER NOW
449 ## DELETE THIS USER NOW
431
450
432 id_, params = _build_data(self.apikey, 'delete_user',
451 id_, params = _build_data(self.apikey, 'delete_user',
433 userid=username,)
452 userid=username,)
434 response = api_call(self, params)
453 response = api_call(self, params)
435
454
436 ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
455 ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
437 'user': None}
456 'user': None}
438 expected = ret
457 expected = ret
439 self._compare_ok(id_, expected, given=response.body)
458 self._compare_ok(id_, expected, given=response.body)
440
459
441 @mock.patch.object(UserModel, 'delete', crash)
460 @mock.patch.object(UserModel, 'delete', crash)
442 def test_api_delete_user_when_exception_happened(self):
461 def test_api_delete_user_when_exception_happened(self):
443 usr = UserModel().create_or_update(username=u'test_user',
462 usr = UserModel().create_or_update(username=u'test_user',
444 password=u'qweqwe',
463 password=u'qweqwe',
445 email=u'u232@rhodecode.org',
464 email=u'u232@rhodecode.org',
446 firstname=u'u1', lastname=u'u1')
465 firstname=u'u1', lastname=u'u1')
447 Session().commit()
466 Session().commit()
448 username = usr.username
467 username = usr.username
449
468
450 id_, params = _build_data(self.apikey, 'delete_user',
469 id_, params = _build_data(self.apikey, 'delete_user',
451 userid=username,)
470 userid=username,)
452 response = api_call(self, params)
471 response = api_call(self, params)
453 ret = 'failed to delete ID:%s %s' % (usr.user_id,
472 ret = 'failed to delete ID:%s %s' % (usr.user_id,
454 usr.username)
473 usr.username)
455 expected = ret
474 expected = ret
456 self._compare_error(id_, expected, given=response.body)
475 self._compare_error(id_, expected, given=response.body)
457
476
458 @parameterized.expand([('firstname', 'new_username'),
477 @parameterized.expand([('firstname', 'new_username'),
459 ('lastname', 'new_username'),
478 ('lastname', 'new_username'),
460 ('email', 'new_username'),
479 ('email', 'new_username'),
461 ('admin', True),
480 ('admin', True),
462 ('admin', False),
481 ('admin', False),
463 ('ldap_dn', 'test'),
482 ('ldap_dn', 'test'),
464 ('ldap_dn', None),
483 ('ldap_dn', None),
465 ('active', False),
484 ('active', False),
466 ('active', True),
485 ('active', True),
467 ('password', 'newpass')
486 ('password', 'newpass')
468 ])
487 ])
469 def test_api_update_user(self, name, expected):
488 def test_api_update_user(self, name, expected):
470 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
489 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
471 kw = {name: expected,
490 kw = {name: expected,
472 'userid': usr.user_id}
491 'userid': usr.user_id}
473 id_, params = _build_data(self.apikey, 'update_user', **kw)
492 id_, params = _build_data(self.apikey, 'update_user', **kw)
474 response = api_call(self, params)
493 response = api_call(self, params)
475
494
476 ret = {
495 ret = {
477 'msg': 'updated user ID:%s %s' % (usr.user_id, self.TEST_USER_LOGIN),
496 'msg': 'updated user ID:%s %s' % (usr.user_id, self.TEST_USER_LOGIN),
478 'user': jsonify(UserModel()\
497 'user': jsonify(UserModel()\
479 .get_by_username(self.TEST_USER_LOGIN)\
498 .get_by_username(self.TEST_USER_LOGIN)\
480 .get_api_data())
499 .get_api_data())
481 }
500 }
482
501
483 expected = ret
502 expected = ret
484 self._compare_ok(id_, expected, given=response.body)
503 self._compare_ok(id_, expected, given=response.body)
485
504
486 def test_api_update_user_no_changed_params(self):
505 def test_api_update_user_no_changed_params(self):
487 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
506 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
488 ret = jsonify(usr.get_api_data())
507 ret = jsonify(usr.get_api_data())
489 id_, params = _build_data(self.apikey, 'update_user',
508 id_, params = _build_data(self.apikey, 'update_user',
490 userid=TEST_USER_ADMIN_LOGIN)
509 userid=TEST_USER_ADMIN_LOGIN)
491
510
492 response = api_call(self, params)
511 response = api_call(self, params)
493 ret = {
512 ret = {
494 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
513 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
495 'user': ret
514 'user': ret
496 }
515 }
497 expected = ret
516 expected = ret
498 self._compare_ok(id_, expected, given=response.body)
517 self._compare_ok(id_, expected, given=response.body)
499
518
500 def test_api_update_user_by_user_id(self):
519 def test_api_update_user_by_user_id(self):
501 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
520 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
502 ret = jsonify(usr.get_api_data())
521 ret = jsonify(usr.get_api_data())
503 id_, params = _build_data(self.apikey, 'update_user',
522 id_, params = _build_data(self.apikey, 'update_user',
504 userid=usr.user_id)
523 userid=usr.user_id)
505
524
506 response = api_call(self, params)
525 response = api_call(self, params)
507 ret = {
526 ret = {
508 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
527 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
509 'user': ret
528 'user': ret
510 }
529 }
511 expected = ret
530 expected = ret
512 self._compare_ok(id_, expected, given=response.body)
531 self._compare_ok(id_, expected, given=response.body)
513
532
514 @mock.patch.object(UserModel, 'update_user', crash)
533 @mock.patch.object(UserModel, 'update_user', crash)
515 def test_api_update_user_when_exception_happens(self):
534 def test_api_update_user_when_exception_happens(self):
516 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
535 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
517 ret = jsonify(usr.get_api_data())
536 ret = jsonify(usr.get_api_data())
518 id_, params = _build_data(self.apikey, 'update_user',
537 id_, params = _build_data(self.apikey, 'update_user',
519 userid=usr.user_id)
538 userid=usr.user_id)
520
539
521 response = api_call(self, params)
540 response = api_call(self, params)
522 ret = 'failed to update user `%s`' % usr.user_id
541 ret = 'failed to update user `%s`' % usr.user_id
523
542
524 expected = ret
543 expected = ret
525 self._compare_error(id_, expected, given=response.body)
544 self._compare_error(id_, expected, given=response.body)
526
545
527 def test_api_get_repo(self):
546 def test_api_get_repo(self):
528 new_group = 'some_new_group'
547 new_group = 'some_new_group'
529 make_users_group(new_group)
548 make_users_group(new_group)
530 RepoModel().grant_users_group_permission(repo=self.REPO,
549 RepoModel().grant_users_group_permission(repo=self.REPO,
531 group_name=new_group,
550 group_name=new_group,
532 perm='repository.read')
551 perm='repository.read')
533 Session().commit()
552 Session().commit()
534 id_, params = _build_data(self.apikey, 'get_repo',
553 id_, params = _build_data(self.apikey, 'get_repo',
535 repoid=self.REPO)
554 repoid=self.REPO)
536 response = api_call(self, params)
555 response = api_call(self, params)
537
556
538 repo = RepoModel().get_by_repo_name(self.REPO)
557 repo = RepoModel().get_by_repo_name(self.REPO)
539 ret = repo.get_api_data()
558 ret = repo.get_api_data()
540
559
541 members = []
560 members = []
542 followers = []
561 followers = []
543 for user in repo.repo_to_perm:
562 for user in repo.repo_to_perm:
544 perm = user.permission.permission_name
563 perm = user.permission.permission_name
545 user = user.user
564 user = user.user
546 user_data = user.get_api_data()
565 user_data = user.get_api_data()
547 user_data['type'] = "user"
566 user_data['type'] = "user"
548 user_data['permission'] = perm
567 user_data['permission'] = perm
549 members.append(user_data)
568 members.append(user_data)
550
569
551 for users_group in repo.users_group_to_perm:
570 for users_group in repo.users_group_to_perm:
552 perm = users_group.permission.permission_name
571 perm = users_group.permission.permission_name
553 users_group = users_group.users_group
572 users_group = users_group.users_group
554 users_group_data = users_group.get_api_data()
573 users_group_data = users_group.get_api_data()
555 users_group_data['type'] = "users_group"
574 users_group_data['type'] = "users_group"
556 users_group_data['permission'] = perm
575 users_group_data['permission'] = perm
557 members.append(users_group_data)
576 members.append(users_group_data)
558
577
559 for user in repo.followers:
578 for user in repo.followers:
560 followers.append(user.user.get_api_data())
579 followers.append(user.user.get_api_data())
561
580
562 ret['members'] = members
581 ret['members'] = members
563 ret['followers'] = followers
582 ret['followers'] = followers
564
583
565 expected = ret
584 expected = ret
566 self._compare_ok(id_, expected, given=response.body)
585 self._compare_ok(id_, expected, given=response.body)
567 destroy_users_group(new_group)
586 destroy_users_group(new_group)
568
587
569 def test_api_get_repo_by_non_admin(self):
588 def test_api_get_repo_by_non_admin(self):
570 id_, params = _build_data(self.apikey, 'get_repo',
589 id_, params = _build_data(self.apikey, 'get_repo',
571 repoid=self.REPO)
590 repoid=self.REPO)
572 response = api_call(self, params)
591 response = api_call(self, params)
573
592
574 repo = RepoModel().get_by_repo_name(self.REPO)
593 repo = RepoModel().get_by_repo_name(self.REPO)
575 ret = repo.get_api_data()
594 ret = repo.get_api_data()
576
595
577 members = []
596 members = []
578 followers = []
597 followers = []
579 for user in repo.repo_to_perm:
598 for user in repo.repo_to_perm:
580 perm = user.permission.permission_name
599 perm = user.permission.permission_name
581 user = user.user
600 user = user.user
582 user_data = user.get_api_data()
601 user_data = user.get_api_data()
583 user_data['type'] = "user"
602 user_data['type'] = "user"
584 user_data['permission'] = perm
603 user_data['permission'] = perm
585 members.append(user_data)
604 members.append(user_data)
586
605
587 for users_group in repo.users_group_to_perm:
606 for users_group in repo.users_group_to_perm:
588 perm = users_group.permission.permission_name
607 perm = users_group.permission.permission_name
589 users_group = users_group.users_group
608 users_group = users_group.users_group
590 users_group_data = users_group.get_api_data()
609 users_group_data = users_group.get_api_data()
591 users_group_data['type'] = "users_group"
610 users_group_data['type'] = "users_group"
592 users_group_data['permission'] = perm
611 users_group_data['permission'] = perm
593 members.append(users_group_data)
612 members.append(users_group_data)
594
613
595 for user in repo.followers:
614 for user in repo.followers:
596 followers.append(user.user.get_api_data())
615 followers.append(user.user.get_api_data())
597
616
598 ret['members'] = members
617 ret['members'] = members
599 ret['followers'] = followers
618 ret['followers'] = followers
600
619
601 expected = ret
620 expected = ret
602 self._compare_ok(id_, expected, given=response.body)
621 self._compare_ok(id_, expected, given=response.body)
603
622
604 def test_api_get_repo_by_non_admin_no_permission_to_repo(self):
623 def test_api_get_repo_by_non_admin_no_permission_to_repo(self):
605 RepoModel().grant_user_permission(repo=self.REPO,
624 RepoModel().grant_user_permission(repo=self.REPO,
606 user=self.TEST_USER_LOGIN,
625 user=self.TEST_USER_LOGIN,
607 perm='repository.none')
626 perm='repository.none')
608
627
609 id_, params = _build_data(self.apikey_regular, 'get_repo',
628 id_, params = _build_data(self.apikey_regular, 'get_repo',
610 repoid=self.REPO)
629 repoid=self.REPO)
611 response = api_call(self, params)
630 response = api_call(self, params)
612
631
613 expected = 'repository `%s` does not exist' % (self.REPO)
632 expected = 'repository `%s` does not exist' % (self.REPO)
614 self._compare_error(id_, expected, given=response.body)
633 self._compare_error(id_, expected, given=response.body)
615
634
616 def test_api_get_repo_that_doesn_not_exist(self):
635 def test_api_get_repo_that_doesn_not_exist(self):
617 id_, params = _build_data(self.apikey, 'get_repo',
636 id_, params = _build_data(self.apikey, 'get_repo',
618 repoid='no-such-repo')
637 repoid='no-such-repo')
619 response = api_call(self, params)
638 response = api_call(self, params)
620
639
621 ret = 'repository `%s` does not exist' % 'no-such-repo'
640 ret = 'repository `%s` does not exist' % 'no-such-repo'
622 expected = ret
641 expected = ret
623 self._compare_error(id_, expected, given=response.body)
642 self._compare_error(id_, expected, given=response.body)
624
643
625 def test_api_get_repos(self):
644 def test_api_get_repos(self):
626 id_, params = _build_data(self.apikey, 'get_repos')
645 id_, params = _build_data(self.apikey, 'get_repos')
627 response = api_call(self, params)
646 response = api_call(self, params)
628
647
629 result = []
648 result = []
630 for repo in RepoModel().get_all():
649 for repo in RepoModel().get_all():
631 result.append(repo.get_api_data())
650 result.append(repo.get_api_data())
632 ret = jsonify(result)
651 ret = jsonify(result)
633
652
634 expected = ret
653 expected = ret
635 self._compare_ok(id_, expected, given=response.body)
654 self._compare_ok(id_, expected, given=response.body)
636
655
637 def test_api_get_repos_non_admin(self):
656 def test_api_get_repos_non_admin(self):
638 id_, params = _build_data(self.apikey_regular, 'get_repos')
657 id_, params = _build_data(self.apikey_regular, 'get_repos')
639 response = api_call(self, params)
658 response = api_call(self, params)
640
659
641 result = []
660 result = []
642 for repo in RepoModel().get_all_user_repos(self.TEST_USER_LOGIN):
661 for repo in RepoModel().get_all_user_repos(self.TEST_USER_LOGIN):
643 result.append(repo.get_api_data())
662 result.append(repo.get_api_data())
644 ret = jsonify(result)
663 ret = jsonify(result)
645
664
646 expected = ret
665 expected = ret
647 self._compare_ok(id_, expected, given=response.body)
666 self._compare_ok(id_, expected, given=response.body)
648
667
649 @parameterized.expand([('all', 'all'),
668 @parameterized.expand([('all', 'all'),
650 ('dirs', 'dirs'),
669 ('dirs', 'dirs'),
651 ('files', 'files'), ])
670 ('files', 'files'), ])
652 def test_api_get_repo_nodes(self, name, ret_type):
671 def test_api_get_repo_nodes(self, name, ret_type):
653 rev = 'tip'
672 rev = 'tip'
654 path = '/'
673 path = '/'
655 id_, params = _build_data(self.apikey, 'get_repo_nodes',
674 id_, params = _build_data(self.apikey, 'get_repo_nodes',
656 repoid=self.REPO, revision=rev,
675 repoid=self.REPO, revision=rev,
657 root_path=path,
676 root_path=path,
658 ret_type=ret_type)
677 ret_type=ret_type)
659 response = api_call(self, params)
678 response = api_call(self, params)
660
679
661 # we don't the actual return types here since it's tested somewhere
680 # we don't the actual return types here since it's tested somewhere
662 # else
681 # else
663 expected = json.loads(response.body)['result']
682 expected = json.loads(response.body)['result']
664 self._compare_ok(id_, expected, given=response.body)
683 self._compare_ok(id_, expected, given=response.body)
665
684
666 def test_api_get_repo_nodes_bad_revisions(self):
685 def test_api_get_repo_nodes_bad_revisions(self):
667 rev = 'i-dont-exist'
686 rev = 'i-dont-exist'
668 path = '/'
687 path = '/'
669 id_, params = _build_data(self.apikey, 'get_repo_nodes',
688 id_, params = _build_data(self.apikey, 'get_repo_nodes',
670 repoid=self.REPO, revision=rev,
689 repoid=self.REPO, revision=rev,
671 root_path=path,)
690 root_path=path,)
672 response = api_call(self, params)
691 response = api_call(self, params)
673
692
674 expected = 'failed to get repo: `%s` nodes' % self.REPO
693 expected = 'failed to get repo: `%s` nodes' % self.REPO
675 self._compare_error(id_, expected, given=response.body)
694 self._compare_error(id_, expected, given=response.body)
676
695
677 def test_api_get_repo_nodes_bad_path(self):
696 def test_api_get_repo_nodes_bad_path(self):
678 rev = 'tip'
697 rev = 'tip'
679 path = '/idontexits'
698 path = '/idontexits'
680 id_, params = _build_data(self.apikey, 'get_repo_nodes',
699 id_, params = _build_data(self.apikey, 'get_repo_nodes',
681 repoid=self.REPO, revision=rev,
700 repoid=self.REPO, revision=rev,
682 root_path=path,)
701 root_path=path,)
683 response = api_call(self, params)
702 response = api_call(self, params)
684
703
685 expected = 'failed to get repo: `%s` nodes' % self.REPO
704 expected = 'failed to get repo: `%s` nodes' % self.REPO
686 self._compare_error(id_, expected, given=response.body)
705 self._compare_error(id_, expected, given=response.body)
687
706
688 def test_api_get_repo_nodes_bad_ret_type(self):
707 def test_api_get_repo_nodes_bad_ret_type(self):
689 rev = 'tip'
708 rev = 'tip'
690 path = '/'
709 path = '/'
691 ret_type = 'error'
710 ret_type = 'error'
692 id_, params = _build_data(self.apikey, 'get_repo_nodes',
711 id_, params = _build_data(self.apikey, 'get_repo_nodes',
693 repoid=self.REPO, revision=rev,
712 repoid=self.REPO, revision=rev,
694 root_path=path,
713 root_path=path,
695 ret_type=ret_type)
714 ret_type=ret_type)
696 response = api_call(self, params)
715 response = api_call(self, params)
697
716
698 expected = 'ret_type must be one of %s' % (['files', 'dirs', 'all'])
717 expected = 'ret_type must be one of %s' % (['files', 'dirs', 'all'])
699 self._compare_error(id_, expected, given=response.body)
718 self._compare_error(id_, expected, given=response.body)
700
719
701 def test_api_create_repo(self):
720 def test_api_create_repo(self):
702 repo_name = 'api-repo'
721 repo_name = 'api-repo'
703 id_, params = _build_data(self.apikey, 'create_repo',
722 id_, params = _build_data(self.apikey, 'create_repo',
704 repo_name=repo_name,
723 repo_name=repo_name,
705 owner=TEST_USER_ADMIN_LOGIN,
724 owner=TEST_USER_ADMIN_LOGIN,
706 repo_type='hg',
725 repo_type='hg',
707 )
726 )
708 response = api_call(self, params)
727 response = api_call(self, params)
709
728
710 repo = RepoModel().get_by_repo_name(repo_name)
729 repo = RepoModel().get_by_repo_name(repo_name)
711 ret = {
730 ret = {
712 'msg': 'Created new repository `%s`' % repo_name,
731 'msg': 'Created new repository `%s`' % repo_name,
713 'repo': jsonify(repo.get_api_data())
732 'repo': jsonify(repo.get_api_data())
714 }
733 }
715 expected = ret
734 expected = ret
716 self._compare_ok(id_, expected, given=response.body)
735 self._compare_ok(id_, expected, given=response.body)
717 destroy_repo(repo_name)
736 destroy_repo(repo_name)
718
737
719 def test_api_create_repo_unknown_owner(self):
738 def test_api_create_repo_unknown_owner(self):
720 repo_name = 'api-repo'
739 repo_name = 'api-repo'
721 owner = 'i-dont-exist'
740 owner = 'i-dont-exist'
722 id_, params = _build_data(self.apikey, 'create_repo',
741 id_, params = _build_data(self.apikey, 'create_repo',
723 repo_name=repo_name,
742 repo_name=repo_name,
724 owner=owner,
743 owner=owner,
725 repo_type='hg',
744 repo_type='hg',
726 )
745 )
727 response = api_call(self, params)
746 response = api_call(self, params)
728 expected = 'user `%s` does not exist' % owner
747 expected = 'user `%s` does not exist' % owner
729 self._compare_error(id_, expected, given=response.body)
748 self._compare_error(id_, expected, given=response.body)
730
749
731 def test_api_create_repo_dont_specify_owner(self):
750 def test_api_create_repo_dont_specify_owner(self):
732 repo_name = 'api-repo'
751 repo_name = 'api-repo'
733 owner = 'i-dont-exist'
752 owner = 'i-dont-exist'
734 id_, params = _build_data(self.apikey, 'create_repo',
753 id_, params = _build_data(self.apikey, 'create_repo',
735 repo_name=repo_name,
754 repo_name=repo_name,
736 repo_type='hg',
755 repo_type='hg',
737 )
756 )
738 response = api_call(self, params)
757 response = api_call(self, params)
739
758
740 repo = RepoModel().get_by_repo_name(repo_name)
759 repo = RepoModel().get_by_repo_name(repo_name)
741 ret = {
760 ret = {
742 'msg': 'Created new repository `%s`' % repo_name,
761 'msg': 'Created new repository `%s`' % repo_name,
743 'repo': jsonify(repo.get_api_data())
762 'repo': jsonify(repo.get_api_data())
744 }
763 }
745 expected = ret
764 expected = ret
746 self._compare_ok(id_, expected, given=response.body)
765 self._compare_ok(id_, expected, given=response.body)
747 destroy_repo(repo_name)
766 destroy_repo(repo_name)
748
767
749 def test_api_create_repo_by_non_admin(self):
768 def test_api_create_repo_by_non_admin(self):
750 repo_name = 'api-repo'
769 repo_name = 'api-repo'
751 owner = 'i-dont-exist'
770 owner = 'i-dont-exist'
752 id_, params = _build_data(self.apikey_regular, 'create_repo',
771 id_, params = _build_data(self.apikey_regular, 'create_repo',
753 repo_name=repo_name,
772 repo_name=repo_name,
754 repo_type='hg',
773 repo_type='hg',
755 )
774 )
756 response = api_call(self, params)
775 response = api_call(self, params)
757
776
758 repo = RepoModel().get_by_repo_name(repo_name)
777 repo = RepoModel().get_by_repo_name(repo_name)
759 ret = {
778 ret = {
760 'msg': 'Created new repository `%s`' % repo_name,
779 'msg': 'Created new repository `%s`' % repo_name,
761 'repo': jsonify(repo.get_api_data())
780 'repo': jsonify(repo.get_api_data())
762 }
781 }
763 expected = ret
782 expected = ret
764 self._compare_ok(id_, expected, given=response.body)
783 self._compare_ok(id_, expected, given=response.body)
765 destroy_repo(repo_name)
784 destroy_repo(repo_name)
766
785
767 def test_api_create_repo_by_non_admin_specify_owner(self):
786 def test_api_create_repo_by_non_admin_specify_owner(self):
768 repo_name = 'api-repo'
787 repo_name = 'api-repo'
769 owner = 'i-dont-exist'
788 owner = 'i-dont-exist'
770 id_, params = _build_data(self.apikey_regular, 'create_repo',
789 id_, params = _build_data(self.apikey_regular, 'create_repo',
771 repo_name=repo_name,
790 repo_name=repo_name,
772 repo_type='hg',
791 repo_type='hg',
773 owner=owner
792 owner=owner
774 )
793 )
775 response = api_call(self, params)
794 response = api_call(self, params)
776
795
777 expected = 'Only RhodeCode admin can specify `owner` param'
796 expected = 'Only RhodeCode admin can specify `owner` param'
778 self._compare_error(id_, expected, given=response.body)
797 self._compare_error(id_, expected, given=response.body)
779 destroy_repo(repo_name)
798 destroy_repo(repo_name)
780
799
781 def test_api_create_repo_exists(self):
800 def test_api_create_repo_exists(self):
782 repo_name = self.REPO
801 repo_name = self.REPO
783 id_, params = _build_data(self.apikey, 'create_repo',
802 id_, params = _build_data(self.apikey, 'create_repo',
784 repo_name=repo_name,
803 repo_name=repo_name,
785 owner=TEST_USER_ADMIN_LOGIN,
804 owner=TEST_USER_ADMIN_LOGIN,
786 repo_type='hg',
805 repo_type='hg',
787 )
806 )
788 response = api_call(self, params)
807 response = api_call(self, params)
789 expected = "repo `%s` already exist" % repo_name
808 expected = "repo `%s` already exist" % repo_name
790 self._compare_error(id_, expected, given=response.body)
809 self._compare_error(id_, expected, given=response.body)
791
810
792 @mock.patch.object(RepoModel, 'create_repo', crash)
811 @mock.patch.object(RepoModel, 'create_repo', crash)
793 def test_api_create_repo_exception_occurred(self):
812 def test_api_create_repo_exception_occurred(self):
794 repo_name = 'api-repo'
813 repo_name = 'api-repo'
795 id_, params = _build_data(self.apikey, 'create_repo',
814 id_, params = _build_data(self.apikey, 'create_repo',
796 repo_name=repo_name,
815 repo_name=repo_name,
797 owner=TEST_USER_ADMIN_LOGIN,
816 owner=TEST_USER_ADMIN_LOGIN,
798 repo_type='hg',
817 repo_type='hg',
799 )
818 )
800 response = api_call(self, params)
819 response = api_call(self, params)
801 expected = 'failed to create repository `%s`' % repo_name
820 expected = 'failed to create repository `%s`' % repo_name
802 self._compare_error(id_, expected, given=response.body)
821 self._compare_error(id_, expected, given=response.body)
803
822
804 def test_api_delete_repo(self):
823 def test_api_delete_repo(self):
805 repo_name = 'api_delete_me'
824 repo_name = 'api_delete_me'
806 create_repo(repo_name, self.REPO_TYPE)
825 create_repo(repo_name, self.REPO_TYPE)
807
826
808 id_, params = _build_data(self.apikey, 'delete_repo',
827 id_, params = _build_data(self.apikey, 'delete_repo',
809 repoid=repo_name,)
828 repoid=repo_name,)
810 response = api_call(self, params)
829 response = api_call(self, params)
811
830
812 ret = {
831 ret = {
813 'msg': 'Deleted repository `%s`' % repo_name,
832 'msg': 'Deleted repository `%s`' % repo_name,
814 'success': True
833 'success': True
815 }
834 }
816 expected = ret
835 expected = ret
817 self._compare_ok(id_, expected, given=response.body)
836 self._compare_ok(id_, expected, given=response.body)
818
837
819 def test_api_delete_repo_by_non_admin(self):
838 def test_api_delete_repo_by_non_admin(self):
820 repo_name = 'api_delete_me'
839 repo_name = 'api_delete_me'
821 create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN)
840 create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN)
822 try:
841 try:
823 id_, params = _build_data(self.apikey_regular, 'delete_repo',
842 id_, params = _build_data(self.apikey_regular, 'delete_repo',
824 repoid=repo_name,)
843 repoid=repo_name,)
825 response = api_call(self, params)
844 response = api_call(self, params)
826
845
827 ret = {
846 ret = {
828 'msg': 'Deleted repository `%s`' % repo_name,
847 'msg': 'Deleted repository `%s`' % repo_name,
829 'success': True
848 'success': True
830 }
849 }
831 expected = ret
850 expected = ret
832 self._compare_ok(id_, expected, given=response.body)
851 self._compare_ok(id_, expected, given=response.body)
833 finally:
852 finally:
834 destroy_repo(repo_name)
853 destroy_repo(repo_name)
835
854
836 def test_api_delete_repo_by_non_admin_no_permission(self):
855 def test_api_delete_repo_by_non_admin_no_permission(self):
837 repo_name = 'api_delete_me'
856 repo_name = 'api_delete_me'
838 create_repo(repo_name, self.REPO_TYPE)
857 create_repo(repo_name, self.REPO_TYPE)
839 try:
858 try:
840 id_, params = _build_data(self.apikey_regular, 'delete_repo',
859 id_, params = _build_data(self.apikey_regular, 'delete_repo',
841 repoid=repo_name,)
860 repoid=repo_name,)
842 response = api_call(self, params)
861 response = api_call(self, params)
843 expected = 'repository `%s` does not exist' % (repo_name)
862 expected = 'repository `%s` does not exist' % (repo_name)
844 self._compare_error(id_, expected, given=response.body)
863 self._compare_error(id_, expected, given=response.body)
845 finally:
864 finally:
846 destroy_repo(repo_name)
865 destroy_repo(repo_name)
847
866
848 def test_api_delete_repo_exception_occurred(self):
867 def test_api_delete_repo_exception_occurred(self):
849 repo_name = 'api_delete_me'
868 repo_name = 'api_delete_me'
850 create_repo(repo_name, self.REPO_TYPE)
869 create_repo(repo_name, self.REPO_TYPE)
851 try:
870 try:
852 with mock.patch.object(RepoModel, 'delete', crash):
871 with mock.patch.object(RepoModel, 'delete', crash):
853 id_, params = _build_data(self.apikey, 'delete_repo',
872 id_, params = _build_data(self.apikey, 'delete_repo',
854 repoid=repo_name,)
873 repoid=repo_name,)
855 response = api_call(self, params)
874 response = api_call(self, params)
856
875
857 expected = 'failed to delete repository `%s`' % repo_name
876 expected = 'failed to delete repository `%s`' % repo_name
858 self._compare_error(id_, expected, given=response.body)
877 self._compare_error(id_, expected, given=response.body)
859 finally:
878 finally:
860 destroy_repo(repo_name)
879 destroy_repo(repo_name)
861
880
862 def test_api_fork_repo(self):
881 def test_api_fork_repo(self):
863 fork_name = 'api-repo-fork'
882 fork_name = 'api-repo-fork'
864 id_, params = _build_data(self.apikey, 'fork_repo',
883 id_, params = _build_data(self.apikey, 'fork_repo',
865 repoid=self.REPO,
884 repoid=self.REPO,
866 fork_name=fork_name,
885 fork_name=fork_name,
867 owner=TEST_USER_ADMIN_LOGIN,
886 owner=TEST_USER_ADMIN_LOGIN,
868 )
887 )
869 response = api_call(self, params)
888 response = api_call(self, params)
870
889
871 ret = {
890 ret = {
872 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
891 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
873 fork_name),
892 fork_name),
874 'success': True
893 'success': True
875 }
894 }
876 expected = ret
895 expected = ret
877 self._compare_ok(id_, expected, given=response.body)
896 self._compare_ok(id_, expected, given=response.body)
878 destroy_repo(fork_name)
897 destroy_repo(fork_name)
879
898
880 def test_api_fork_repo_non_admin(self):
899 def test_api_fork_repo_non_admin(self):
881 fork_name = 'api-repo-fork'
900 fork_name = 'api-repo-fork'
882 id_, params = _build_data(self.apikey_regular, 'fork_repo',
901 id_, params = _build_data(self.apikey_regular, 'fork_repo',
883 repoid=self.REPO,
902 repoid=self.REPO,
884 fork_name=fork_name,
903 fork_name=fork_name,
885 )
904 )
886 response = api_call(self, params)
905 response = api_call(self, params)
887
906
888 ret = {
907 ret = {
889 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
908 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
890 fork_name),
909 fork_name),
891 'success': True
910 'success': True
892 }
911 }
893 expected = ret
912 expected = ret
894 self._compare_ok(id_, expected, given=response.body)
913 self._compare_ok(id_, expected, given=response.body)
895 destroy_repo(fork_name)
914 destroy_repo(fork_name)
896
915
897 def test_api_fork_repo_non_admin_specify_owner(self):
916 def test_api_fork_repo_non_admin_specify_owner(self):
898 fork_name = 'api-repo-fork'
917 fork_name = 'api-repo-fork'
899 id_, params = _build_data(self.apikey_regular, 'fork_repo',
918 id_, params = _build_data(self.apikey_regular, 'fork_repo',
900 repoid=self.REPO,
919 repoid=self.REPO,
901 fork_name=fork_name,
920 fork_name=fork_name,
902 owner=TEST_USER_ADMIN_LOGIN,
921 owner=TEST_USER_ADMIN_LOGIN,
903 )
922 )
904 response = api_call(self, params)
923 response = api_call(self, params)
905 expected = 'Only RhodeCode admin can specify `owner` param'
924 expected = 'Only RhodeCode admin can specify `owner` param'
906 self._compare_error(id_, expected, given=response.body)
925 self._compare_error(id_, expected, given=response.body)
907 destroy_repo(fork_name)
926 destroy_repo(fork_name)
908
927
909 def test_api_fork_repo_non_admin_no_permission_to_fork(self):
928 def test_api_fork_repo_non_admin_no_permission_to_fork(self):
910 RepoModel().grant_user_permission(repo=self.REPO,
929 RepoModel().grant_user_permission(repo=self.REPO,
911 user=self.TEST_USER_LOGIN,
930 user=self.TEST_USER_LOGIN,
912 perm='repository.none')
931 perm='repository.none')
913 fork_name = 'api-repo-fork'
932 fork_name = 'api-repo-fork'
914 id_, params = _build_data(self.apikey_regular, 'fork_repo',
933 id_, params = _build_data(self.apikey_regular, 'fork_repo',
915 repoid=self.REPO,
934 repoid=self.REPO,
916 fork_name=fork_name,
935 fork_name=fork_name,
917 )
936 )
918 response = api_call(self, params)
937 response = api_call(self, params)
919 expected = 'repository `%s` does not exist' % (self.REPO)
938 expected = 'repository `%s` does not exist' % (self.REPO)
920 self._compare_error(id_, expected, given=response.body)
939 self._compare_error(id_, expected, given=response.body)
921 destroy_repo(fork_name)
940 destroy_repo(fork_name)
922
941
923 def test_api_fork_repo_unknown_owner(self):
942 def test_api_fork_repo_unknown_owner(self):
924 fork_name = 'api-repo-fork'
943 fork_name = 'api-repo-fork'
925 owner = 'i-dont-exist'
944 owner = 'i-dont-exist'
926 id_, params = _build_data(self.apikey, 'fork_repo',
945 id_, params = _build_data(self.apikey, 'fork_repo',
927 repoid=self.REPO,
946 repoid=self.REPO,
928 fork_name=fork_name,
947 fork_name=fork_name,
929 owner=owner,
948 owner=owner,
930 )
949 )
931 response = api_call(self, params)
950 response = api_call(self, params)
932 expected = 'user `%s` does not exist' % owner
951 expected = 'user `%s` does not exist' % owner
933 self._compare_error(id_, expected, given=response.body)
952 self._compare_error(id_, expected, given=response.body)
934
953
935 def test_api_fork_repo_fork_exists(self):
954 def test_api_fork_repo_fork_exists(self):
936 fork_name = 'api-repo-fork'
955 fork_name = 'api-repo-fork'
937 create_fork(fork_name, self.REPO_TYPE, self.REPO)
956 create_fork(fork_name, self.REPO_TYPE, self.REPO)
938
957
939 try:
958 try:
940 fork_name = 'api-repo-fork'
959 fork_name = 'api-repo-fork'
941
960
942 id_, params = _build_data(self.apikey, 'fork_repo',
961 id_, params = _build_data(self.apikey, 'fork_repo',
943 repoid=self.REPO,
962 repoid=self.REPO,
944 fork_name=fork_name,
963 fork_name=fork_name,
945 owner=TEST_USER_ADMIN_LOGIN,
964 owner=TEST_USER_ADMIN_LOGIN,
946 )
965 )
947 response = api_call(self, params)
966 response = api_call(self, params)
948
967
949 expected = "fork `%s` already exist" % fork_name
968 expected = "fork `%s` already exist" % fork_name
950 self._compare_error(id_, expected, given=response.body)
969 self._compare_error(id_, expected, given=response.body)
951 finally:
970 finally:
952 destroy_repo(fork_name)
971 destroy_repo(fork_name)
953
972
954 def test_api_fork_repo_repo_exists(self):
973 def test_api_fork_repo_repo_exists(self):
955 fork_name = self.REPO
974 fork_name = self.REPO
956
975
957 id_, params = _build_data(self.apikey, 'fork_repo',
976 id_, params = _build_data(self.apikey, 'fork_repo',
958 repoid=self.REPO,
977 repoid=self.REPO,
959 fork_name=fork_name,
978 fork_name=fork_name,
960 owner=TEST_USER_ADMIN_LOGIN,
979 owner=TEST_USER_ADMIN_LOGIN,
961 )
980 )
962 response = api_call(self, params)
981 response = api_call(self, params)
963
982
964 expected = "repo `%s` already exist" % fork_name
983 expected = "repo `%s` already exist" % fork_name
965 self._compare_error(id_, expected, given=response.body)
984 self._compare_error(id_, expected, given=response.body)
966
985
967 @mock.patch.object(RepoModel, 'create_fork', crash)
986 @mock.patch.object(RepoModel, 'create_fork', crash)
968 def test_api_fork_repo_exception_occurred(self):
987 def test_api_fork_repo_exception_occurred(self):
969 fork_name = 'api-repo-fork'
988 fork_name = 'api-repo-fork'
970 id_, params = _build_data(self.apikey, 'fork_repo',
989 id_, params = _build_data(self.apikey, 'fork_repo',
971 repoid=self.REPO,
990 repoid=self.REPO,
972 fork_name=fork_name,
991 fork_name=fork_name,
973 owner=TEST_USER_ADMIN_LOGIN,
992 owner=TEST_USER_ADMIN_LOGIN,
974 )
993 )
975 response = api_call(self, params)
994 response = api_call(self, params)
976
995
977 expected = 'failed to fork repository `%s` as `%s`' % (self.REPO,
996 expected = 'failed to fork repository `%s` as `%s`' % (self.REPO,
978 fork_name)
997 fork_name)
979 self._compare_error(id_, expected, given=response.body)
998 self._compare_error(id_, expected, given=response.body)
980
999
981 def test_api_get_users_group(self):
1000 def test_api_get_users_group(self):
982 id_, params = _build_data(self.apikey, 'get_users_group',
1001 id_, params = _build_data(self.apikey, 'get_users_group',
983 usersgroupid=TEST_USERS_GROUP)
1002 usersgroupid=TEST_USERS_GROUP)
984 response = api_call(self, params)
1003 response = api_call(self, params)
985
1004
986 users_group = UsersGroupModel().get_group(TEST_USERS_GROUP)
1005 users_group = UsersGroupModel().get_group(TEST_USERS_GROUP)
987 members = []
1006 members = []
988 for user in users_group.members:
1007 for user in users_group.members:
989 user = user.user
1008 user = user.user
990 members.append(user.get_api_data())
1009 members.append(user.get_api_data())
991
1010
992 ret = users_group.get_api_data()
1011 ret = users_group.get_api_data()
993 ret['members'] = members
1012 ret['members'] = members
994 expected = ret
1013 expected = ret
995 self._compare_ok(id_, expected, given=response.body)
1014 self._compare_ok(id_, expected, given=response.body)
996
1015
997 def test_api_get_users_groups(self):
1016 def test_api_get_users_groups(self):
998
1017
999 make_users_group('test_users_group2')
1018 make_users_group('test_users_group2')
1000
1019
1001 id_, params = _build_data(self.apikey, 'get_users_groups',)
1020 id_, params = _build_data(self.apikey, 'get_users_groups',)
1002 response = api_call(self, params)
1021 response = api_call(self, params)
1003
1022
1004 expected = []
1023 expected = []
1005 for gr_name in [TEST_USERS_GROUP, 'test_users_group2']:
1024 for gr_name in [TEST_USERS_GROUP, 'test_users_group2']:
1006 users_group = UsersGroupModel().get_group(gr_name)
1025 users_group = UsersGroupModel().get_group(gr_name)
1007 ret = users_group.get_api_data()
1026 ret = users_group.get_api_data()
1008 expected.append(ret)
1027 expected.append(ret)
1009 self._compare_ok(id_, expected, given=response.body)
1028 self._compare_ok(id_, expected, given=response.body)
1010
1029
1011 UsersGroupModel().delete(users_group='test_users_group2')
1030 UsersGroupModel().delete(users_group='test_users_group2')
1012 Session().commit()
1031 Session().commit()
1013
1032
1014 def test_api_create_users_group(self):
1033 def test_api_create_users_group(self):
1015 group_name = 'some_new_group'
1034 group_name = 'some_new_group'
1016 id_, params = _build_data(self.apikey, 'create_users_group',
1035 id_, params = _build_data(self.apikey, 'create_users_group',
1017 group_name=group_name)
1036 group_name=group_name)
1018 response = api_call(self, params)
1037 response = api_call(self, params)
1019
1038
1020 ret = {
1039 ret = {
1021 'msg': 'created new users group `%s`' % group_name,
1040 'msg': 'created new users group `%s`' % group_name,
1022 'users_group': jsonify(UsersGroupModel()\
1041 'users_group': jsonify(UsersGroupModel()\
1023 .get_by_name(group_name)\
1042 .get_by_name(group_name)\
1024 .get_api_data())
1043 .get_api_data())
1025 }
1044 }
1026 expected = ret
1045 expected = ret
1027 self._compare_ok(id_, expected, given=response.body)
1046 self._compare_ok(id_, expected, given=response.body)
1028
1047
1029 destroy_users_group(group_name)
1048 destroy_users_group(group_name)
1030
1049
1031 def test_api_get_users_group_that_exist(self):
1050 def test_api_get_users_group_that_exist(self):
1032 id_, params = _build_data(self.apikey, 'create_users_group',
1051 id_, params = _build_data(self.apikey, 'create_users_group',
1033 group_name=TEST_USERS_GROUP)
1052 group_name=TEST_USERS_GROUP)
1034 response = api_call(self, params)
1053 response = api_call(self, params)
1035
1054
1036 expected = "users group `%s` already exist" % TEST_USERS_GROUP
1055 expected = "users group `%s` already exist" % TEST_USERS_GROUP
1037 self._compare_error(id_, expected, given=response.body)
1056 self._compare_error(id_, expected, given=response.body)
1038
1057
1039 @mock.patch.object(UsersGroupModel, 'create', crash)
1058 @mock.patch.object(UsersGroupModel, 'create', crash)
1040 def test_api_get_users_group_exception_occurred(self):
1059 def test_api_get_users_group_exception_occurred(self):
1041 group_name = 'exception_happens'
1060 group_name = 'exception_happens'
1042 id_, params = _build_data(self.apikey, 'create_users_group',
1061 id_, params = _build_data(self.apikey, 'create_users_group',
1043 group_name=group_name)
1062 group_name=group_name)
1044 response = api_call(self, params)
1063 response = api_call(self, params)
1045
1064
1046 expected = 'failed to create group `%s`' % group_name
1065 expected = 'failed to create group `%s`' % group_name
1047 self._compare_error(id_, expected, given=response.body)
1066 self._compare_error(id_, expected, given=response.body)
1048
1067
1049 def test_api_add_user_to_users_group(self):
1068 def test_api_add_user_to_users_group(self):
1050 gr_name = 'test_group'
1069 gr_name = 'test_group'
1051 UsersGroupModel().create(gr_name)
1070 UsersGroupModel().create(gr_name)
1052 Session().commit()
1071 Session().commit()
1053 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1072 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1054 usersgroupid=gr_name,
1073 usersgroupid=gr_name,
1055 userid=TEST_USER_ADMIN_LOGIN)
1074 userid=TEST_USER_ADMIN_LOGIN)
1056 response = api_call(self, params)
1075 response = api_call(self, params)
1057
1076
1058 expected = {
1077 expected = {
1059 'msg': 'added member `%s` to users group `%s`' % (
1078 'msg': 'added member `%s` to users group `%s`' % (
1060 TEST_USER_ADMIN_LOGIN, gr_name
1079 TEST_USER_ADMIN_LOGIN, gr_name
1061 ),
1080 ),
1062 'success': True}
1081 'success': True}
1063 self._compare_ok(id_, expected, given=response.body)
1082 self._compare_ok(id_, expected, given=response.body)
1064
1083
1065 UsersGroupModel().delete(users_group=gr_name)
1084 UsersGroupModel().delete(users_group=gr_name)
1066 Session().commit()
1085 Session().commit()
1067
1086
1068 def test_api_add_user_to_users_group_that_doesnt_exist(self):
1087 def test_api_add_user_to_users_group_that_doesnt_exist(self):
1069 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1088 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1070 usersgroupid='false-group',
1089 usersgroupid='false-group',
1071 userid=TEST_USER_ADMIN_LOGIN)
1090 userid=TEST_USER_ADMIN_LOGIN)
1072 response = api_call(self, params)
1091 response = api_call(self, params)
1073
1092
1074 expected = 'users group `%s` does not exist' % 'false-group'
1093 expected = 'users group `%s` does not exist' % 'false-group'
1075 self._compare_error(id_, expected, given=response.body)
1094 self._compare_error(id_, expected, given=response.body)
1076
1095
1077 @mock.patch.object(UsersGroupModel, 'add_user_to_group', crash)
1096 @mock.patch.object(UsersGroupModel, 'add_user_to_group', crash)
1078 def test_api_add_user_to_users_group_exception_occurred(self):
1097 def test_api_add_user_to_users_group_exception_occurred(self):
1079 gr_name = 'test_group'
1098 gr_name = 'test_group'
1080 UsersGroupModel().create(gr_name)
1099 UsersGroupModel().create(gr_name)
1081 Session().commit()
1100 Session().commit()
1082 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1101 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1083 usersgroupid=gr_name,
1102 usersgroupid=gr_name,
1084 userid=TEST_USER_ADMIN_LOGIN)
1103 userid=TEST_USER_ADMIN_LOGIN)
1085 response = api_call(self, params)
1104 response = api_call(self, params)
1086
1105
1087 expected = 'failed to add member to users group `%s`' % gr_name
1106 expected = 'failed to add member to users group `%s`' % gr_name
1088 self._compare_error(id_, expected, given=response.body)
1107 self._compare_error(id_, expected, given=response.body)
1089
1108
1090 UsersGroupModel().delete(users_group=gr_name)
1109 UsersGroupModel().delete(users_group=gr_name)
1091 Session().commit()
1110 Session().commit()
1092
1111
1093 def test_api_remove_user_from_users_group(self):
1112 def test_api_remove_user_from_users_group(self):
1094 gr_name = 'test_group_3'
1113 gr_name = 'test_group_3'
1095 gr = UsersGroupModel().create(gr_name)
1114 gr = UsersGroupModel().create(gr_name)
1096 UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
1115 UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
1097 Session().commit()
1116 Session().commit()
1098 id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
1117 id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
1099 usersgroupid=gr_name,
1118 usersgroupid=gr_name,
1100 userid=TEST_USER_ADMIN_LOGIN)
1119 userid=TEST_USER_ADMIN_LOGIN)
1101 response = api_call(self, params)
1120 response = api_call(self, params)
1102
1121
1103 expected = {
1122 expected = {
1104 'msg': 'removed member `%s` from users group `%s`' % (
1123 'msg': 'removed member `%s` from users group `%s`' % (
1105 TEST_USER_ADMIN_LOGIN, gr_name
1124 TEST_USER_ADMIN_LOGIN, gr_name
1106 ),
1125 ),
1107 'success': True}
1126 'success': True}
1108 self._compare_ok(id_, expected, given=response.body)
1127 self._compare_ok(id_, expected, given=response.body)
1109
1128
1110 UsersGroupModel().delete(users_group=gr_name)
1129 UsersGroupModel().delete(users_group=gr_name)
1111 Session().commit()
1130 Session().commit()
1112
1131
1113 @mock.patch.object(UsersGroupModel, 'remove_user_from_group', crash)
1132 @mock.patch.object(UsersGroupModel, 'remove_user_from_group', crash)
1114 def test_api_remove_user_from_users_group_exception_occurred(self):
1133 def test_api_remove_user_from_users_group_exception_occurred(self):
1115 gr_name = 'test_group_3'
1134 gr_name = 'test_group_3'
1116 gr = UsersGroupModel().create(gr_name)
1135 gr = UsersGroupModel().create(gr_name)
1117 UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
1136 UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
1118 Session().commit()
1137 Session().commit()
1119 id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
1138 id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
1120 usersgroupid=gr_name,
1139 usersgroupid=gr_name,
1121 userid=TEST_USER_ADMIN_LOGIN)
1140 userid=TEST_USER_ADMIN_LOGIN)
1122 response = api_call(self, params)
1141 response = api_call(self, params)
1123
1142
1124 expected = 'failed to remove member from users group `%s`' % gr_name
1143 expected = 'failed to remove member from users group `%s`' % gr_name
1125 self._compare_error(id_, expected, given=response.body)
1144 self._compare_error(id_, expected, given=response.body)
1126
1145
1127 UsersGroupModel().delete(users_group=gr_name)
1146 UsersGroupModel().delete(users_group=gr_name)
1128 Session().commit()
1147 Session().commit()
1129
1148
1130 @parameterized.expand([('none', 'repository.none'),
1149 @parameterized.expand([('none', 'repository.none'),
1131 ('read', 'repository.read'),
1150 ('read', 'repository.read'),
1132 ('write', 'repository.write'),
1151 ('write', 'repository.write'),
1133 ('admin', 'repository.admin')])
1152 ('admin', 'repository.admin')])
1134 def test_api_grant_user_permission(self, name, perm):
1153 def test_api_grant_user_permission(self, name, perm):
1135 id_, params = _build_data(self.apikey, 'grant_user_permission',
1154 id_, params = _build_data(self.apikey, 'grant_user_permission',
1136 repoid=self.REPO,
1155 repoid=self.REPO,
1137 userid=TEST_USER_ADMIN_LOGIN,
1156 userid=TEST_USER_ADMIN_LOGIN,
1138 perm=perm)
1157 perm=perm)
1139 response = api_call(self, params)
1158 response = api_call(self, params)
1140
1159
1141 ret = {
1160 ret = {
1142 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1161 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1143 perm, TEST_USER_ADMIN_LOGIN, self.REPO
1162 perm, TEST_USER_ADMIN_LOGIN, self.REPO
1144 ),
1163 ),
1145 'success': True
1164 'success': True
1146 }
1165 }
1147 expected = ret
1166 expected = ret
1148 self._compare_ok(id_, expected, given=response.body)
1167 self._compare_ok(id_, expected, given=response.body)
1149
1168
1150 def test_api_grant_user_permission_wrong_permission(self):
1169 def test_api_grant_user_permission_wrong_permission(self):
1151 perm = 'haha.no.permission'
1170 perm = 'haha.no.permission'
1152 id_, params = _build_data(self.apikey, 'grant_user_permission',
1171 id_, params = _build_data(self.apikey, 'grant_user_permission',
1153 repoid=self.REPO,
1172 repoid=self.REPO,
1154 userid=TEST_USER_ADMIN_LOGIN,
1173 userid=TEST_USER_ADMIN_LOGIN,
1155 perm=perm)
1174 perm=perm)
1156 response = api_call(self, params)
1175 response = api_call(self, params)
1157
1176
1158 expected = 'permission `%s` does not exist' % perm
1177 expected = 'permission `%s` does not exist' % perm
1159 self._compare_error(id_, expected, given=response.body)
1178 self._compare_error(id_, expected, given=response.body)
1160
1179
1161 @mock.patch.object(RepoModel, 'grant_user_permission', crash)
1180 @mock.patch.object(RepoModel, 'grant_user_permission', crash)
1162 def test_api_grant_user_permission_exception_when_adding(self):
1181 def test_api_grant_user_permission_exception_when_adding(self):
1163 perm = 'repository.read'
1182 perm = 'repository.read'
1164 id_, params = _build_data(self.apikey, 'grant_user_permission',
1183 id_, params = _build_data(self.apikey, 'grant_user_permission',
1165 repoid=self.REPO,
1184 repoid=self.REPO,
1166 userid=TEST_USER_ADMIN_LOGIN,
1185 userid=TEST_USER_ADMIN_LOGIN,
1167 perm=perm)
1186 perm=perm)
1168 response = api_call(self, params)
1187 response = api_call(self, params)
1169
1188
1170 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1189 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1171 TEST_USER_ADMIN_LOGIN, self.REPO
1190 TEST_USER_ADMIN_LOGIN, self.REPO
1172 )
1191 )
1173 self._compare_error(id_, expected, given=response.body)
1192 self._compare_error(id_, expected, given=response.body)
1174
1193
1175 def test_api_revoke_user_permission(self):
1194 def test_api_revoke_user_permission(self):
1176 id_, params = _build_data(self.apikey, 'revoke_user_permission',
1195 id_, params = _build_data(self.apikey, 'revoke_user_permission',
1177 repoid=self.REPO,
1196 repoid=self.REPO,
1178 userid=TEST_USER_ADMIN_LOGIN,)
1197 userid=TEST_USER_ADMIN_LOGIN,)
1179 response = api_call(self, params)
1198 response = api_call(self, params)
1180
1199
1181 expected = {
1200 expected = {
1182 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1201 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1183 TEST_USER_ADMIN_LOGIN, self.REPO
1202 TEST_USER_ADMIN_LOGIN, self.REPO
1184 ),
1203 ),
1185 'success': True
1204 'success': True
1186 }
1205 }
1187 self._compare_ok(id_, expected, given=response.body)
1206 self._compare_ok(id_, expected, given=response.body)
1188
1207
1189 @mock.patch.object(RepoModel, 'revoke_user_permission', crash)
1208 @mock.patch.object(RepoModel, 'revoke_user_permission', crash)
1190 def test_api_revoke_user_permission_exception_when_adding(self):
1209 def test_api_revoke_user_permission_exception_when_adding(self):
1191 id_, params = _build_data(self.apikey, 'revoke_user_permission',
1210 id_, params = _build_data(self.apikey, 'revoke_user_permission',
1192 repoid=self.REPO,
1211 repoid=self.REPO,
1193 userid=TEST_USER_ADMIN_LOGIN,)
1212 userid=TEST_USER_ADMIN_LOGIN,)
1194 response = api_call(self, params)
1213 response = api_call(self, params)
1195
1214
1196 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1215 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1197 TEST_USER_ADMIN_LOGIN, self.REPO
1216 TEST_USER_ADMIN_LOGIN, self.REPO
1198 )
1217 )
1199 self._compare_error(id_, expected, given=response.body)
1218 self._compare_error(id_, expected, given=response.body)
1200
1219
1201 @parameterized.expand([('none', 'repository.none'),
1220 @parameterized.expand([('none', 'repository.none'),
1202 ('read', 'repository.read'),
1221 ('read', 'repository.read'),
1203 ('write', 'repository.write'),
1222 ('write', 'repository.write'),
1204 ('admin', 'repository.admin')])
1223 ('admin', 'repository.admin')])
1205 def test_api_grant_users_group_permission(self, name, perm):
1224 def test_api_grant_users_group_permission(self, name, perm):
1206 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1225 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1207 repoid=self.REPO,
1226 repoid=self.REPO,
1208 usersgroupid=TEST_USERS_GROUP,
1227 usersgroupid=TEST_USERS_GROUP,
1209 perm=perm)
1228 perm=perm)
1210 response = api_call(self, params)
1229 response = api_call(self, params)
1211
1230
1212 ret = {
1231 ret = {
1213 'msg': 'Granted perm: `%s` for users group: `%s` in repo: `%s`' % (
1232 'msg': 'Granted perm: `%s` for users group: `%s` in repo: `%s`' % (
1214 perm, TEST_USERS_GROUP, self.REPO
1233 perm, TEST_USERS_GROUP, self.REPO
1215 ),
1234 ),
1216 'success': True
1235 'success': True
1217 }
1236 }
1218 expected = ret
1237 expected = ret
1219 self._compare_ok(id_, expected, given=response.body)
1238 self._compare_ok(id_, expected, given=response.body)
1220
1239
1221 def test_api_grant_users_group_permission_wrong_permission(self):
1240 def test_api_grant_users_group_permission_wrong_permission(self):
1222 perm = 'haha.no.permission'
1241 perm = 'haha.no.permission'
1223 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1242 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1224 repoid=self.REPO,
1243 repoid=self.REPO,
1225 usersgroupid=TEST_USERS_GROUP,
1244 usersgroupid=TEST_USERS_GROUP,
1226 perm=perm)
1245 perm=perm)
1227 response = api_call(self, params)
1246 response = api_call(self, params)
1228
1247
1229 expected = 'permission `%s` does not exist' % perm
1248 expected = 'permission `%s` does not exist' % perm
1230 self._compare_error(id_, expected, given=response.body)
1249 self._compare_error(id_, expected, given=response.body)
1231
1250
1232 @mock.patch.object(RepoModel, 'grant_users_group_permission', crash)
1251 @mock.patch.object(RepoModel, 'grant_users_group_permission', crash)
1233 def test_api_grant_users_group_permission_exception_when_adding(self):
1252 def test_api_grant_users_group_permission_exception_when_adding(self):
1234 perm = 'repository.read'
1253 perm = 'repository.read'
1235 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1254 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1236 repoid=self.REPO,
1255 repoid=self.REPO,
1237 usersgroupid=TEST_USERS_GROUP,
1256 usersgroupid=TEST_USERS_GROUP,
1238 perm=perm)
1257 perm=perm)
1239 response = api_call(self, params)
1258 response = api_call(self, params)
1240
1259
1241 expected = 'failed to edit permission for users group: `%s` in repo: `%s`' % (
1260 expected = 'failed to edit permission for users group: `%s` in repo: `%s`' % (
1242 TEST_USERS_GROUP, self.REPO
1261 TEST_USERS_GROUP, self.REPO
1243 )
1262 )
1244 self._compare_error(id_, expected, given=response.body)
1263 self._compare_error(id_, expected, given=response.body)
1245
1264
1246 def test_api_revoke_users_group_permission(self):
1265 def test_api_revoke_users_group_permission(self):
1247 RepoModel().grant_users_group_permission(repo=self.REPO,
1266 RepoModel().grant_users_group_permission(repo=self.REPO,
1248 group_name=TEST_USERS_GROUP,
1267 group_name=TEST_USERS_GROUP,
1249 perm='repository.read')
1268 perm='repository.read')
1250 Session().commit()
1269 Session().commit()
1251 id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
1270 id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
1252 repoid=self.REPO,
1271 repoid=self.REPO,
1253 usersgroupid=TEST_USERS_GROUP,)
1272 usersgroupid=TEST_USERS_GROUP,)
1254 response = api_call(self, params)
1273 response = api_call(self, params)
1255
1274
1256 expected = {
1275 expected = {
1257 'msg': 'Revoked perm for users group: `%s` in repo: `%s`' % (
1276 'msg': 'Revoked perm for users group: `%s` in repo: `%s`' % (
1258 TEST_USERS_GROUP, self.REPO
1277 TEST_USERS_GROUP, self.REPO
1259 ),
1278 ),
1260 'success': True
1279 'success': True
1261 }
1280 }
1262 self._compare_ok(id_, expected, given=response.body)
1281 self._compare_ok(id_, expected, given=response.body)
1263
1282
1264 @mock.patch.object(RepoModel, 'revoke_users_group_permission', crash)
1283 @mock.patch.object(RepoModel, 'revoke_users_group_permission', crash)
1265 def test_api_revoke_users_group_permission_exception_when_adding(self):
1284 def test_api_revoke_users_group_permission_exception_when_adding(self):
1266
1285
1267 id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
1286 id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
1268 repoid=self.REPO,
1287 repoid=self.REPO,
1269 usersgroupid=TEST_USERS_GROUP,)
1288 usersgroupid=TEST_USERS_GROUP,)
1270 response = api_call(self, params)
1289 response = api_call(self, params)
1271
1290
1272 expected = 'failed to edit permission for users group: `%s` in repo: `%s`' % (
1291 expected = 'failed to edit permission for users group: `%s` in repo: `%s`' % (
1273 TEST_USERS_GROUP, self.REPO
1292 TEST_USERS_GROUP, self.REPO
1274 )
1293 )
1275 self._compare_error(id_, expected, given=response.body)
1294 self._compare_error(id_, expected, given=response.body)
General Comments 0
You need to be logged in to leave comments. Login now