Show More
@@ -6,12 +6,12 b' API' | |||||
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 |
|
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 |
|
11 | <your_server>/_admin/api | |
12 |
|
12 | |||
13 |
|
13 | |||
14 |
|
|
14 | All clients need to send JSON data in such format:: | |
15 |
|
15 | |||
16 | { |
|
16 | { | |
17 | "api_key":"<api_key>", |
|
17 | "api_key":"<api_key>", | |
@@ -19,16 +19,20 b' Clients need to send JSON data in such f' | |||||
19 | "args":{"<arg_key>":"<arg_val>"} |
|
19 | "args":{"<arg_key>":"<arg_val>"} | |
20 | } |
|
20 | } | |
21 |
|
21 | |||
22 | Simply provide api_key for access and permission validation |
|
22 | Example call for autopulling remotes repos using curl:: | |
23 | method is name of method to call |
|
23 | curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}' | |
24 | and args is an key:value list of arguments to pass to method |
|
24 | ||
|
25 | Simply provide | |||
|
26 | - *api_key* for access and permission validation. | |||
|
27 | - *method* is name of method to call | |||
|
28 | - *args* is an key:value list of arguments to pass to method | |||
25 |
|
29 | |||
26 | .. note:: |
|
30 | .. note:: | |
27 |
|
31 | |||
28 | api_key can be found in your user account page |
|
32 | api_key can be found in your user account page | |
29 |
|
33 | |||
30 |
|
34 | |||
31 |
|
|
35 | RhodeCode API will return always a JSON formatted answer:: | |
32 |
|
36 | |||
33 | { |
|
37 | { | |
34 | "result": "<result>", |
|
38 | "result": "<result>", | |
@@ -36,7 +40,7 b' And will receive JSON formatted answer::' | |||||
36 | } |
|
40 | } | |
37 |
|
41 | |||
38 | All responses from API will be `HTTP/1.0 200 OK`, if there's an error while |
|
42 | All responses from API will be `HTTP/1.0 200 OK`, if there's an error while | |
39 |
calling api |
|
43 | calling api *error* key from response will contain failure description | |
40 | and result will be null. |
|
44 | and result will be null. | |
41 |
|
45 | |||
42 | API METHODS |
|
46 | API METHODS | |
@@ -47,11 +51,61 b' pull' | |||||
47 | ---- |
|
51 | ---- | |
48 |
|
52 | |||
49 | Pulls given repo from remote location. Can be used to automatically keep |
|
53 | Pulls given repo from remote location. Can be used to automatically keep | |
50 |
remote repos upto date. This command can be executed only using a |
|
54 | remote repos up to date. This command can be executed only using api_key | |
51 | api_key |
|
55 | belonging to user with admin rights | |
52 |
|
56 | |||
53 | :: |
|
57 | INPUT:: | |
|
58 | ||||
54 | api_key:"<api_key>" |
|
59 | api_key:"<api_key>" | |
55 | method: "pull" |
|
60 | method: "pull" | |
56 | args: {"repo":<repo_name>} |
|
61 | args: {"repo":<repo_name>} | |
57 |
|
|
62 | ||
|
63 | OUTPUT:: | |||
|
64 | ||||
|
65 | result:"Pulled from <repo_name>" | |||
|
66 | error:null | |||
|
67 | ||||
|
68 | ||||
|
69 | create_user | |||
|
70 | ----------- | |||
|
71 | ||||
|
72 | Creates new user in RhodeCode. This command can be executed only using api_key | |||
|
73 | belonging to user with admin rights | |||
|
74 | ||||
|
75 | INPUT:: | |||
|
76 | ||||
|
77 | api_key:"<api_key>" | |||
|
78 | method: "create_user" | |||
|
79 | args: {"username": "<username>", | |||
|
80 | "password": "<password>", | |||
|
81 | "active": "<bool>", | |||
|
82 | "admin": "<bool>", | |||
|
83 | "name": "<firstname>", | |||
|
84 | "lastname": "<lastname>", | |||
|
85 | "email": "<useremail>"} | |||
|
86 | ||||
|
87 | OUTPUT:: | |||
|
88 | ||||
|
89 | result:{"id": <newuserid>, | |||
|
90 | "msg":"created new user <username>"} | |||
|
91 | error:null | |||
|
92 | ||||
|
93 | ||||
|
94 | create_users_group | |||
|
95 | ------------------ | |||
|
96 | ||||
|
97 | creates new users group. This command can be executed only using api_key | |||
|
98 | belonging to user with admin rights | |||
|
99 | ||||
|
100 | INPUT:: | |||
|
101 | ||||
|
102 | api_key:"<api_key>" | |||
|
103 | method: "create_user" | |||
|
104 | args: {"name": "<groupname>", | |||
|
105 | "active":"<bool>"} | |||
|
106 | ||||
|
107 | OUTPUT:: | |||
|
108 | ||||
|
109 | result:{"id": <newusersgroupid>, | |||
|
110 | "msg":"created new users group <groupname>"} | |||
|
111 | error:null |
@@ -136,25 +136,29 b' class JSONRPCController(WSGIController):' | |||||
136 |
|
136 | |||
137 | # this is little trick to inject logged in user for |
|
137 | # this is little trick to inject logged in user for | |
138 | # perms decorators to work they expect the controller class to have |
|
138 | # perms decorators to work they expect the controller class to have | |
139 | # rhodecode_user set |
|
139 | # rhodecode_user attribute set | |
140 | self.rhodecode_user = auth_u |
|
140 | self.rhodecode_user = auth_u | |
141 |
|
141 | |||
142 | if 'user' not in arglist: |
|
142 | # This attribute will need to be first param of a method that uses | |
|
143 | # api_key, which is translated to instance of user at that name | |||
|
144 | USER_SESSION_ATTR = 'apiuser' | |||
|
145 | ||||
|
146 | if USER_SESSION_ATTR not in arglist: | |||
143 | return jsonrpc_error(message='This method [%s] does not support ' |
|
147 | return jsonrpc_error(message='This method [%s] does not support ' | |
144 |
'authentication (missing |
|
148 | 'authentication (missing %s param)' % | |
145 | self._func.__name__) |
|
149 | (self._func.__name__, USER_SESSION_ATTR)) | |
146 |
|
150 | |||
147 | # get our arglist and check if we provided them as args |
|
151 | # get our arglist and check if we provided them as args | |
148 | for arg in arglist: |
|
152 | for arg in arglist: | |
149 |
if arg == |
|
153 | if arg == USER_SESSION_ATTR: | |
150 |
# |
|
154 | # USER_SESSION_ATTR is something translated from api key and | |
151 | # checked before |
|
155 | # this is checked before so we don't need validate it | |
152 | continue |
|
156 | continue | |
153 |
|
157 | |||
154 | if not self._req_params or arg not in self._req_params: |
|
158 | if not self._req_params or arg not in self._req_params: | |
155 | return jsonrpc_error(message='Missing %s arg in JSON DATA' % arg) |
|
159 | return jsonrpc_error(message='Missing %s arg in JSON DATA' % arg) | |
156 |
|
160 | |||
157 |
self._rpc_args = |
|
161 | self._rpc_args = {USER_SESSION_ATTR:u} | |
158 | self._rpc_args.update(self._req_params) |
|
162 | self._rpc_args.update(self._req_params) | |
159 |
|
163 | |||
160 | self._rpc_args['action'] = self._req_method |
|
164 | self._rpc_args['action'] = self._req_method | |
@@ -183,7 +187,6 b' class JSONRPCController(WSGIController):' | |||||
183 | """ |
|
187 | """ | |
184 | try: |
|
188 | try: | |
185 | raw_response = self._inspect_call(self._func) |
|
189 | raw_response = self._inspect_call(self._func) | |
186 | print raw_response |
|
|||
187 | if isinstance(raw_response, HTTPError): |
|
190 | if isinstance(raw_response, HTTPError): | |
188 | self._error = str(raw_response) |
|
191 | self._error = str(raw_response) | |
189 | except JSONRPCError as e: |
|
192 | except JSONRPCError as e: | |
@@ -223,3 +226,4 b' class JSONRPCController(WSGIController):' | |||||
223 | return func |
|
226 | return func | |
224 | else: |
|
227 | else: | |
225 | raise AttributeError("No such method: %s" % self._req_method) |
|
228 | raise AttributeError("No such method: %s" % self._req_method) | |
|
229 |
@@ -1,7 +1,14 b'' | |||||
|
1 | import traceback | |||
|
2 | import logging | |||
|
3 | ||||
1 | from rhodecode.controllers.api import JSONRPCController, JSONRPCError |
|
4 | from rhodecode.controllers.api import JSONRPCController, JSONRPCError | |
2 | from rhodecode.lib.auth import HasPermissionAllDecorator |
|
5 | from rhodecode.lib.auth import HasPermissionAllDecorator | |
3 | from rhodecode.model.scm import ScmModel |
|
6 | from rhodecode.model.scm import ScmModel | |
4 |
|
7 | |||
|
8 | from rhodecode.model.db import User, UsersGroup | |||
|
9 | ||||
|
10 | log = logging.getLogger(__name__) | |||
|
11 | ||||
5 |
|
12 | |||
6 | class ApiController(JSONRPCController): |
|
13 | class ApiController(JSONRPCController): | |
7 | """ |
|
14 | """ | |
@@ -20,13 +27,13 b' class ApiController(JSONRPCController):' | |||||
20 | """ |
|
27 | """ | |
21 |
|
28 | |||
22 | @HasPermissionAllDecorator('hg.admin') |
|
29 | @HasPermissionAllDecorator('hg.admin') | |
23 | def pull(self, user, repo): |
|
30 | def pull(self, apiuser, repo): | |
24 | """ |
|
31 | """ | |
25 | Dispatch pull action on given repo |
|
32 | Dispatch pull action on given repo | |
26 |
|
33 | |||
27 |
|
34 | |||
28 | param user: |
|
35 | :param user: | |
29 | param repo: |
|
36 | :param repo: | |
30 | """ |
|
37 | """ | |
31 |
|
38 | |||
32 | try: |
|
39 | try: | |
@@ -36,5 +43,52 b' class ApiController(JSONRPCController):' | |||||
36 | raise JSONRPCError('Unable to pull changes from "%s"' % repo) |
|
43 | raise JSONRPCError('Unable to pull changes from "%s"' % repo) | |
37 |
|
44 | |||
38 |
|
45 | |||
|
46 | @HasPermissionAllDecorator('hg.admin') | |||
|
47 | def create_user(self, apiuser, username, password, active, admin, name, | |||
|
48 | lastname, email): | |||
|
49 | """ | |||
|
50 | Creates new user | |||
|
51 | ||||
|
52 | :param apiuser: | |||
|
53 | :param username: | |||
|
54 | :param password: | |||
|
55 | :param active: | |||
|
56 | :param admin: | |||
|
57 | :param name: | |||
|
58 | :param lastname: | |||
|
59 | :param email: | |||
|
60 | """ | |||
|
61 | ||||
|
62 | form_data = dict(username=username, | |||
|
63 | password=password, | |||
|
64 | active=active, | |||
|
65 | admin=admin, | |||
|
66 | name=name, | |||
|
67 | lastname=lastname, | |||
|
68 | email=email) | |||
|
69 | try: | |||
|
70 | u = User.create(form_data) | |||
|
71 | return {'id':u.user_id, | |||
|
72 | 'msg':'created new user %s' % name} | |||
|
73 | except Exception: | |||
|
74 | log.error(traceback.format_exc()) | |||
|
75 | raise JSONRPCError('failed to create user %s' % name) | |||
39 |
|
76 | |||
40 |
|
77 | |||
|
78 | @HasPermissionAllDecorator('hg.admin') | |||
|
79 | def create_users_group(self, apiuser, name, active): | |||
|
80 | """ | |||
|
81 | Creates an new usergroup | |||
|
82 | ||||
|
83 | :param name: | |||
|
84 | :param active: | |||
|
85 | """ | |||
|
86 | form_data = {'users_group_name':name, | |||
|
87 | 'users_group_active':active} | |||
|
88 | try: | |||
|
89 | ug = UsersGroup.create(form_data) | |||
|
90 | return {'id':ug.users_group_id, | |||
|
91 | 'msg':'created new users group %s' % name} | |||
|
92 | except Exception: | |||
|
93 | log.error(traceback.format_exc()) | |||
|
94 | raise JSONRPCError('failed to create group %s' % name) |
@@ -38,12 +38,13 b' from beaker.cache import cache_region, r' | |||||
38 |
|
38 | |||
39 | from vcs import get_backend |
|
39 | from vcs import get_backend | |
40 | from vcs.utils.helpers import get_scm |
|
40 | from vcs.utils.helpers import get_scm | |
41 |
from vcs.exceptions import |
|
41 | from vcs.exceptions import VCSError | |
42 | from vcs.utils.lazy import LazyProperty |
|
42 | from vcs.utils.lazy import LazyProperty | |
43 | from vcs.nodes import FileNode |
|
|||
44 |
|
43 | |||
45 | from rhodecode.lib.exceptions import UsersGroupsAssignedException |
|
44 | from rhodecode.lib.exceptions import UsersGroupsAssignedException | |
46 | from rhodecode.lib import str2bool, json, safe_str, get_changeset_safe |
|
45 | from rhodecode.lib import str2bool, json, safe_str, get_changeset_safe,\ | |
|
46 | generate_api_key | |||
|
47 | ||||
47 | from rhodecode.model.meta import Base, Session |
|
48 | from rhodecode.model.meta import Base, Session | |
48 | from rhodecode.model.caching_query import FromCache |
|
49 | from rhodecode.model.caching_query import FromCache | |
49 |
|
50 | |||
@@ -298,6 +299,25 b' class User(Base, BaseModel):' | |||||
298 | Session.commit() |
|
299 | Session.commit() | |
299 | log.debug('updated user %s lastlogin', self.username) |
|
300 | log.debug('updated user %s lastlogin', self.username) | |
300 |
|
301 | |||
|
302 | @classmethod | |||
|
303 | def create(cls, form_data): | |||
|
304 | from rhodecode.lib.auth import get_crypt_password | |||
|
305 | ||||
|
306 | try: | |||
|
307 | new_user = cls() | |||
|
308 | for k, v in form_data.items(): | |||
|
309 | if k == 'password': | |||
|
310 | v = get_crypt_password(v) | |||
|
311 | setattr(new_user, k, v) | |||
|
312 | ||||
|
313 | new_user.api_key = generate_api_key(form_data['username']) | |||
|
314 | Session.add(new_user) | |||
|
315 | Session.commit() | |||
|
316 | return new_user | |||
|
317 | except: | |||
|
318 | log.error(traceback.format_exc()) | |||
|
319 | Session.rollback() | |||
|
320 | raise | |||
301 |
|
321 | |||
302 | class UserLog(Base, BaseModel): |
|
322 | class UserLog(Base, BaseModel): | |
303 | __tablename__ = 'user_logs' |
|
323 | __tablename__ = 'user_logs' | |
@@ -362,6 +382,7 b' class UsersGroup(Base, BaseModel):' | |||||
362 |
|
382 | |||
363 | Session.add(new_users_group) |
|
383 | Session.add(new_users_group) | |
364 | Session.commit() |
|
384 | Session.commit() | |
|
385 | return new_users_group | |||
365 | except: |
|
386 | except: | |
366 | log.error(traceback.format_exc()) |
|
387 | log.error(traceback.format_exc()) | |
367 | Session.rollback() |
|
388 | Session.rollback() |
General Comments 0
You need to be logged in to leave comments.
Login now