##// END OF EJS Templates
implements #329...
marcink -
r1793:631caf88 beta
parent child Browse files
Show More
@@ -1,365 +1,382 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 in RhodeCode is
10 with JSON protocol both ways. An url to send API request in RhodeCode is
11 <your_server>/_admin/api
11 <your_server>/_admin/api
12
12
13
13
14 All clients are required to send JSON-RPC spec JSON data::
14 All clients are required to send JSON-RPC spec JSON data::
15
15
16 {
16 {
17 "id:<id>,
17 "id:<id>,
18 "api_key":"<api_key>",
18 "api_key":"<api_key>",
19 "method":"<method_name>",
19 "method":"<method_name>",
20 "args":{"<arg_key>":"<arg_val>"}
20 "args":{"<arg_key>":"<arg_val>"}
21 }
21 }
22
22
23 Example call for autopulling remotes repos using curl::
23 Example call for autopulling remotes repos using curl::
24 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"}}'
24 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"}}'
25
25
26 Simply provide
26 Simply provide
27 - *id* A value of any type, which is used to match the response with the request that it is replying to.
27 - *id* A value of any type, which is used to match the response with the request that it is replying to.
28 - *api_key* for access and permission validation.
28 - *api_key* for access and permission validation.
29 - *method* is name of method to call
29 - *method* is name of method to call
30 - *args* is an key:value list of arguments to pass to method
30 - *args* is an key:value list of arguments to pass to method
31
31
32 .. note::
32 .. note::
33
33
34 api_key can be found in your user account page
34 api_key can be found in your user account page
35
35
36
36
37 RhodeCode API will return always a JSON-RPC response::
37 RhodeCode API will return always a JSON-RPC response::
38
38
39 {
39 {
40 "id":<id>,
40 "id":<id>,
41 "result": "<result>",
41 "result": "<result>",
42 "error": null
42 "error": null
43 }
43 }
44
44
45 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
45 All responses from API will be `HTTP/1.0 200 OK`, if there's an error while
46 calling api *error* key from response will contain failure description
46 calling api *error* key from response will contain failure description
47 and result will be null.
47 and result will be null.
48
48
49 API METHODS
49 API METHODS
50 +++++++++++
50 +++++++++++
51
51
52
52
53 pull
53 pull
54 ----
54 ----
55
55
56 Pulls given repo from remote location. Can be used to automatically keep
56 Pulls given repo from remote location. Can be used to automatically keep
57 remote repos up to date. This command can be executed only using api_key
57 remote repos up to date. This command can be executed only using api_key
58 belonging to user with admin rights
58 belonging to user with admin rights
59
59
60 INPUT::
60 INPUT::
61
61
62 api_key : "<api_key>"
62 api_key : "<api_key>"
63 method : "pull"
63 method : "pull"
64 args : {
64 args : {
65 "repo" : "<repo_name>"
65 "repo" : "<repo_name>"
66 }
66 }
67
67
68 OUTPUT::
68 OUTPUT::
69
69
70 result : "Pulled from <repo_name>"
70 result : "Pulled from <repo_name>"
71 error : null
71 error : null
72
72
73
73
74 get_users
74 get_users
75 ---------
75 ---------
76
76
77 Lists all existing users. This command can be executed only using api_key
77 Lists all existing users. This command can be executed only using api_key
78 belonging to user with admin rights.
78 belonging to user with admin rights.
79
79
80 INPUT::
80 INPUT::
81
81
82 api_key : "<api_key>"
82 api_key : "<api_key>"
83 method : "get_users"
83 method : "get_users"
84 args : { }
84 args : { }
85
85
86 OUTPUT::
86 OUTPUT::
87
87
88 result: [
88 result: [
89 {
89 {
90 "id" : "<id>",
90 "id" : "<id>",
91 "username" : "<username>",
91 "username" : "<username>",
92 "firstname": "<firstname>",
92 "firstname": "<firstname>",
93 "lastname" : "<lastname>",
93 "lastname" : "<lastname>",
94 "email" : "<email>",
94 "email" : "<email>",
95 "active" : "<bool>",
95 "active" : "<bool>",
96 "admin" :Β  "<bool>",
96 "admin" :Β  "<bool>",
97 "ldap" : "<ldap_dn>"
97 "ldap" : "<ldap_dn>"
98 },
98 },
99 …
99 …
100 ]
100 ]
101 error: null
101 error: null
102
102
103 create_user
103 create_user
104 -----------
104 -----------
105
105
106 Creates new user in RhodeCode. This command can be executed only using api_key
106 Creates new user in RhodeCode. This command can be executed only using api_key
107 belonging to user with admin rights.
107 belonging to user with admin rights.
108
108
109 INPUT::
109 INPUT::
110
110
111 api_key : "<api_key>"
111 api_key : "<api_key>"
112 method : "create_user"
112 method : "create_user"
113 args : {
113 args : {
114 "username" : "<username>",
114 "username" : "<username>",
115 "password" : "<password>",
115 "password" : "<password>",
116 "firstname" : "<firstname>",
116 "firstname" : "<firstname>",
117 "lastname" : "<lastname>",
117 "lastname" : "<lastname>",
118 "email" : "<useremail>"
118 "email" : "<useremail>"
119 "active" : "<bool> = True",
119 "active" : "<bool> = True",
120 "admin" : "<bool> = False",
120 "admin" : "<bool> = False",
121 "ldap_dn" : "<ldap_dn> = None"
121 "ldap_dn" : "<ldap_dn> = None"
122 }
122 }
123
123
124 OUTPUT::
124 OUTPUT::
125
125
126 result: {
126 result: {
127 "msg" : "created new user <username>"
127 "msg" : "created new user <username>"
128 }
128 }
129 error: null
129 error: null
130
130
131 get_users_groups
131 get_users_groups
132 ----------------
132 ----------------
133
133
134 Lists all existing users groups. This command can be executed only using api_key
134 Lists all existing users groups. This command can be executed only using api_key
135 belonging to user with admin rights.
135 belonging to user with admin rights.
136
136
137 INPUT::
137 INPUT::
138
138
139 api_key : "<api_key>"
139 api_key : "<api_key>"
140 method : "get_users_groups"
140 method : "get_users_groups"
141 args : { }
141 args : { }
142
142
143 OUTPUT::
143 OUTPUT::
144
144
145 result : [
145 result : [
146 {
146 {
147 "id" : "<id>",
147 "id" : "<id>",
148 "name" : "<name>",
148 "name" : "<name>",
149 "active": "<bool>",
149 "active": "<bool>",
150 "members" : [
150 "members" : [
151 {
151 {
152 "id" : "<userid>",
152 "id" : "<userid>",
153 "username" : "<username>",
153 "username" : "<username>",
154 "firstname": "<firstname>",
154 "firstname": "<firstname>",
155 "lastname" : "<lastname>",
155 "lastname" : "<lastname>",
156 "email" : "<email>",
156 "email" : "<email>",
157 "active" : "<bool>",
157 "active" : "<bool>",
158 "admin" :Β  "<bool>",
158 "admin" :Β  "<bool>",
159 "ldap" : "<ldap_dn>"
159 "ldap" : "<ldap_dn>"
160 },
160 },
161 …
161 …
162 ]
162 ]
163 }
163 }
164 ]
164 ]
165 error : null
165 error : null
166
166
167 get_users_group
167 get_users_group
168 ---------------
168 ---------------
169
169
170 Gets an existing users group. This command can be executed only using api_key
170 Gets an existing users group. This command can be executed only using api_key
171 belonging to user with admin rights.
171 belonging to user with admin rights.
172
172
173 INPUT::
173 INPUT::
174
174
175 api_key : "<api_key>"
175 api_key : "<api_key>"
176 method : "get_users_group"
176 method : "get_users_group"
177 args : {
177 args : {
178 "group_name" : "<name>"
178 "group_name" : "<name>"
179 }
179 }
180
180
181 OUTPUT::
181 OUTPUT::
182
182
183 result : None if group not exist
183 result : None if group not exist
184 {
184 {
185 "id" : "<id>",
185 "id" : "<id>",
186 "name" : "<name>",
186 "name" : "<name>",
187 "active": "<bool>",
187 "active": "<bool>",
188 "members" : [
188 "members" : [
189 { "id" : "<userid>",
189 { "id" : "<userid>",
190 "username" : "<username>",
190 "username" : "<username>",
191 "firstname": "<firstname>",
191 "firstname": "<firstname>",
192 "lastname" : "<lastname>",
192 "lastname" : "<lastname>",
193 "email" : "<email>",
193 "email" : "<email>",
194 "active" : "<bool>",
194 "active" : "<bool>",
195 "admin" :Β  "<bool>",
195 "admin" :Β  "<bool>",
196 "ldap" : "<ldap_dn>"
196 "ldap" : "<ldap_dn>"
197 },
197 },
198 …
198 …
199 ]
199 ]
200 }
200 }
201 error : null
201 error : null
202
202
203 create_users_group
203 create_users_group
204 ------------------
204 ------------------
205
205
206 Creates new users group. This command can be executed only using api_key
206 Creates new users group. This command can be executed only using api_key
207 belonging to user with admin rights
207 belonging to user with admin rights
208
208
209 INPUT::
209 INPUT::
210
210
211 api_key : "<api_key>"
211 api_key : "<api_key>"
212 method : "create_users_group"
212 method : "create_users_group"
213 args: {
213 args: {
214 "name": "<name>",
214 "name": "<name>",
215 "active":"<bool> = True"
215 "active":"<bool> = True"
216 }
216 }
217
217
218 OUTPUT::
218 OUTPUT::
219
219
220 result: {
220 result: {
221 "id": "<newusersgroupid>",
221 "id": "<newusersgroupid>",
222 "msg": "created new users group <name>"
222 "msg": "created new users group <name>"
223 }
223 }
224 error: null
224 error: null
225
225
226 add_user_to_users_groups
226 add_user_to_users_group
227 ------------------------
227 -----------------------
228
228
229 Adds a user to a users group. This command can be executed only using api_key
229 Adds a user to a users group. This command can be executed only using api_key
230 belonging to user with admin rights
230 belonging to user with admin rights
231
231
232 INPUT::
232 INPUT::
233
233
234 api_key : "<api_key>"
234 api_key : "<api_key>"
235 method : "add_user_users_group"
235 method : "add_user_users_group"
236 args: {
236 args: {
237 "group_name" : "<groupname>",
237 "group_name" : "<groupname>",
238 "user_name" : "<username>"
238 "user_name" : "<username>"
239 }
239 }
240
240
241 OUTPUT::
241 OUTPUT::
242
242
243 result: {
243 result: {
244 "id": "<newusersgroupmemberid>",
244 "id": "<newusersgroupmemberid>",
245 "msg": "created new users group member"
245 "msg": "created new users group member"
246 }
246 }
247 error: null
247 error: null
248
248
249 get_repos
249 get_repos
250 ---------
250 ---------
251
251
252 Lists all existing repositories. This command can be executed only using api_key
252 Lists all existing repositories. This command can be executed only using api_key
253 belonging to user with admin rights
253 belonging to user with admin rights
254
254
255 INPUT::
255 INPUT::
256
256
257 api_key : "<api_key>"
257 api_key : "<api_key>"
258 method : "get_repos"
258 method : "get_repos"
259 args: { }
259 args: { }
260
260
261 OUTPUT::
261 OUTPUT::
262
262
263 result: [
263 result: [
264 {
264 {
265 "id" : "<id>",
265 "id" : "<id>",
266 "name" : "<name>"
266 "name" : "<name>"
267 "type" : "<type>",
267 "type" : "<type>",
268 "description" : "<description>"
268 "description" : "<description>"
269 },
269 },
270 …
270 …
271 ]
271 ]
272 error: null
272 error: null
273
273
274 get_repo
274 get_repo
275 --------
275 --------
276
276
277 Gets an existing repository. This command can be executed only using api_key
277 Gets an existing repository. This command can be executed only using api_key
278 belonging to user with admin rights
278 belonging to user with admin rights
279
279
280 INPUT::
280 INPUT::
281
281
282 api_key : "<api_key>"
282 api_key : "<api_key>"
283 method : "get_repo"
283 method : "get_repo"
284 args: {
284 args: {
285 "name" : "<name>"
285 "name" : "<name>"
286 }
286 }
287
287
288 OUTPUT::
288 OUTPUT::
289
289
290 result: None if repository not exist
290 result: None if repository not exist
291 {
291 {
292 "id" : "<id>",
292 "id" : "<id>",
293 "name" : "<name>"
293 "name" : "<name>"
294 "type" : "<type>",
294 "type" : "<type>",
295 "description" : "<description>",
295 "description" : "<description>",
296 "members" : [
296 "members" : [
297 { "id" : "<userid>",
297 { "id" : "<userid>",
298 "username" : "<username>",
298 "username" : "<username>",
299 "firstname": "<firstname>",
299 "firstname": "<firstname>",
300 "lastname" : "<lastname>",
300 "lastname" : "<lastname>",
301 "email" : "<email>",
301 "email" : "<email>",
302 "active" : "<bool>",
302 "active" : "<bool>",
303 "admin" :Β  "<bool>",
303 "admin" :Β  "<bool>",
304 "ldap" : "<ldap_dn>",
304 "ldap" : "<ldap_dn>",
305 "permission" : "repository_(read|write|admin)"
305 "permission" : "repository.(read|write|admin)"
306 },
306 },
307 …
307 …
308 {
308 {
309 "id" : "<usersgroupid>",
309 "id" : "<usersgroupid>",
310 "name" : "<usersgroupname>",
310 "name" : "<usersgroupname>",
311 "active": "<bool>",
311 "active": "<bool>",
312 "permission" : "repository_(read|write|admin)"
312 "permission" : "repository.(read|write|admin)"
313 },
313 },
314 …
314 …
315 ]
315 ]
316 }
316 }
317 error: null
317 error: null
318
318
319 create_repo
319 create_repo
320 -----------
320 -----------
321
321
322 Creates a repository. This command can be executed only using api_key
322 Creates a repository. This command can be executed only using api_key
323 belonging to user with admin rights.
323 belonging to user with admin rights.
324 If repository name contains "/", all needed repository groups will be created.
324 If repository name contains "/", all needed repository groups will be created.
325 For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
325 For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
326 and create "baz" repository with "bar" as group.
326 and create "baz" repository with "bar" as group.
327
327
328 INPUT::
328 INPUT::
329
329
330 api_key : "<api_key>"
330 api_key : "<api_key>"
331 method : "create_repo"
331 method : "create_repo"
332 args: {
332 args: {
333 "name" : "<name>",
333 "name" : "<name>",
334 "owner_name" : "<ownername>",
334 "owner_name" : "<ownername>",
335 "description" : "<description> = ''",
335 "description" : "<description> = ''",
336 "repo_type" : "<type> = 'hg'",
336 "repo_type" : "<type> = 'hg'",
337 "private" : "<bool> = False"
337 "private" : "<bool> = False"
338 }
338 }
339
339
340 OUTPUT::
340 OUTPUT::
341
341
342 result: None
342 result: None
343 error: null
343 error: null
344
344
345 add_user_to_repo
345 add_user_to_repo
346 ----------------
346 ----------------
347
347
348 Add a user to a repository. This command can be executed only using api_key
348 Add a user to a repository. This command can be executed only using api_key
349 belonging to user with admin rights.
349 belonging to user with admin rights.
350 If "perm" is None, user will be removed from the repository.
350 If "perm" is None, user will be removed from the repository.
351
351
352 INPUT::
352 INPUT::
353
353
354 api_key : "<api_key>"
354 api_key : "<api_key>"
355 method : "add_user_to_repo"
355 method : "add_user_to_repo"
356 args: {
356 args: {
357 "repo_name" : "<reponame>",
357 "repo_name" : "<reponame>",
358 "user_name" : "<username>",
358 "user_name" : "<username>",
359 "perm" : "(None|repository_(read|write|admin))",
359 "perm" : "(None|repository.(read|write|admin))",
360 }
360 }
361
361
362 OUTPUT::
362 OUTPUT::
363
363
364 result: None
364 result: None
365 error: null
365 error: null
366
367 add_users_group_to_repo
368 -----------------------
369
370 Add a users group to a repository. This command can be executed only using
371 api_key belonging to user with admin rights. If "perm" is None, group will
372 be removed from the repository.
373
374 INPUT::
375
376 api_key : "<api_key>"
377 method : "add_users_group_to_repo"
378 args: {
379 "repo_name" : "<reponame>",
380 "group_name" : "<groupname>",
381 "perm" : "(None|repository.(read|write|admin))",
382 } No newline at end of file
@@ -1,253 +1,257 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.api
3 rhodecode.controllers.api
4 ~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 JSON RPC controller
6 JSON RPC controller
7
7
8 :created_on: Aug 20, 2011
8 :created_on: Aug 20, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2010 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 inspect
28 import inspect
29 import logging
29 import logging
30 import types
30 import types
31 import urllib
31 import urllib
32 import traceback
32 import traceback
33
33
34 from rhodecode.lib.compat import izip_longest, json
34 from rhodecode.lib.compat import izip_longest, json
35
35
36 from paste.response import replace_header
36 from paste.response import replace_header
37
37
38 from pylons.controllers import WSGIController
38 from pylons.controllers import WSGIController
39
39
40
40
41 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
41 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
42 HTTPBadRequest, HTTPError
42 HTTPBadRequest, HTTPError
43
43
44 from rhodecode.model.db import User
44 from rhodecode.model.db import User
45 from rhodecode.lib.auth import AuthUser
45 from rhodecode.lib.auth import AuthUser
46
46
47 log = logging.getLogger('JSONRPC')
47 log = logging.getLogger('JSONRPC')
48
48
49
49 class JSONRPCError(BaseException):
50 class JSONRPCError(BaseException):
50
51
51 def __init__(self, message):
52 def __init__(self, message):
52 self.message = message
53 self.message = message
53 super(JSONRPCError, self).__init__()
54 super(JSONRPCError, self).__init__()
54
55
55 def __str__(self):
56 def __str__(self):
56 return str(self.message)
57 return str(self.message)
57
58
58
59
59 def jsonrpc_error(message, code=None):
60 def jsonrpc_error(message, code=None):
60 """
61 """
61 Generate a Response object with a JSON-RPC error body
62 Generate a Response object with a JSON-RPC error body
62 """
63 """
63 from pylons.controllers.util import Response
64 from pylons.controllers.util import Response
64 resp = Response(body=json.dumps(dict(id=None, result=None, error=message)),
65 resp = Response(body=json.dumps(dict(id=None, result=None, error=message)),
65 status=code,
66 status=code,
66 content_type='application/json')
67 content_type='application/json')
67 return resp
68 return resp
68
69
69
70
70
71 class JSONRPCController(WSGIController):
71 class JSONRPCController(WSGIController):
72 """
72 """
73 A WSGI-speaking JSON-RPC controller class
73 A WSGI-speaking JSON-RPC controller class
74
74
75 See the specification:
75 See the specification:
76 <http://json-rpc.org/wiki/specification>`.
76 <http://json-rpc.org/wiki/specification>`.
77
77
78 Valid controller return values should be json-serializable objects.
78 Valid controller return values should be json-serializable objects.
79
79
80 Sub-classes should catch their exceptions and raise JSONRPCError
80 Sub-classes should catch their exceptions and raise JSONRPCError
81 if they want to pass meaningful errors to the client.
81 if they want to pass meaningful errors to the client.
82
82
83 """
83 """
84
84
85 def _get_method_args(self):
85 def _get_method_args(self):
86 """
86 """
87 Return `self._rpc_args` to dispatched controller method
87 Return `self._rpc_args` to dispatched controller method
88 chosen by __call__
88 chosen by __call__
89 """
89 """
90 return self._rpc_args
90 return self._rpc_args
91
91
92 def __call__(self, environ, start_response):
92 def __call__(self, environ, start_response):
93 """
93 """
94 Parse the request body as JSON, look up the method on the
94 Parse the request body as JSON, look up the method on the
95 controller and if it exists, dispatch to it.
95 controller and if it exists, dispatch to it.
96 """
96 """
97 if 'CONTENT_LENGTH' not in environ:
97 if 'CONTENT_LENGTH' not in environ:
98 log.debug("No Content-Length")
98 log.debug("No Content-Length")
99 return jsonrpc_error(message="No Content-Length in request")
99 return jsonrpc_error(message="No Content-Length in request")
100 else:
100 else:
101 length = environ['CONTENT_LENGTH'] or 0
101 length = environ['CONTENT_LENGTH'] or 0
102 length = int(environ['CONTENT_LENGTH'])
102 length = int(environ['CONTENT_LENGTH'])
103 log.debug('Content-Length: %s', length)
103 log.debug('Content-Length: %s', length)
104
104
105 if length == 0:
105 if length == 0:
106 log.debug("Content-Length is 0")
106 log.debug("Content-Length is 0")
107 return jsonrpc_error(message="Content-Length is 0")
107 return jsonrpc_error(message="Content-Length is 0")
108
108
109 raw_body = environ['wsgi.input'].read(length)
109 raw_body = environ['wsgi.input'].read(length)
110
110
111 try:
111 try:
112 json_body = json.loads(urllib.unquote_plus(raw_body))
112 json_body = json.loads(urllib.unquote_plus(raw_body))
113 except ValueError, e:
113 except ValueError, e:
114 #catch JSON errors Here
114 # catch JSON errors Here
115 return jsonrpc_error(message="JSON parse error ERR:%s RAW:%r" \
115 return jsonrpc_error(message="JSON parse error ERR:%s RAW:%r" \
116 % (e, urllib.unquote_plus(raw_body)))
116 % (e, urllib.unquote_plus(raw_body)))
117
117
118 # check AUTH based on API KEY
118 # check AUTH based on API KEY
119 try:
119 try:
120 self._req_api_key = json_body['api_key']
120 self._req_api_key = json_body['api_key']
121 self._req_id = json_body['id']
121 self._req_id = json_body['id']
122 self._req_method = json_body['method']
122 self._req_method = json_body['method']
123 self._req_params = json_body['args']
123 self._request_params = json_body['args']
124 log.debug('method: %s, params: %s',
124 log.debug('method: %s, params: %s',
125 self._req_method,
125 self._req_method,
126 self._req_params)
126 self._request_params)
127 except KeyError, e:
127 except KeyError, e:
128 return jsonrpc_error(message='Incorrect JSON query missing %s' % e)
128 return jsonrpc_error(message='Incorrect JSON query missing %s' % e)
129
129
130 # check if we can find this session using api_key
130 # check if we can find this session using api_key
131 try:
131 try:
132 u = User.get_by_api_key(self._req_api_key)
132 u = User.get_by_api_key(self._req_api_key)
133 if u is None:
133 if u is None:
134 return jsonrpc_error(message='Invalid API KEY')
134 return jsonrpc_error(message='Invalid API KEY')
135 auth_u = AuthUser(u.user_id, self._req_api_key)
135 auth_u = AuthUser(u.user_id, self._req_api_key)
136 except Exception, e:
136 except Exception, e:
137 return jsonrpc_error(message='Invalid API KEY')
137 return jsonrpc_error(message='Invalid API KEY')
138
138
139 self._error = None
139 self._error = None
140 try:
140 try:
141 self._func = self._find_method()
141 self._func = self._find_method()
142 except AttributeError, e:
142 except AttributeError, e:
143 return jsonrpc_error(message=str(e))
143 return jsonrpc_error(message=str(e))
144
144
145 # now that we have a method, add self._req_params to
145 # now that we have a method, add self._req_params to
146 # self.kargs and dispatch control to WGIController
146 # self.kargs and dispatch control to WGIController
147 argspec = inspect.getargspec(self._func)
147 argspec = inspect.getargspec(self._func)
148 arglist = argspec[0][1:]
148 arglist = argspec[0][1:]
149 defaults = argspec[3] or []
149 defaults = map(type, argspec[3] or [])
150 default_empty = types.NotImplementedType
150 default_empty = types.NotImplementedType
151
151
152 kwarglist = list(izip_longest(reversed(arglist), reversed(defaults),
152 # kw arguments required by this method
153 func_kwargs = dict(izip_longest(reversed(arglist), reversed(defaults),
153 fillvalue=default_empty))
154 fillvalue=default_empty))
154
155
155 # this is little trick to inject logged in user for
156 # this is little trick to inject logged in user for
156 # perms decorators to work they expect the controller class to have
157 # perms decorators to work they expect the controller class to have
157 # rhodecode_user attribute set
158 # rhodecode_user attribute set
158 self.rhodecode_user = auth_u
159 self.rhodecode_user = auth_u
159
160
160 # This attribute will need to be first param of a method that uses
161 # This attribute will need to be first param of a method that uses
161 # api_key, which is translated to instance of user at that name
162 # api_key, which is translated to instance of user at that name
162 USER_SESSION_ATTR = 'apiuser'
163 USER_SESSION_ATTR = 'apiuser'
163
164
164 if USER_SESSION_ATTR not in arglist:
165 if USER_SESSION_ATTR not in arglist:
165 return jsonrpc_error(message='This method [%s] does not support '
166 return jsonrpc_error(message='This method [%s] does not support '
166 'authentication (missing %s param)' %
167 'authentication (missing %s param)' %
167 (self._func.__name__, USER_SESSION_ATTR))
168 (self._func.__name__, USER_SESSION_ATTR))
168
169
169 # get our arglist and check if we provided them as args
170 # get our arglist and check if we provided them as args
170 for arg, default in kwarglist:
171 for arg, default in func_kwargs.iteritems():
171 if arg == USER_SESSION_ATTR:
172 if arg == USER_SESSION_ATTR:
172 # USER_SESSION_ATTR is something translated from api key and
173 # USER_SESSION_ATTR is something translated from api key and
173 # this is checked before so we don't need validate it
174 # this is checked before so we don't need validate it
174 continue
175 continue
175
176
176 # skip the required param check if it's default value is
177 # skip the required param check if it's default value is
177 # NotImplementedType (default_empty)
178 # NotImplementedType (default_empty)
178 if not self._req_params or (type(default) == default_empty
179 if (default == default_empty and arg not in self._request_params):
179 and arg not in self._req_params):
180 return jsonrpc_error(
180 return jsonrpc_error(message=('Missing non optional %s arg '
181 message=(
181 'in JSON DATA') % arg)
182 'Missing non optional `%s` arg in JSON DATA' % arg
183 )
184 )
182
185
183 self._rpc_args = {USER_SESSION_ATTR:u}
186 self._rpc_args = {USER_SESSION_ATTR: u}
184 self._rpc_args.update(self._req_params)
187 self._rpc_args.update(self._request_params)
185
188
186 self._rpc_args['action'] = self._req_method
189 self._rpc_args['action'] = self._req_method
187 self._rpc_args['environ'] = environ
190 self._rpc_args['environ'] = environ
188 self._rpc_args['start_response'] = start_response
191 self._rpc_args['start_response'] = start_response
189
192
190 status = []
193 status = []
191 headers = []
194 headers = []
192 exc_info = []
195 exc_info = []
196
193 def change_content(new_status, new_headers, new_exc_info=None):
197 def change_content(new_status, new_headers, new_exc_info=None):
194 status.append(new_status)
198 status.append(new_status)
195 headers.extend(new_headers)
199 headers.extend(new_headers)
196 exc_info.append(new_exc_info)
200 exc_info.append(new_exc_info)
197
201
198 output = WSGIController.__call__(self, environ, change_content)
202 output = WSGIController.__call__(self, environ, change_content)
199 output = list(output)
203 output = list(output)
200 headers.append(('Content-Length', str(len(output[0]))))
204 headers.append(('Content-Length', str(len(output[0]))))
201 replace_header(headers, 'Content-Type', 'application/json')
205 replace_header(headers, 'Content-Type', 'application/json')
202 start_response(status[0], headers, exc_info[0])
206 start_response(status[0], headers, exc_info[0])
203
207
204 return output
208 return output
205
209
206 def _dispatch_call(self):
210 def _dispatch_call(self):
207 """
211 """
208 Implement dispatch interface specified by WSGIController
212 Implement dispatch interface specified by WSGIController
209 """
213 """
210 try:
214 try:
211 raw_response = self._inspect_call(self._func)
215 raw_response = self._inspect_call(self._func)
212 if isinstance(raw_response, HTTPError):
216 if isinstance(raw_response, HTTPError):
213 self._error = str(raw_response)
217 self._error = str(raw_response)
214 except JSONRPCError, e:
218 except JSONRPCError, e:
215 self._error = str(e)
219 self._error = str(e)
216 except Exception, e:
220 except Exception, e:
217 log.error('Encountered unhandled exception: %s' \
221 log.error('Encountered unhandled exception: %s' \
218 % traceback.format_exc())
222 % traceback.format_exc())
219 json_exc = JSONRPCError('Internal server error')
223 json_exc = JSONRPCError('Internal server error')
220 self._error = str(json_exc)
224 self._error = str(json_exc)
221
225
222 if self._error is not None:
226 if self._error is not None:
223 raw_response = None
227 raw_response = None
224
228
225 response = dict(id=self._req_id, result=raw_response,
229 response = dict(id=self._req_id, result=raw_response,
226 error=self._error)
230 error=self._error)
227
231
228 try:
232 try:
229 return json.dumps(response)
233 return json.dumps(response)
230 except TypeError, e:
234 except TypeError, e:
231 log.debug('Error encoding response: %s', e)
235 log.debug('Error encoding response: %s', e)
232 return json.dumps(dict(result=None,
236 return json.dumps(dict(result=None,
233 error="Error encoding response"))
237 error="Error encoding response"))
234
238
235 def _find_method(self):
239 def _find_method(self):
236 """
240 """
237 Return method named by `self._req_method` in controller if able
241 Return method named by `self._req_method` in controller if able
238 """
242 """
239 log.debug('Trying to find JSON-RPC method: %s', self._req_method)
243 log.debug('Trying to find JSON-RPC method: %s', self._req_method)
240 if self._req_method.startswith('_'):
244 if self._req_method.startswith('_'):
241 raise AttributeError("Method not allowed")
245 raise AttributeError("Method not allowed")
242
246
243 try:
247 try:
244 func = getattr(self, self._req_method, None)
248 func = getattr(self, self._req_method, None)
245 except UnicodeEncodeError:
249 except UnicodeEncodeError:
246 raise AttributeError("Problem decoding unicode in requested "
250 raise AttributeError("Problem decoding unicode in requested "
247 "method name.")
251 "method name.")
248
252
249 if isinstance(func, types.MethodType):
253 if isinstance(func, types.MethodType):
250 return func
254 return func
251 else:
255 else:
252 raise AttributeError("No such method: %s" % self._req_method)
256 raise AttributeError("No such method: %s" % self._req_method)
253
257
@@ -1,369 +1,444 b''
1 import traceback
1 import traceback
2 import logging
2 import logging
3
3
4 from sqlalchemy.orm.exc import NoResultFound
4 from sqlalchemy.orm.exc import NoResultFound
5
5
6 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
6 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
7 from rhodecode.lib.auth import HasPermissionAllDecorator, \
7 from rhodecode.lib.auth import HasPermissionAllDecorator, \
8 HasPermissionAnyDecorator
8 HasPermissionAnyDecorator
9
9
10 from rhodecode.model.meta import Session
10 from rhodecode.model.meta import Session
11 from rhodecode.model.scm import ScmModel
11 from rhodecode.model.scm import ScmModel
12 from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository
12 from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository
13 from rhodecode.model.repo import RepoModel
13 from rhodecode.model.repo import RepoModel
14 from rhodecode.model.user import UserModel
14 from rhodecode.model.user import UserModel
15 from rhodecode.model.repo_permission import RepositoryPermissionModel
15 from rhodecode.model.repo_permission import RepositoryPermissionModel
16 from rhodecode.model.users_group import UsersGroupModel
16 from rhodecode.model.users_group import UsersGroupModel
17 from rhodecode.model.repos_group import ReposGroupModel
17 from rhodecode.model.repos_group import ReposGroupModel
18
18
19
19
20 log = logging.getLogger(__name__)
20 log = logging.getLogger(__name__)
21
21
22
22
23 class ApiController(JSONRPCController):
23 class ApiController(JSONRPCController):
24 """
24 """
25 API Controller
25 API Controller
26
26
27
27
28 Each method needs to have USER as argument this is then based on given
28 Each method needs to have USER as argument this is then based on given
29 API_KEY propagated as instance of user object
29 API_KEY propagated as instance of user object
30
30
31 Preferably this should be first argument also
31 Preferably this should be first argument also
32
32
33
33
34 Each function should also **raise** JSONRPCError for any
34 Each function should also **raise** JSONRPCError for any
35 errors that happens
35 errors that happens
36
36
37 """
37 """
38
38
39 @HasPermissionAllDecorator('hg.admin')
39 @HasPermissionAllDecorator('hg.admin')
40 def pull(self, apiuser, repo):
40 def pull(self, apiuser, repo):
41 """
41 """
42 Dispatch pull action on given repo
42 Dispatch pull action on given repo
43
43
44
44
45 :param user:
45 :param user:
46 :param repo:
46 :param repo:
47 """
47 """
48
48
49 if Repository.is_valid(repo) is False:
49 if Repository.is_valid(repo) is False:
50 raise JSONRPCError('Unknown repo "%s"' % repo)
50 raise JSONRPCError('Unknown repo "%s"' % repo)
51
51
52 try:
52 try:
53 ScmModel().pull_changes(repo, self.rhodecode_user.username)
53 ScmModel().pull_changes(repo, self.rhodecode_user.username)
54 return 'Pulled from %s' % repo
54 return 'Pulled from %s' % repo
55 except Exception:
55 except Exception:
56 raise JSONRPCError('Unable to pull changes from "%s"' % repo)
56 raise JSONRPCError('Unable to pull changes from "%s"' % repo)
57
57
58 @HasPermissionAllDecorator('hg.admin')
58 @HasPermissionAllDecorator('hg.admin')
59 def get_user(self, apiuser, username):
59 def get_user(self, apiuser, username):
60 """"
60 """"
61 Get a user by username
61 Get a user by username
62
62
63 :param apiuser
63 :param apiuser:
64 :param username
64 :param username:
65 """
65 """
66
66
67 user = User.get_by_username(username)
67 user = User.get_by_username(username)
68 if not user:
68 if not user:
69 return None
69 return None
70
70
71 return dict(id=user.user_id,
71 return dict(
72 id=user.user_id,
72 username=user.username,
73 username=user.username,
73 firstname=user.name,
74 firstname=user.name,
74 lastname=user.lastname,
75 lastname=user.lastname,
75 email=user.email,
76 email=user.email,
76 active=user.active,
77 active=user.active,
77 admin=user.admin,
78 admin=user.admin,
78 ldap=user.ldap_dn)
79 ldap=user.ldap_dn
80 )
79
81
80 @HasPermissionAllDecorator('hg.admin')
82 @HasPermissionAllDecorator('hg.admin')
81 def get_users(self, apiuser):
83 def get_users(self, apiuser):
82 """"
84 """"
83 Get all users
85 Get all users
84
86
85 :param apiuser
87 :param apiuser:
86 """
88 """
87
89
88 result = []
90 result = []
89 for user in User.getAll():
91 for user in User.getAll():
90 result.append(dict(id=user.user_id,
92 result.append(
93 dict(
94 id=user.user_id,
91 username=user.username,
95 username=user.username,
92 firstname=user.name,
96 firstname=user.name,
93 lastname=user.lastname,
97 lastname=user.lastname,
94 email=user.email,
98 email=user.email,
95 active=user.active,
99 active=user.active,
96 admin=user.admin,
100 admin=user.admin,
97 ldap=user.ldap_dn))
101 ldap=user.ldap_dn
102 )
103 )
98 return result
104 return result
99
105
100 @HasPermissionAllDecorator('hg.admin')
106 @HasPermissionAllDecorator('hg.admin')
101 def create_user(self, apiuser, username, password, firstname,
107 def create_user(self, apiuser, username, password, firstname,
102 lastname, email, active=True, admin=False, ldap_dn=None):
108 lastname, email, active=True, admin=False, ldap_dn=None):
103 """
109 """
104 Create new user
110 Create new user
105
111
106 :param apiuser:
112 :param apiuser:
107 :param username:
113 :param username:
108 :param password:
114 :param password:
109 :param name:
115 :param name:
110 :param lastname:
116 :param lastname:
111 :param email:
117 :param email:
112 :param active:
118 :param active:
113 :param admin:
119 :param admin:
114 :param ldap_dn:
120 :param ldap_dn:
115 """
121 """
116
122
117 if User.get_by_username(username):
123 if User.get_by_username(username):
118 raise JSONRPCError("user %s already exist" % username)
124 raise JSONRPCError("user %s already exist" % username)
119
125
120 try:
126 try:
121 UserModel().create_or_update(username, password, email, firstname,
127 UserModel().create_or_update(username, password, email, firstname,
122 lastname, active, admin, ldap_dn)
128 lastname, active, admin, ldap_dn)
123 Session.commit()
129 Session.commit()
124 return dict(msg='created new user %s' % username)
130 return dict(msg='created new user %s' % username)
125 except Exception:
131 except Exception:
126 log.error(traceback.format_exc())
132 log.error(traceback.format_exc())
127 raise JSONRPCError('failed to create user %s' % username)
133 raise JSONRPCError('failed to create user %s' % username)
128
134
129 @HasPermissionAllDecorator('hg.admin')
135 @HasPermissionAllDecorator('hg.admin')
130 def get_users_group(self, apiuser, group_name):
136 def get_users_group(self, apiuser, group_name):
131 """"
137 """"
132 Get users group by name
138 Get users group by name
133
139
134 :param apiuser
140 :param apiuser:
135 :param group_name
141 :param group_name:
136 """
142 """
137
143
138 users_group = UsersGroup.get_by_group_name(group_name)
144 users_group = UsersGroup.get_by_group_name(group_name)
139 if not users_group:
145 if not users_group:
140 return None
146 return None
141
147
142 members = []
148 members = []
143 for user in users_group.members:
149 for user in users_group.members:
144 user = user.user
150 user = user.user
145 members.append(dict(id=user.user_id,
151 members.append(dict(id=user.user_id,
146 username=user.username,
152 username=user.username,
147 firstname=user.name,
153 firstname=user.name,
148 lastname=user.lastname,
154 lastname=user.lastname,
149 email=user.email,
155 email=user.email,
150 active=user.active,
156 active=user.active,
151 admin=user.admin,
157 admin=user.admin,
152 ldap=user.ldap_dn))
158 ldap=user.ldap_dn))
153
159
154 return dict(id=users_group.users_group_id,
160 return dict(id=users_group.users_group_id,
155 name=users_group.users_group_name,
161 name=users_group.users_group_name,
156 active=users_group.users_group_active,
162 active=users_group.users_group_active,
157 members=members)
163 members=members)
158
164
159 @HasPermissionAllDecorator('hg.admin')
165 @HasPermissionAllDecorator('hg.admin')
160 def get_users_groups(self, apiuser):
166 def get_users_groups(self, apiuser):
161 """"
167 """"
162 Get all users groups
168 Get all users groups
163
169
164 :param apiuser
170 :param apiuser:
165 """
171 """
166
172
167 result = []
173 result = []
168 for users_group in UsersGroup.getAll():
174 for users_group in UsersGroup.getAll():
169 members = []
175 members = []
170 for user in users_group.members:
176 for user in users_group.members:
171 user = user.user
177 user = user.user
172 members.append(dict(id=user.user_id,
178 members.append(dict(id=user.user_id,
173 username=user.username,
179 username=user.username,
174 firstname=user.name,
180 firstname=user.name,
175 lastname=user.lastname,
181 lastname=user.lastname,
176 email=user.email,
182 email=user.email,
177 active=user.active,
183 active=user.active,
178 admin=user.admin,
184 admin=user.admin,
179 ldap=user.ldap_dn))
185 ldap=user.ldap_dn))
180
186
181 result.append(dict(id=users_group.users_group_id,
187 result.append(dict(id=users_group.users_group_id,
182 name=users_group.users_group_name,
188 name=users_group.users_group_name,
183 active=users_group.users_group_active,
189 active=users_group.users_group_active,
184 members=members))
190 members=members))
185 return result
191 return result
186
192
187 @HasPermissionAllDecorator('hg.admin')
193 @HasPermissionAllDecorator('hg.admin')
188 def create_users_group(self, apiuser, name, active=True):
194 def create_users_group(self, apiuser, name, active=True):
189 """
195 """
190 Creates an new usergroup
196 Creates an new usergroup
191
197
192 :param name:
198 :param name:
193 :param active:
199 :param active:
194 """
200 """
195
201
196 if self.get_users_group(apiuser, name):
202 if self.get_users_group(apiuser, name):
197 raise JSONRPCError("users group %s already exist" % name)
203 raise JSONRPCError("users group %s already exist" % name)
198
204
199 try:
205 try:
200 ug = UsersGroupModel().create(name=name, active=active)
206 ug = UsersGroupModel().create(name=name, active=active)
201 Session.commit()
207 Session.commit()
202 return dict(id=ug.users_group_id,
208 return dict(id=ug.users_group_id,
203 msg='created new users group %s' % name)
209 msg='created new users group %s' % name)
204 except Exception:
210 except Exception:
205 log.error(traceback.format_exc())
211 log.error(traceback.format_exc())
206 raise JSONRPCError('failed to create group %s' % name)
212 raise JSONRPCError('failed to create group %s' % name)
207
213
208 @HasPermissionAllDecorator('hg.admin')
214 @HasPermissionAllDecorator('hg.admin')
209 def add_user_to_users_group(self, apiuser, group_name, user_name):
215 def add_user_to_users_group(self, apiuser, group_name, user_name):
210 """"
216 """"
211 Add a user to a group
217 Add a user to a group
212
218
213 :param apiuser
219 :param apiuser:
214 :param group_name
220 :param group_name:
215 :param user_name
221 :param user_name:
216 """
222 """
217
223
218 try:
224 try:
219 users_group = UsersGroup.get_by_group_name(group_name)
225 users_group = UsersGroup.get_by_group_name(group_name)
220 if not users_group:
226 if not users_group:
221 raise JSONRPCError('unknown users group %s' % group_name)
227 raise JSONRPCError('unknown users group %s' % group_name)
222
228
223 try:
229 try:
224 user = User.get_by_username(user_name)
230 user = User.get_by_username(user_name)
225 except NoResultFound:
231 except NoResultFound:
226 raise JSONRPCError('unknown user %s' % user_name)
232 raise JSONRPCError('unknown user %s' % user_name)
227
233
228 ugm = UsersGroupModel().add_user_to_group(users_group, user)
234 ugm = UsersGroupModel().add_user_to_group(users_group, user)
229 Session.commit()
235 Session.commit()
230 return dict(id=ugm.users_group_member_id,
236 return dict(id=ugm.users_group_member_id,
231 msg='created new users group member')
237 msg='created new users group member')
232 except Exception:
238 except Exception:
233 log.error(traceback.format_exc())
239 log.error(traceback.format_exc())
234 raise JSONRPCError('failed to create users group member')
240 raise JSONRPCError('failed to create users group member')
235
241
236 @HasPermissionAnyDecorator('hg.admin')
242 @HasPermissionAnyDecorator('hg.admin')
237 def get_repo(self, apiuser, repo_name):
243 def get_repo(self, apiuser, repo_name):
238 """"
244 """"
239 Get repository by name
245 Get repository by name
240
246
241 :param apiuser
247 :param apiuser:
242 :param repo_name
248 :param repo_name:
243 """
249 """
244
250
245 repo = Repository.get_by_repo_name(repo_name)
251 repo = Repository.get_by_repo_name(repo_name)
246 if repo is None:
252 if repo is None:
247 raise JSONRPCError('unknown repository %s' % repo)
253 raise JSONRPCError('unknown repository %s' % repo)
248
254
249 members = []
255 members = []
250 for user in repo.repo_to_perm:
256 for user in repo.repo_to_perm:
251 perm = user.permission.permission_name
257 perm = user.permission.permission_name
252 user = user.user
258 user = user.user
253 members.append(dict(type_="user",
259 members.append(
260 dict(
261 type_="user",
254 id=user.user_id,
262 id=user.user_id,
255 username=user.username,
263 username=user.username,
256 firstname=user.name,
264 firstname=user.name,
257 lastname=user.lastname,
265 lastname=user.lastname,
258 email=user.email,
266 email=user.email,
259 active=user.active,
267 active=user.active,
260 admin=user.admin,
268 admin=user.admin,
261 ldap=user.ldap_dn,
269 ldap=user.ldap_dn,
262 permission=perm))
270 permission=perm
271 )
272 )
263 for users_group in repo.users_group_to_perm:
273 for users_group in repo.users_group_to_perm:
264 perm = users_group.permission.permission_name
274 perm = users_group.permission.permission_name
265 users_group = users_group.users_group
275 users_group = users_group.users_group
266 members.append(dict(type_="users_group",
276 members.append(
277 dict(
278 type_="users_group",
267 id=users_group.users_group_id,
279 id=users_group.users_group_id,
268 name=users_group.users_group_name,
280 name=users_group.users_group_name,
269 active=users_group.users_group_active,
281 active=users_group.users_group_active,
270 permission=perm))
282 permission=perm
283 )
284 )
271
285
272 return dict(id=repo.repo_id,
286 return dict(
287 id=repo.repo_id,
273 name=repo.repo_name,
288 name=repo.repo_name,
274 type=repo.repo_type,
289 type=repo.repo_type,
275 description=repo.description,
290 description=repo.description,
276 members=members)
291 members=members
292 )
277
293
278 @HasPermissionAnyDecorator('hg.admin')
294 @HasPermissionAnyDecorator('hg.admin')
279 def get_repos(self, apiuser):
295 def get_repos(self, apiuser):
280 """"
296 """"
281 Get all repositories
297 Get all repositories
282
298
283 :param apiuser
299 :param apiuser:
284 """
300 """
285
301
286 result = []
302 result = []
287 for repository in Repository.getAll():
303 for repository in Repository.getAll():
288 result.append(dict(id=repository.repo_id,
304 result.append(
305 dict(
306 id=repository.repo_id,
289 name=repository.repo_name,
307 name=repository.repo_name,
290 type=repository.repo_type,
308 type=repository.repo_type,
291 description=repository.description))
309 description=repository.description
310 )
311 )
292 return result
312 return result
293
313
294 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
314 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
295 def create_repo(self, apiuser, name, owner_name, description='',
315 def create_repo(self, apiuser, name, owner_name, description='',
296 repo_type='hg', private=False):
316 repo_type='hg', private=False):
297 """
317 """
298 Create a repository
318 Create a repository
299
319
300 :param apiuser
320 :param apiuser:
301 :param name
321 :param name:
302 :param description
322 :param description:
303 :param type
323 :param type:
304 :param private
324 :param private:
305 :param owner_name
325 :param owner_name:
306 """
326 """
307
327
308 try:
328 try:
309 try:
329 try:
310 owner = User.get_by_username(owner_name)
330 owner = User.get_by_username(owner_name)
311 except NoResultFound:
331 except NoResultFound:
312 raise JSONRPCError('unknown user %s' % owner)
332 raise JSONRPCError('unknown user %s' % owner)
313
333
314 if self.get_repo(apiuser, name):
334 if self.get_repo(apiuser, name):
315 raise JSONRPCError("repo %s already exist" % name)
335 raise JSONRPCError("repo %s already exist" % name)
316
336
317 groups = name.split('/')
337 groups = name.split('/')
318 real_name = groups[-1]
338 real_name = groups[-1]
319 groups = groups[:-1]
339 groups = groups[:-1]
320 parent_id = None
340 parent_id = None
321 for g in groups:
341 for g in groups:
322 group = RepoGroup.get_by_group_name(g)
342 group = RepoGroup.get_by_group_name(g)
323 if not group:
343 if not group:
324 group = ReposGroupModel().create(dict(group_name=g,
344 group = ReposGroupModel().create(
345 dict(
346 group_name=g,
325 group_description='',
347 group_description='',
326 group_parent_id=parent_id))
348 group_parent_id=parent_id
349 )
350 )
327 parent_id = group.group_id
351 parent_id = group.group_id
328
352
329 RepoModel().create(dict(repo_name=real_name,
353 RepoModel().create(
354 dict(
355 repo_name=real_name,
330 repo_name_full=name,
356 repo_name_full=name,
331 description=description,
357 description=description,
332 private=private,
358 private=private,
333 repo_type=repo_type,
359 repo_type=repo_type,
334 repo_group=parent_id,
360 repo_group=parent_id,
335 clone_uri=None), owner)
361 clone_uri=None
362 ),
363 owner
364 )
336 Session.commit()
365 Session.commit()
337 except Exception:
366 except Exception:
338 log.error(traceback.format_exc())
367 log.error(traceback.format_exc())
339 raise JSONRPCError('failed to create repository %s' % name)
368 raise JSONRPCError('failed to create repository %s' % name)
340
369
341 @HasPermissionAnyDecorator('hg.admin')
370 @HasPermissionAnyDecorator('hg.admin')
342 def add_user_to_repo(self, apiuser, repo_name, user_name, perm):
371 def add_user_to_repo(self, apiuser, repo_name, user_name, perm):
343 """
372 """
344 Add permission for a user to a repository
373 Add permission for a user to a repository
345
374
346 :param apiuser
375 :param apiuser:
347 :param repo_name
376 :param repo_name:
348 :param user_name
377 :param user_name:
349 :param perm
378 :param perm:
350 """
379 """
351
380
352 try:
381 try:
353 repo = Repository.get_by_repo_name(repo_name)
382 repo = Repository.get_by_repo_name(repo_name)
354 if repo is None:
383 if repo is None:
355 raise JSONRPCError('unknown repository %s' % repo)
384 raise JSONRPCError('unknown repository %s' % repo)
356
385
357 try:
386 try:
358 user = User.get_by_username(user_name)
387 user = User.get_by_username(user_name)
359 except NoResultFound:
388 except NoResultFound:
360 raise JSONRPCError('unknown user %s' % user)
389 raise JSONRPCError('unknown user %s' % user)
361
390
362 RepositoryPermissionModel()\
391 RepositoryPermissionModel()\
363 .update_or_delete_user_permission(repo, user, perm)
392 .update_or_delete_user_permission(repo, user, perm)
364 Session.commit()
393 Session.commit()
394
395 return dict(
396 msg='Added perm: %s for %s in repo: %s' % (
397 perm, user_name, repo_name
398 )
399 )
365 except Exception:
400 except Exception:
366 log.error(traceback.format_exc())
401 log.error(traceback.format_exc())
367 raise JSONRPCError('failed to edit permission %(repo)s for %(user)s'
402 raise JSONRPCError(
368 % dict(user=user_name, repo=repo_name))
403 'failed to edit permission %(repo)s for %(user)s' % dict(
404 user=user_name, repo=repo_name
405 )
406 )
407
408 @HasPermissionAnyDecorator('hg.admin')
409 def add_users_group_to_repo(self, apiuser, repo_name, group_name, perm):
410 """
411 Add permission for a users group to a repository
412
413 :param apiuser:
414 :param repo_name:
415 :param group_name:
416 :param perm:
417 """
418
419 try:
420 repo = Repository.get_by_repo_name(repo_name)
421 if repo is None:
422 raise JSONRPCError('unknown repository %s' % repo)
369
423
424 try:
425 user_group = UsersGroup.get_by_group_name(group_name)
426 except NoResultFound:
427 raise JSONRPCError('unknown users group %s' % user_group)
428
429 RepositoryPermissionModel()\
430 .update_or_delete_users_group_permission(repo, user_group,
431 perm)
432 Session.commit()
433 return dict(
434 msg='Added perm: %s for %s in repo: %s' % (
435 perm, group_name, repo_name
436 )
437 )
438 except Exception:
439 log.error(traceback.format_exc())
440 raise JSONRPCError(
441 'failed to edit permission %(repo)s for %(usergr)s' % dict(
442 usergr=group_name, repo=repo_name
443 )
444 )
@@ -1,63 +1,106 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.users_group
3 rhodecode.model.users_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 repository permission model for RhodeCode
6 repository permission model for RhodeCode
7
7
8 :created_on: Oct 1, 2011
8 :created_on: Oct 1, 2011
9 :author: nvinot
9 :author: nvinot, marcink
10 :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
10 :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
12 """
13 """
13 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 # (at your option) any later version.
17 #
18 #
18 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 # GNU General Public License for more details.
22 #
23 #
23 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26
26 import logging
27 import logging
27 from rhodecode.model import BaseModel
28 from rhodecode.model import BaseModel
28 from rhodecode.model.db import UserRepoToPerm, Permission
29 from rhodecode.model.db import UserRepoToPerm, UsersGroupRepoToPerm, Permission
29
30
30 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
31
32
32
33
33 class RepositoryPermissionModel(BaseModel):
34 class RepositoryPermissionModel(BaseModel):
34
35
35 def get_user_permission(self, repository, user):
36 def get_user_permission(self, repository, user):
36 return UserRepoToPerm.query() \
37 return UserRepoToPerm.query() \
37 .filter(UserRepoToPerm.user == user) \
38 .filter(UserRepoToPerm.user == user) \
38 .filter(UserRepoToPerm.repository == repository) \
39 .filter(UserRepoToPerm.repository == repository) \
39 .scalar()
40 .scalar()
40
41
41 def update_user_permission(self, repository, user, permission):
42 def update_user_permission(self, repository, user, permission):
43
44 #TODO: REMOVE THIS !!
45 ################################
46 import ipdb;ipdb.set_trace()
47 print 'setting ipdb debuggin for rhodecode.model.repo_permission.RepositoryPermissionModel.update_user_permission'
48 ################################
49
50
51
42 permission = Permission.get_by_key(permission)
52 permission = Permission.get_by_key(permission)
43 current = self.get_user_permission(repository, user)
53 current = self.get_user_permission(repository, user)
44 if current:
54 if current:
45 if not current.permission is permission:
55 if not current.permission is permission:
46 current.permission = permission
56 current.permission = permission
47 else:
57 else:
48 p = UserRepoToPerm()
58 p = UserRepoToPerm()
49 p.user = user
59 p.user = user
50 p.repository = repository
60 p.repository = repository
51 p.permission = permission
61 p.permission = permission
52 self.sa.add(p)
62 self.sa.add(p)
53
63
54 def delete_user_permission(self, repository, user):
64 def delete_user_permission(self, repository, user):
55 current = self.get_user_permission(repository, user)
65 current = self.get_user_permission(repository, user)
56 if current:
66 if current:
57 self.sa.delete(current)
67 self.sa.delete(current)
58
68
69 def get_users_group_permission(self, repository, users_group):
70 return UsersGroupRepoToPerm.query() \
71 .filter(UsersGroupRepoToPerm.users_group == users_group) \
72 .filter(UsersGroupRepoToPerm.repository == repository) \
73 .scalar()
74
75 def update_users_group_permission(self, repository, users_group,
76 permission):
77 permission = Permission.get_by_key(permission)
78 current = self.get_users_group_permission(repository, users_group)
79 if current:
80 if not current.permission is permission:
81 current.permission = permission
82 else:
83 p = UsersGroupRepoToPerm()
84 p.users_group = users_group
85 p.repository = repository
86 p.permission = permission
87 self.sa.add(p)
88
89 def delete_users_group_permission(self, repository, users_group):
90 current = self.get_users_group_permission(repository, users_group)
91 if current:
92 self.sa.delete(current)
93
59 def update_or_delete_user_permission(self, repository, user, permission):
94 def update_or_delete_user_permission(self, repository, user, permission):
60 if permission:
95 if permission:
61 self.update_user_permission(repository, user, permission)
96 self.update_user_permission(repository, user, permission)
62 else:
97 else:
63 self.delete_user_permission(repository, user)
98 self.delete_user_permission(repository, user)
99
100 def update_or_delete_users_group_permission(self, repository, user_group,
101 permission):
102 if permission:
103 self.update_users_group_permission(repository, user_group,
104 permission)
105 else:
106 self.delete_users_group_permission(repository, user_group) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now