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