##// END OF EJS Templates
merged upto rev 019026a8cf67
marcink -
r1639:95c3e33e merge default
parent child Browse files
Show More
@@ -0,0 +1,63 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.model.users_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 repository permission model for RhodeCode
7
8 :created_on: Oct 1, 2011
9 :author: nvinot
10 :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # 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 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # 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
26 import logging
27 from rhodecode.model.db import BaseModel, RepoToPerm, Permission
28 from rhodecode.model.meta import Session
29
30 log = logging.getLogger(__name__)
31
32 class RepositoryPermissionModel(BaseModel):
33 def get_user_permission(self, repository, user):
34 return RepoToPerm.query() \
35 .filter(RepoToPerm.user == user) \
36 .filter(RepoToPerm.repository == repository) \
37 .scalar()
38
39 def update_user_permission(self, repository, user, permission):
40 permission = Permission.get_by_key(permission)
41 current = self.get_user_permission(repository, user)
42 if current:
43 if not current.permission is permission:
44 current.permission = permission
45 else:
46 p = RepoToPerm()
47 p.user = user
48 p.repository = repository
49 p.permission = permission
50 Session.add(p)
51 Session.commit()
52
53 def delete_user_permission(self, repository, user):
54 current = self.get_user_permission(repository, user)
55 if current:
56 Session.delete(current)
57 Session.commit()
58
59 def update_or_delete_user_permission(self, repository, user, permission):
60 if permission:
61 self.update_user_permission(repository, user, permission)
62 else:
63 self.delete_user_permission(repository, user)
@@ -0,0 +1,89 b''
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.model.users_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 users group model for RhodeCode
7
8 :created_on: Oct 1, 2011
9 :author: nvinot
10 :copyright: (C) 2011-2011 Nicolas Vinot <aeris@imirhil.fr>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # 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 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # 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
26 import logging
27 import traceback
28
29 from rhodecode.model import BaseModel
30 from rhodecode.model.caching_query import FromCache
31 from rhodecode.model.db import UsersGroupMember, UsersGroup
32
33 log = logging.getLogger(__name__)
34
35 class UsersGroupModel(BaseModel):
36
37 def get(self, users_group_id, cache = False):
38 users_group = UsersGroup.query()
39 if cache:
40 users_group = users_group.options(FromCache("sql_cache_short",
41 "get_users_group_%s" % users_group_id))
42 return users_group.get(users_group_id)
43
44 def get_by_name(self, name, cache = False, case_insensitive = False):
45 users_group = UsersGroup.query()
46 if case_insensitive:
47 users_group = users_group.filter(UsersGroup.users_group_name.ilike(name))
48 else:
49 users_group = users_group.filter(UsersGroup.users_group_name == name)
50 if cache:
51 users_group = users_group.options(FromCache("sql_cache_short",
52 "get_users_group_%s" % name))
53 return users_group.scalar()
54
55 def create(self, form_data):
56 try:
57 new_users_group = UsersGroup()
58 for k, v in form_data.items():
59 setattr(new_users_group, k, v)
60
61 self.sa.add(new_users_group)
62 self.sa.commit()
63 return new_users_group
64 except:
65 log.error(traceback.format_exc())
66 self.sa.rollback()
67 raise
68
69 def add_user_to_group(self, users_group, user):
70 for m in users_group.members:
71 u = m.user
72 if u.user_id == user.user_id:
73 return m
74
75 try:
76 users_group_member = UsersGroupMember()
77 users_group_member.user = user
78 users_group_member.users_group = users_group
79
80 users_group.members.append(users_group_member)
81 user.group_member.append(users_group_member)
82
83 self.sa.add(users_group_member)
84 self.sa.commit()
85 return users_group_member
86 except:
87 log.error(traceback.format_exc())
88 self.sa.rollback()
89 raise
@@ -24,6 +24,8 b' pdebug = false'
24 #smtp_port =
24 #smtp_port =
25 #smtp_use_tls = false
25 #smtp_use_tls = false
26 #smtp_use_ssl = true
26 #smtp_use_ssl = true
27 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
28 #smtp_auth =
27
29
28 [server:main]
30 [server:main]
29 ##nr of threads to spawn
31 ##nr of threads to spawn
@@ -7,7 +7,7 b' API'
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
@@ -22,90 +22,341 b' All clients need to send JSON data in su'
22 Example call for autopulling remotes repos using curl::
22 Example call for autopulling remotes repos using curl::
23 curl https://server.com/_admin/api -X POST -H 'content-type:text/plain' --data-binary '{"api_key":"xe7cdb2v278e4evbdf5vs04v832v0efvcbcve4a3","method":"pull","args":{"repo":"CPython"}}'
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
24
25 Simply provide
25 Simply provide
26 - *api_key* for access and permission validation.
26 - *api_key* for access and permission validation.
27 - *method* is name of method to call
27 - *method* is name of method to call
28 - *args* is an key:value list of arguments to pass to method
28 - *args* is an key:value list of arguments to pass to method
29
29
30 .. note::
30 .. note::
31
31
32 api_key can be found in your user account page
32 api_key can be found in your user account page
33
33
34
34
35 RhodeCode API will return always a JSON formatted answer::
35 RhodeCode API will return always a JSON formatted answer::
36
36
37 {
37 {
38 "result": "<result>",
38 "result": "<result>",
39 "error": null
39 "error": null
40 }
40 }
41
41
42 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
43 calling api *error* key from response will contain failure description
43 calling api *error* key from response will contain failure description
44 and result will be null.
44 and result will be null.
45
45
46 API METHODS
46 API METHODS
47 +++++++++++
47 +++++++++++
48
48
49
49
50 pull
50 pull
51 ----
51 ----
52
52
53 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
54 remote repos up to date. This command can be executed only using api_key
54 remote repos up to date. This command can be executed only using api_key
55 belonging to user with admin rights
56
57 INPUT::
58
59 api_key:"<api_key>"
60 method: "pull"
61 args: {"repo":<repo_name>}
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
55 belonging to user with admin rights
74
56
75 INPUT::
57 INPUT::
76
58
77 api_key:"<api_key>"
59 api_key : "<api_key>"
78 method: "create_user"
60 method : "pull"
79 args: {"username": "<username>",
61 args : {
80 "password": "<password>",
62 "repo" : "<repo_name>"
81 "active": "<bool>",
63 }
82 "admin": "<bool>",
64
83 "name": "<firstname>",
65 OUTPUT::
84 "lastname": "<lastname>",
66
85 "email": "<useremail>"}
67 result : "Pulled from <repo_name>"
68 error : null
69
70
71 get_users
72 ---------
73
74 Lists all existing users. This command can be executed only using api_key
75 belonging to user with admin rights.
76
77 INPUT::
78
79 api_key : "<api_key>"
80 method : "get_users"
81 args : { }
82
83 OUTPUT::
84
85 result: [
86 {
87 "id" : "<id>",
88 "username" : "<username>",
89 "firstname": "<firstname>",
90 "lastname" : "<lastname>",
91 "email" : "<email>",
92 "active" : "<bool>",
93 "admin" :  "<bool>",
94 "ldap" : "<ldap_dn>"
95 },
96 …
97 ]
98 error: null
99
100 create_user
101 -----------
102
103 Creates new user in RhodeCode. This command can be executed only using api_key
104 belonging to user with admin rights.
105
106 INPUT::
107
108 api_key : "<api_key>"
109 method : "create_user"
110 args : {
111 "username" : "<username>",
112 "password" : "<password>",
113 "firstname" : "<firstname>",
114 "lastname" : "<lastname>",
115 "email" : "<useremail>"
116 "active" : "<bool> = True",
117 "admin" : "<bool> = False",
118 "ldap_dn" : "<ldap_dn> = None"
119 }
86
120
87 OUTPUT::
121 OUTPUT::
88
122
89 result:{"id": <newuserid>,
123 result: {
90 "msg":"created new user <username>"}
124 "msg" : "created new user <username>"
91 error:null
125 }
92
126 error: null
93
127
128 get_users_groups
129 ----------------
130
131 Lists all existing users groups. This command can be executed only using api_key
132 belonging to user with admin rights.
133
134 INPUT::
135
136 api_key : "<api_key>"
137 method : "get_users_groups"
138 args : { }
139
140 OUTPUT::
141
142 result : [
143 {
144 "id" : "<id>",
145 "name" : "<name>",
146 "active": "<bool>",
147 "members" : [
148 {
149 "id" : "<userid>",
150 "username" : "<username>",
151 "firstname": "<firstname>",
152 "lastname" : "<lastname>",
153 "email" : "<email>",
154 "active" : "<bool>",
155 "admin" :  "<bool>",
156 "ldap" : "<ldap_dn>"
157 },
158 …
159 ]
160 }
161 ]
162 error : null
163
164 get_users_group
165 ---------------
166
167 Gets an existing users group. This command can be executed only using api_key
168 belonging to user with admin rights.
169
170 INPUT::
171
172 api_key : "<api_key>"
173 method : "get_users_group"
174 args : {
175 "group_name" : "<name>"
176 }
177
178 OUTPUT::
179
180 result : None if group not exist
181 {
182 "id" : "<id>",
183 "name" : "<name>",
184 "active": "<bool>",
185 "members" : [
186 { "id" : "<userid>",
187 "username" : "<username>",
188 "firstname": "<firstname>",
189 "lastname" : "<lastname>",
190 "email" : "<email>",
191 "active" : "<bool>",
192 "admin" :  "<bool>",
193 "ldap" : "<ldap_dn>"
194 },
195 …
196 ]
197 }
198 error : null
199
94 create_users_group
200 create_users_group
95 ------------------
201 ------------------
96
202
97 creates new users group. This command can be executed only using api_key
203 Creates new users group. This command can be executed only using api_key
98 belonging to user with admin rights
204 belonging to user with admin rights
99
205
100 INPUT::
206 INPUT::
101
207
102 api_key:"<api_key>"
208 api_key : "<api_key>"
103 method: "create_user"
209 method : "create_users_group"
104 args: {"name": "<groupname>",
210 args: {
105 "active":"<bool>"}
211 "name": "<name>",
212 "active":"<bool> = True"
213 }
214
215 OUTPUT::
216
217 result: {
218 "id": "<newusersgroupid>",
219 "msg": "created new users group <name>"
220 }
221 error: null
222
223 add_user_to_users_groups
224 ------------------------
225
226 Adds a user to a users group. This command can be executed only using api_key
227 belonging to user with admin rights
228
229 INPUT::
230
231 api_key : "<api_key>"
232 method : "add_user_users_group"
233 args: {
234 "group_name" : "<groupname>",
235 "user_name" : "<username>"
236 }
237
238 OUTPUT::
239
240 result: {
241 "id": "<newusersgroupmemberid>",
242 "msg": "created new users group member"
243 }
244 error: null
245
246 get_repos
247 ---------
248
249 Lists all existing repositories. This command can be executed only using api_key
250 belonging to user with admin rights
251
252 INPUT::
253
254 api_key : "<api_key>"
255 method : "get_repos"
256 args: { }
106
257
107 OUTPUT::
258 OUTPUT::
108
259
109 result:{"id": <newusersgroupid>,
260 result: [
110 "msg":"created new users group <groupname>"}
261 {
111 error:null
262 "id" : "<id>",
263 "name" : "<name>"
264 "type" : "<type>",
265 "description" : "<description>"
266 },
267 …
268 ]
269 error: null
270
271 get_repo
272 --------
273
274 Gets an existing repository. This command can be executed only using api_key
275 belonging to user with admin rights
276
277 INPUT::
278
279 api_key : "<api_key>"
280 method : "get_repo"
281 args: {
282 "name" : "<name>"
283 }
284
285 OUTPUT::
286
287 result: None if repository not exist
288 {
289 "id" : "<id>",
290 "name" : "<name>"
291 "type" : "<type>",
292 "description" : "<description>",
293 "members" : [
294 { "id" : "<userid>",
295 "username" : "<username>",
296 "firstname": "<firstname>",
297 "lastname" : "<lastname>",
298 "email" : "<email>",
299 "active" : "<bool>",
300 "admin" :  "<bool>",
301 "ldap" : "<ldap_dn>",
302 "permission" : "repository_(read|write|admin)"
303 },
304 …
305 {
306 "id" : "<usersgroupid>",
307 "name" : "<usersgroupname>",
308 "active": "<bool>",
309 "permission" : "repository_(read|write|admin)"
310 },
311 …
312 ]
313 }
314 error: null
315
316 create_repo
317 -----------
318
319 Creates a repository. This command can be executed only using api_key
320 belonging to user with admin rights.
321 If repository name contains "/", all needed repository groups will be created.
322 For example "foo/bar/baz" will create groups "foo", "bar" (with "foo" as parent),
323 and create "baz" repository with "bar" as group.
324
325 INPUT::
326
327 api_key : "<api_key>"
328 method : "create_repo"
329 args: {
330 "name" : "<name>",
331 "owner_name" : "<ownername>",
332 "description" : "<description> = ''",
333 "repo_type" : "<type> = 'hg'",
334 "private" : "<bool> = False"
335 }
336
337 OUTPUT::
338
339 result: None
340 error: null
341
342 add_user_to_repo
343 ----------------
344
345 Add a user to a repository. This command can be executed only using api_key
346 belonging to user with admin rights.
347 If "perm" is None, user will be removed from the repository.
348
349 INPUT::
350
351 api_key : "<api_key>"
352 method : "add_user_to_repo"
353 args: {
354 "repo_name" : "<reponame>",
355 "user_name" : "<username>",
356 "perm" : "(None|repository_(read|write|admin))",
357 }
358
359 OUTPUT::
360
361 result: None
362 error: null
@@ -24,6 +24,8 b' pdebug = false'
24 #smtp_port =
24 #smtp_port =
25 #smtp_use_tls = false
25 #smtp_use_tls = false
26 #smtp_use_ssl = true
26 #smtp_use_ssl = true
27 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
28 #smtp_auth =
27
29
28 [server:main]
30 [server:main]
29 ##nr of threads to spawn
31 ##nr of threads to spawn
@@ -24,6 +24,8 b' pdebug = false'
24 #smtp_port =
24 #smtp_port =
25 #smtp_use_tls = false
25 #smtp_use_tls = false
26 #smtp_use_ssl = true
26 #smtp_use_ssl = true
27 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
28 #smtp_auth =
27
29
28 [server:main]
30 [server:main]
29 ##nr of threads to spawn
31 ##nr of threads to spawn
@@ -146,7 +148,7 b' logview.pylons.util = #eee'
146 # SQLITE [default]
148 # SQLITE [default]
147 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
149 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
148
150
149 # POSTGRES
151 # POSTGRESQL
150 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
152 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
151
153
152 # MySQL
154 # MySQL
@@ -26,7 +26,6 b''
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29 from operator import itemgetter
30 from formencode import htmlfill
29 from formencode import htmlfill
31
30
32 from paste.httpexceptions import HTTPInternalServerError
31 from paste.httpexceptions import HTTPInternalServerError
@@ -92,7 +91,7 b' class ReposController(BaseController):'
92 return redirect(url('repos'))
91 return redirect(url('repos'))
93
92
94 c.default_user_id = User.get_by_username('default').user_id
93 c.default_user_id = User.get_by_username('default').user_id
95 c.in_public_journal = self.sa.query(UserFollowing)\
94 c.in_public_journal = UserFollowing.query()\
96 .filter(UserFollowing.user_id == c.default_user_id)\
95 .filter(UserFollowing.user_id == c.default_user_id)\
97 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
96 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
98
97
@@ -110,30 +109,7 b' class ReposController(BaseController):'
110 c.stats_percentage = '%.2f' % ((float((last_rev)) /
109 c.stats_percentage = '%.2f' % ((float((last_rev)) /
111 c.repo_last_rev) * 100)
110 c.repo_last_rev) * 100)
112
111
113 defaults = c.repo_info.get_dict()
112 defaults = RepoModel()._get_defaults(repo_name)
114 group, repo_name = c.repo_info.groups_and_repo
115 defaults['repo_name'] = repo_name
116 defaults['repo_group'] = getattr(group[-1] if group else None,
117 'group_id', None)
118
119 #fill owner
120 if c.repo_info.user:
121 defaults.update({'user': c.repo_info.user.username})
122 else:
123 replacement_user = self.sa.query(User)\
124 .filter(User.admin == True).first().username
125 defaults.update({'user': replacement_user})
126
127 #fill repository users
128 for p in c.repo_info.repo_to_perm:
129 defaults.update({'u_perm_%s' % p.user.username:
130 p.permission.permission_name})
131
132 #fill repository groups
133 for p in c.repo_info.users_group_to_perm:
134 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
135 p.permission.permission_name})
136
137 return defaults
113 return defaults
138
114
139 @HasPermissionAllDecorator('hg.admin')
115 @HasPermissionAllDecorator('hg.admin')
@@ -2,10 +2,18 b' import traceback'
2 import logging
2 import logging
3
3
4 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
4 from rhodecode.controllers.api import JSONRPCController, JSONRPCError
5 from rhodecode.lib.auth import HasPermissionAllDecorator
5 from rhodecode.lib.auth import HasPermissionAllDecorator, \
6 HasPermissionAnyDecorator
6 from rhodecode.model.scm import ScmModel
7 from rhodecode.model.scm import ScmModel
7
8
8 from rhodecode.model.db import User, UsersGroup, Repository
9 from rhodecode.model.db import User, UsersGroup, Group, Repository
10 from rhodecode.model.repo import RepoModel
11 from rhodecode.model.user import UserModel
12 from rhodecode.model.repo_permission import RepositoryPermissionModel
13 from rhodecode.model.users_group import UsersGroupModel
14 from rhodecode.model import users_group
15 from rhodecode.model.repos_group import ReposGroupModel
16 from sqlalchemy.orm.exc import NoResultFound
9
17
10 log = logging.getLogger(__name__)
18 log = logging.getLogger(__name__)
11
19
@@ -13,86 +21,354 b' log = logging.getLogger(__name__)'
13 class ApiController(JSONRPCController):
21 class ApiController(JSONRPCController):
14 """
22 """
15 API Controller
23 API Controller
16
24
17
25
18 Each method needs to have USER as argument this is then based on given
26 Each method needs to have USER as argument this is then based on given
19 API_KEY propagated as instance of user object
27 API_KEY propagated as instance of user object
20
28
21 Preferably this should be first argument also
29 Preferably this should be first argument also
22
30
23
31
24 Each function should also **raise** JSONRPCError for any
32 Each function should also **raise** JSONRPCError for any
25 errors that happens
33 errors that happens
26
34
27 """
35 """
28
36
29 @HasPermissionAllDecorator('hg.admin')
37 @HasPermissionAllDecorator('hg.admin')
30 def pull(self, apiuser, repo):
38 def pull(self, apiuser, repo):
31 """
39 """
32 Dispatch pull action on given repo
40 Dispatch pull action on given repo
33
41
34
42
35 :param user:
43 :param user:
36 :param repo:
44 :param repo:
37 """
45 """
38
46
39 if Repository.is_valid(repo) is False:
47 if Repository.is_valid(repo) is False:
40 raise JSONRPCError('Unknown repo "%s"' % repo)
48 raise JSONRPCError('Unknown repo "%s"' % repo)
41
49
42 try:
50 try:
43 ScmModel().pull_changes(repo, self.rhodecode_user.username)
51 ScmModel().pull_changes(repo, self.rhodecode_user.username)
44 return 'Pulled from %s' % repo
52 return 'Pulled from %s' % repo
45 except Exception:
53 except Exception:
46 raise JSONRPCError('Unable to pull changes from "%s"' % repo)
54 raise JSONRPCError('Unable to pull changes from "%s"' % repo)
47
55
56 @HasPermissionAllDecorator('hg.admin')
57 def get_user(self, apiuser, username):
58 """"
59 Get a user by username
60
61 :param apiuser
62 :param username
63 """
64
65 user = User.get_by_username(username)
66 if not user:
67 return None
68
69 return dict(id=user.user_id,
70 username=user.username,
71 firstname=user.name,
72 lastname=user.lastname,
73 email=user.email,
74 active=user.active,
75 admin=user.admin,
76 ldap=user.ldap_dn)
48
77
49 @HasPermissionAllDecorator('hg.admin')
78 @HasPermissionAllDecorator('hg.admin')
50 def create_user(self, apiuser, username, password, active, admin, name,
79 def get_users(self, apiuser):
51 lastname, email):
80 """"
81 Get all users
82
83 :param apiuser
52 """
84 """
53 Creates new user
85
54
86 result = []
87 for user in User.getAll():
88 result.append(dict(id=user.user_id,
89 username=user.username,
90 firstname=user.name,
91 lastname=user.lastname,
92 email=user.email,
93 active=user.active,
94 admin=user.admin,
95 ldap=user.ldap_dn))
96 return result
97
98 @HasPermissionAllDecorator('hg.admin')
99 def create_user(self, apiuser, username, password, firstname,
100 lastname, email, active=True, admin=False, ldap_dn=None):
101 """
102 Create new user
103
55 :param apiuser:
104 :param apiuser:
56 :param username:
105 :param username:
57 :param password:
106 :param password:
58 :param active:
59 :param admin:
60 :param name:
107 :param name:
61 :param lastname:
108 :param lastname:
62 :param email:
109 :param email:
110 :param active:
111 :param admin:
112 :param ldap_dn:
63 """
113 """
64
114
65 form_data = dict(username=username,
115 if self.get_user(apiuser, username):
66 password=password,
116 raise JSONRPCError("user %s already exist" % username)
67 active=active,
117
68 admin=admin,
69 name=name,
70 lastname=lastname,
71 email=email)
72 try:
118 try:
73 u = User.create(form_data)
119 form_data = dict(username=username,
74 return {'id':u.user_id,
120 password=password,
75 'msg':'created new user %s' % name}
121 active=active,
122 admin=admin,
123 name=firstname,
124 lastname=lastname,
125 email=email,
126 ldap_dn=ldap_dn)
127 UserModel().create_ldap(username, password, ldap_dn, form_data)
128 return dict(msg='created new user %s' % username)
76 except Exception:
129 except Exception:
77 log.error(traceback.format_exc())
130 log.error(traceback.format_exc())
78 raise JSONRPCError('failed to create user %s' % name)
131 raise JSONRPCError('failed to create user %s' % username)
132
133 @HasPermissionAllDecorator('hg.admin')
134 def get_users_group(self, apiuser, group_name):
135 """"
136 Get users group by name
137
138 :param apiuser
139 :param group_name
140 """
141
142 users_group = UsersGroup.get_by_group_name(group_name)
143 if not users_group:
144 return None
79
145
146 members = []
147 for user in users_group.members:
148 user = user.user
149 members.append(dict(id=user.user_id,
150 username=user.username,
151 firstname=user.name,
152 lastname=user.lastname,
153 email=user.email,
154 active=user.active,
155 admin=user.admin,
156 ldap=user.ldap_dn))
157
158 return dict(id=users_group.users_group_id,
159 name=users_group.users_group_name,
160 active=users_group.users_group_active,
161 members=members)
80
162
81 @HasPermissionAllDecorator('hg.admin')
163 @HasPermissionAllDecorator('hg.admin')
82 def create_users_group(self, apiuser, name, active):
164 def get_users_groups(self, apiuser):
165 """"
166 Get all users groups
167
168 :param apiuser
169 """
170
171 result = []
172 for users_group in UsersGroup.getAll():
173 members = []
174 for user in users_group.members:
175 user = user.user
176 members.append(dict(id=user.user_id,
177 username=user.username,
178 firstname=user.name,
179 lastname=user.lastname,
180 email=user.email,
181 active=user.active,
182 admin=user.admin,
183 ldap=user.ldap_dn))
184
185 result.append(dict(id=users_group.users_group_id,
186 name=users_group.users_group_name,
187 active=users_group.users_group_active,
188 members=members))
189 return result
190
191 @HasPermissionAllDecorator('hg.admin')
192 def create_users_group(self, apiuser, name, active=True):
83 """
193 """
84 Creates an new usergroup
194 Creates an new usergroup
85
195
86 :param name:
196 :param name:
87 :param active:
197 :param active:
88 """
198 """
89 form_data = {'users_group_name':name,
199
90 'users_group_active':active}
200 if self.get_users_group(apiuser, name):
201 raise JSONRPCError("users group %s already exist" % name)
202
91 try:
203 try:
204 form_data = dict(users_group_name=name,
205 users_group_active=active)
92 ug = UsersGroup.create(form_data)
206 ug = UsersGroup.create(form_data)
93 return {'id':ug.users_group_id,
207 return dict(id=ug.users_group_id,
94 'msg':'created new users group %s' % name}
208 msg='created new users group %s' % name)
95 except Exception:
209 except Exception:
96 log.error(traceback.format_exc())
210 log.error(traceback.format_exc())
97 raise JSONRPCError('failed to create group %s' % name)
211 raise JSONRPCError('failed to create group %s' % name)
98 No newline at end of file
212
213 @HasPermissionAllDecorator('hg.admin')
214 def add_user_to_users_group(self, apiuser, group_name, user_name):
215 """"
216 Add a user to a group
217
218 :param apiuser
219 :param group_name
220 :param user_name
221 """
222
223 try:
224 users_group = UsersGroup.get_by_group_name(group_name)
225 if not users_group:
226 raise JSONRPCError('unknown users group %s' % group_name)
227
228 try:
229 user = User.get_by_username(user_name)
230 except NoResultFound:
231 raise JSONRPCError('unknown user %s' % user_name)
232
233 ugm = UsersGroupModel().add_user_to_group(users_group, user)
234
235 return dict(id=ugm.users_group_member_id,
236 msg='created new users group member')
237 except Exception:
238 log.error(traceback.format_exc())
239 raise JSONRPCError('failed to create users group member')
240
241 @HasPermissionAnyDecorator('hg.admin')
242 def get_repo(self, apiuser, repo_name):
243 """"
244 Get repository by name
245
246 :param apiuser
247 :param repo_name
248 """
249
250 try:
251 repo = Repository.get_by_repo_name(repo_name)
252 except NoResultFound:
253 return None
254
255 members = []
256 for user in repo.repo_to_perm:
257 perm = user.permission.permission_name
258 user = user.user
259 members.append(dict(type_="user",
260 id=user.user_id,
261 username=user.username,
262 firstname=user.name,
263 lastname=user.lastname,
264 email=user.email,
265 active=user.active,
266 admin=user.admin,
267 ldap=user.ldap_dn,
268 permission=perm))
269 for users_group in repo.users_group_to_perm:
270 perm = users_group.permission.permission_name
271 users_group = users_group.users_group
272 members.append(dict(type_="users_group",
273 id=users_group.users_group_id,
274 name=users_group.users_group_name,
275 active=users_group.users_group_active,
276 permission=perm))
277
278 return dict(id=repo.repo_id,
279 name=repo.repo_name,
280 type=repo.repo_type,
281 description=repo.description,
282 members=members)
283
284 @HasPermissionAnyDecorator('hg.admin')
285 def get_repos(self, apiuser):
286 """"
287 Get all repositories
288
289 :param apiuser
290 """
291
292 result = []
293 for repository in Repository.getAll():
294 result.append(dict(id=repository.repo_id,
295 name=repository.repo_name,
296 type=repository.repo_type,
297 description=repository.description))
298 return result
299
300 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
301 def create_repo(self, apiuser, name, owner_name, description='',
302 repo_type='hg', private=False):
303 """
304 Create a repository
305
306 :param apiuser
307 :param name
308 :param description
309 :param type
310 :param private
311 :param owner_name
312 """
313
314 try:
315 try:
316 owner = User.get_by_username(owner_name)
317 except NoResultFound:
318 raise JSONRPCError('unknown user %s' % owner)
319
320 if self.get_repo(apiuser, name):
321 raise JSONRPCError("repo %s already exist" % name)
322
323 groups = name.split('/')
324 real_name = groups[-1]
325 groups = groups[:-1]
326 parent_id = None
327 for g in groups:
328 group = Group.get_by_group_name(g)
329 if not group:
330 group = ReposGroupModel().create(dict(group_name=g,
331 group_description='',
332 group_parent_id=parent_id))
333 parent_id = group.group_id
334
335 RepoModel().create(dict(repo_name=real_name,
336 repo_name_full=name,
337 description=description,
338 private=private,
339 repo_type=repo_type,
340 repo_group=parent_id,
341 clone_uri=None), owner)
342 except Exception:
343 log.error(traceback.format_exc())
344 raise JSONRPCError('failed to create repository %s' % name)
345
346 @HasPermissionAnyDecorator('hg.admin')
347 def add_user_to_repo(self, apiuser, repo_name, user_name, perm):
348 """
349 Add permission for a user to a repository
350
351 :param apiuser
352 :param repo_name
353 :param user_name
354 :param perm
355 """
356
357 try:
358 try:
359 repo = Repository.get_by_repo_name(repo_name)
360 except NoResultFound:
361 raise JSONRPCError('unknown repository %s' % repo)
362
363 try:
364 user = User.get_by_username(user_name)
365 except NoResultFound:
366 raise JSONRPCError('unknown user %s' % user)
367
368 RepositoryPermissionModel()\
369 .update_or_delete_user_permission(repo, user, perm)
370 except Exception:
371 log.error(traceback.format_exc())
372 raise JSONRPCError('failed to edit permission %(repo)s for %(user)s'
373 % dict(user=user_name, repo=repo_name))
374
@@ -42,7 +42,7 b' from rhodecode.lib.utils import invalida'
42
42
43 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
43 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
44 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.repo import RepoModel
45 from rhodecode.model.db import User
45 from rhodecode.model.db import Group
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
@@ -52,7 +52,15 b' class SettingsController(BaseRepoControl'
52 @LoginRequired()
52 @LoginRequired()
53 def __before__(self):
53 def __before__(self):
54 super(SettingsController, self).__before__()
54 super(SettingsController, self).__before__()
55
55
56 def __load_defaults(self):
57 c.repo_groups = Group.groups_choices()
58 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
59
60 repo_model = RepoModel()
61 c.users_array = repo_model.get_users_js()
62 c.users_groups_array = repo_model.get_users_groups_js()
63
56 @HasRepoPermissionAllDecorator('repository.admin')
64 @HasRepoPermissionAllDecorator('repository.admin')
57 def index(self, repo_name):
65 def index(self, repo_name):
58 repo_model = RepoModel()
66 repo_model = RepoModel()
@@ -66,28 +74,9 b' class SettingsController(BaseRepoControl'
66
74
67 return redirect(url('home'))
75 return redirect(url('home'))
68
76
69 c.users_array = repo_model.get_users_js()
77 self.__load_defaults()
70 c.users_groups_array = repo_model.get_users_groups_js()
71
72 defaults = c.repo_info.get_dict()
73
78
74 #fill owner
79 defaults = RepoModel()._get_defaults(repo_name)
75 if c.repo_info.user:
76 defaults.update({'user': c.repo_info.user.username})
77 else:
78 replacement_user = self.sa.query(User)\
79 .filter(User.admin == True).first().username
80 defaults.update({'user': replacement_user})
81
82 #fill repository users
83 for p in c.repo_info.repo_to_perm:
84 defaults.update({'u_perm_%s' % p.user.username:
85 p.permission.permission_name})
86
87 #fill repository groups
88 for p in c.repo_info.users_group_to_perm:
89 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
90 p.permission.permission_name})
91
80
92 return htmlfill.render(
81 return htmlfill.render(
93 render('settings/repo_settings.html'),
82 render('settings/repo_settings.html'),
@@ -100,17 +89,22 b' class SettingsController(BaseRepoControl'
100 def update(self, repo_name):
89 def update(self, repo_name):
101 repo_model = RepoModel()
90 repo_model = RepoModel()
102 changed_name = repo_name
91 changed_name = repo_name
92
93 self.__load_defaults()
94
103 _form = RepoSettingsForm(edit=True,
95 _form = RepoSettingsForm(edit=True,
104 old_data={'repo_name': repo_name})()
96 old_data={'repo_name': repo_name},
97 repo_groups=c.repo_groups_choices)()
105 try:
98 try:
106 form_result = _form.to_python(dict(request.POST))
99 form_result = _form.to_python(dict(request.POST))
100
107 repo_model.update(repo_name, form_result)
101 repo_model.update(repo_name, form_result)
108 invalidate_cache('get_repo_cached_%s' % repo_name)
102 invalidate_cache('get_repo_cached_%s' % repo_name)
109 h.flash(_('Repository %s updated successfully' % repo_name),
103 h.flash(_('Repository %s updated successfully' % repo_name),
110 category='success')
104 category='success')
111 changed_name = form_result['repo_name']
105 changed_name = form_result['repo_name_full']
112 action_logger(self.rhodecode_user, 'user_updated_repo',
106 action_logger(self.rhodecode_user, 'user_updated_repo',
113 changed_name, '', self.sa)
107 changed_name, '', self.sa)
114 except formencode.Invalid, errors:
108 except formencode.Invalid, errors:
115 c.repo_info = repo_model.get_by_repo_name(repo_name)
109 c.repo_info = repo_model.get_by_repo_name(repo_name)
116 c.users_array = repo_model.get_users_js()
110 c.users_array = repo_model.get_users_js()
@@ -394,13 +394,12 b' def get_current_revision(quiet=False):'
394 try:
394 try:
395 from vcs import get_repo
395 from vcs import get_repo
396 from vcs.utils.helpers import get_scm
396 from vcs.utils.helpers import get_scm
397 from vcs.exceptions import RepositoryError, VCSError
398 repopath = os.path.join(os.path.dirname(__file__), '..', '..')
397 repopath = os.path.join(os.path.dirname(__file__), '..', '..')
399 scm = get_scm(repopath)[0]
398 scm = get_scm(repopath)[0]
400 repo = get_repo(path=repopath, alias=scm)
399 repo = get_repo(path=repopath, alias=scm)
401 tip = repo.get_changeset()
400 tip = repo.get_changeset()
402 return (tip.revision, tip.short_id)
401 return (tip.revision, tip.short_id)
403 except (ImportError, RepositoryError, VCSError), err:
402 except Exception, err:
404 if not quiet:
403 if not quiet:
405 print ("Cannot retrieve rhodecode's revision. Original error "
404 print ("Cannot retrieve rhodecode's revision. Original error "
406 "was: %s" % err)
405 "was: %s" % err)
@@ -53,8 +53,10 b' class AuthLdap(object):'
53 if self.TLS_KIND == 'LDAPS':
53 if self.TLS_KIND == 'LDAPS':
54 port = port or 689
54 port = port or 689
55 ldap_server_type = ldap_server_type + 's'
55 ldap_server_type = ldap_server_type + 's'
56
56
57 self.TLS_REQCERT = ldap.__dict__['OPT_X_TLS_' + tls_reqcert]
57 OPT_X_TLS_DEMAND = 2
58 self.TLS_REQCERT = getattr(ldap, 'OPT_X_TLS_%s' % tls_reqcert,
59 OPT_X_TLS_DEMAND)
58 self.LDAP_SERVER_ADDRESS = server
60 self.LDAP_SERVER_ADDRESS = server
59 self.LDAP_SERVER_PORT = port
61 self.LDAP_SERVER_PORT = port
60
62
@@ -63,12 +65,12 b' class AuthLdap(object):'
63 self.LDAP_BIND_PASS = bind_pass
65 self.LDAP_BIND_PASS = bind_pass
64
66
65 self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
67 self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
66 self.LDAP_SERVER_ADDRESS,
68 self.LDAP_SERVER_ADDRESS,
67 self.LDAP_SERVER_PORT)
69 self.LDAP_SERVER_PORT)
68
70
69 self.BASE_DN = base_dn
71 self.BASE_DN = base_dn
70 self.LDAP_FILTER = ldap_filter
72 self.LDAP_FILTER = ldap_filter
71 self.SEARCH_SCOPE = ldap.__dict__['SCOPE_' + search_scope]
73 self.SEARCH_SCOPE = getattr(ldap, 'SCOPE_%s' % search_scope)
72 self.attr_login = attr_login
74 self.attr_login = attr_login
73
75
74 def authenticate_ldap(self, username, password):
76 def authenticate_ldap(self, username, password):
@@ -88,7 +90,9 b' class AuthLdap(object):'
88 if "," in username:
90 if "," in username:
89 raise LdapUsernameError("invalid character in username: ,")
91 raise LdapUsernameError("invalid character in username: ,")
90 try:
92 try:
91 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
93 if hasattr(ldap,'OPT_X_TLS_CACERTDIR'):
94 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR,
95 '/etc/openldap/cacerts')
92 ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
96 ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
93 ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
97 ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
94 ldap.set_option(ldap.OPT_TIMEOUT, 20)
98 ldap.set_option(ldap.OPT_TIMEOUT, 20)
@@ -356,9 +356,10 b' def send_email(recipients, subject, body'
356 tls = str2bool(email_config.get('smtp_use_tls'))
356 tls = str2bool(email_config.get('smtp_use_tls'))
357 ssl = str2bool(email_config.get('smtp_use_ssl'))
357 ssl = str2bool(email_config.get('smtp_use_ssl'))
358 debug = str2bool(config.get('debug'))
358 debug = str2bool(config.get('debug'))
359 smtp_auth = email_config.get('smtp_auth')
359
360
360 try:
361 try:
361 m = SmtpMailer(mail_from, user, passwd, mail_server,
362 m = SmtpMailer(mail_from, user, passwd, mail_server,smtp_auth,
362 mail_port, ssl, tls, debug=debug)
363 mail_port, ssl, tls, debug=debug)
363 m.send(recipients, subject, body)
364 m.send(recipients, subject, body)
364 except:
365 except:
@@ -167,6 +167,8 b' class SimpleGit(object):'
167 username = REMOTE_USER(environ)
167 username = REMOTE_USER(environ)
168 try:
168 try:
169 user = self.__get_user(username)
169 user = self.__get_user(username)
170 if user is None:
171 return HTTPForbidden()(environ, start_response)
170 username = user.username
172 username = user.username
171 except:
173 except:
172 log.error(traceback.format_exc())
174 log.error(traceback.format_exc())
@@ -133,6 +133,8 b' class SimpleHg(object):'
133 username = REMOTE_USER(environ)
133 username = REMOTE_USER(environ)
134 try:
134 try:
135 user = self.__get_user(username)
135 user = self.__get_user(username)
136 if user is None:
137 return HTTPForbidden()(environ, start_response)
136 username = user.username
138 username = user.username
137 except:
139 except:
138 log.error(traceback.format_exc())
140 log.error(traceback.format_exc())
@@ -39,7 +39,7 b' from email import encoders'
39 class SmtpMailer(object):
39 class SmtpMailer(object):
40 """SMTP mailer class
40 """SMTP mailer class
41
41
42 mailer = SmtpMailer(mail_from, user, passwd, mail_server,
42 mailer = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth
43 mail_port, ssl, tls)
43 mail_port, ssl, tls)
44 mailer.send(recipients, subject, body, attachment_files)
44 mailer.send(recipients, subject, body, attachment_files)
45
45
@@ -49,8 +49,8 b' class SmtpMailer(object):'
49
49
50 """
50 """
51
51
52 def __init__(self, mail_from, user, passwd, mail_server,
52 def __init__(self, mail_from, user, passwd, mail_server, smtp_auth=None,
53 mail_port=None, ssl=False, tls=False, debug=False):
53 mail_port=None, ssl=False, tls=False, debug=False):
54
54
55 self.mail_from = mail_from
55 self.mail_from = mail_from
56 self.mail_server = mail_server
56 self.mail_server = mail_server
@@ -60,6 +60,7 b' class SmtpMailer(object):'
60 self.ssl = ssl
60 self.ssl = ssl
61 self.tls = tls
61 self.tls = tls
62 self.debug = debug
62 self.debug = debug
63 self.auth = smtp_auth
63
64
64 def send(self, recipients=[], subject='', body='', attachment_files=None):
65 def send(self, recipients=[], subject='', body='', attachment_files=None):
65
66
@@ -78,9 +79,11 b' class SmtpMailer(object):'
78 smtp_serv.set_debuglevel(1)
79 smtp_serv.set_debuglevel(1)
79
80
80 smtp_serv.ehlo()
81 smtp_serv.ehlo()
82 if self.auth:
83 smtp_serv.esmtp_features["auth"] = self.auth
81
84
82 #if server requires authorization you must provide login and password
85 # if server requires authorization you must provide login and password
83 #but only if we have them
86 # but only if we have them
84 if self.user and self.passwd:
87 if self.user and self.passwd:
85 smtp_serv.login(self.user, self.passwd)
88 smtp_serv.login(self.user, self.passwd)
86
89
@@ -156,6 +159,7 b' class SmtpMailer(object):'
156 if isinstance(msg_file, str):
159 if isinstance(msg_file, str):
157 return open(msg_file, "rb").read()
160 return open(msg_file, "rb").read()
158 else:
161 else:
159 #just for safe seek to 0
162 # just for safe seek to 0
160 msg_file.seek(0)
163 msg_file.seek(0)
161 return msg_file.read()
164 return msg_file.read()
165
@@ -30,11 +30,8 b' import traceback'
30 from datetime import date
30 from datetime import date
31
31
32 from sqlalchemy import *
32 from sqlalchemy import *
33 from sqlalchemy.exc import DatabaseError
34 from sqlalchemy.ext.hybrid import hybrid_property
33 from sqlalchemy.ext.hybrid import hybrid_property
35 from sqlalchemy.orm import relationship, backref, joinedload, class_mapper, \
34 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
36 validates
37 from sqlalchemy.orm.interfaces import MapperExtension
38 from beaker.cache import cache_region, region_invalidate
35 from beaker.cache import cache_region, region_invalidate
39
36
40 from vcs import get_backend
37 from vcs import get_backend
@@ -60,24 +57,24 b' log = logging.getLogger(__name__)'
60 class ModelSerializer(json.JSONEncoder):
57 class ModelSerializer(json.JSONEncoder):
61 """
58 """
62 Simple Serializer for JSON,
59 Simple Serializer for JSON,
63
60
64 usage::
61 usage::
65
62
66 to make object customized for serialization implement a __json__
63 to make object customized for serialization implement a __json__
67 method that will return a dict for serialization into json
64 method that will return a dict for serialization into json
68
65
69 example::
66 example::
70
67
71 class Task(object):
68 class Task(object):
72
69
73 def __init__(self, name, value):
70 def __init__(self, name, value):
74 self.name = name
71 self.name = name
75 self.value = value
72 self.value = value
76
73
77 def __json__(self):
74 def __json__(self):
78 return dict(name=self.name,
75 return dict(name=self.name,
79 value=self.value)
76 value=self.value)
80
77
81 """
78 """
82
79
83 def default(self, obj):
80 def default(self, obj):
@@ -129,11 +126,15 b' class BaseModel(object):'
129 @classmethod
126 @classmethod
130 def get(cls, id_):
127 def get(cls, id_):
131 if id_:
128 if id_:
132 return Session.query(cls).get(id_)
129 return cls.query().get(id_)
130
131 @classmethod
132 def getAll(cls):
133 return cls.query().all()
133
134
134 @classmethod
135 @classmethod
135 def delete(cls, id_):
136 def delete(cls, id_):
136 obj = Session.query(cls).get(id_)
137 obj = cls.query().get(id_)
137 Session.delete(obj)
138 Session.delete(obj)
138 Session.commit()
139 Session.commit()
139
140
@@ -160,13 +161,13 b' class RhodeCodeSettings(Base, BaseModel)'
160 v = self._app_settings_value
161 v = self._app_settings_value
161 if v == 'ldap_active':
162 if v == 'ldap_active':
162 v = str2bool(v)
163 v = str2bool(v)
163 return v
164 return v
164
165
165 @app_settings_value.setter
166 @app_settings_value.setter
166 def app_settings_value(self,val):
167 def app_settings_value(self, val):
167 """
168 """
168 Setter that will always make sure we use unicode in app_settings_value
169 Setter that will always make sure we use unicode in app_settings_value
169
170
170 :param val:
171 :param val:
171 """
172 """
172 self._app_settings_value = safe_unicode(val)
173 self._app_settings_value = safe_unicode(val)
@@ -178,13 +179,13 b' class RhodeCodeSettings(Base, BaseModel)'
178
179
179 @classmethod
180 @classmethod
180 def get_by_name(cls, ldap_key):
181 def get_by_name(cls, ldap_key):
181 return Session.query(cls)\
182 return cls.query()\
182 .filter(cls.app_settings_name == ldap_key).scalar()
183 .filter(cls.app_settings_name == ldap_key).scalar()
183
184
184 @classmethod
185 @classmethod
185 def get_app_settings(cls, cache=False):
186 def get_app_settings(cls, cache=False):
186
187
187 ret = Session.query(cls)
188 ret = cls.query()
188
189
189 if cache:
190 if cache:
190 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
191 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
@@ -200,7 +201,7 b' class RhodeCodeSettings(Base, BaseModel)'
200
201
201 @classmethod
202 @classmethod
202 def get_ldap_settings(cls, cache=False):
203 def get_ldap_settings(cls, cache=False):
203 ret = Session.query(cls)\
204 ret = cls.query()\
204 .filter(cls.app_settings_name.startswith('ldap_')).all()
205 .filter(cls.app_settings_name.startswith('ldap_')).all()
205 fd = {}
206 fd = {}
206 for row in ret:
207 for row in ret:
@@ -227,7 +228,7 b' class RhodeCodeUi(Base, BaseModel):'
227
228
228 @classmethod
229 @classmethod
229 def get_by_key(cls, key):
230 def get_by_key(cls, key):
230 return Session.query(cls).filter(cls.ui_key == key)
231 return cls.query().filter(cls.ui_key == key)
231
232
232
233
233 @classmethod
234 @classmethod
@@ -311,7 +312,7 b' class User(Base, BaseModel):'
311
312
312 @classmethod
313 @classmethod
313 def get_by_api_key(cls, api_key):
314 def get_by_api_key(cls, api_key):
314 return Session.query(cls).filter(cls.api_key == api_key).one()
315 return cls.query().filter(cls.api_key == api_key).one()
315
316
316 def update_lastlogin(self):
317 def update_lastlogin(self):
317 """Update user lastlogin"""
318 """Update user lastlogin"""
@@ -376,11 +377,11 b' class UsersGroup(Base, BaseModel):'
376 @classmethod
377 @classmethod
377 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
378 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
378 if case_insensitive:
379 if case_insensitive:
379 gr = Session.query(cls)\
380 gr = cls.query()\
380 .filter(cls.users_group_name.ilike(group_name))
381 .filter(cls.users_group_name.ilike(group_name))
381 else:
382 else:
382 gr = Session.query(UsersGroup)\
383 gr = cls.query()\
383 .filter(UsersGroup.users_group_name == group_name)
384 .filter(cls.users_group_name == group_name)
384 if cache:
385 if cache:
385 gr = gr.options(FromCache("sql_cache_short",
386 gr = gr.options(FromCache("sql_cache_short",
386 "get_user_%s" % group_name))
387 "get_user_%s" % group_name))
@@ -389,7 +390,7 b' class UsersGroup(Base, BaseModel):'
389
390
390 @classmethod
391 @classmethod
391 def get(cls, users_group_id, cache=False):
392 def get(cls, users_group_id, cache=False):
392 users_group = Session.query(cls)
393 users_group = cls.query()
393 if cache:
394 if cache:
394 users_group = users_group.options(FromCache("sql_cache_short",
395 users_group = users_group.options(FromCache("sql_cache_short",
395 "get_users_group_%s" % users_group_id))
396 "get_users_group_%s" % users_group_id))
@@ -422,10 +423,10 b' class UsersGroup(Base, BaseModel):'
422 Session.flush()
423 Session.flush()
423 members_list = []
424 members_list = []
424 if v:
425 if v:
426 v = [v] if isinstance(v, basestring) else v
425 for u_id in set(v):
427 for u_id in set(v):
426 members_list.append(UsersGroupMember(
428 member = UsersGroupMember(users_group_id, u_id)
427 users_group_id,
429 members_list.append(member)
428 u_id))
429 setattr(users_group, 'members', members_list)
430 setattr(users_group, 'members', members_list)
430 setattr(users_group, k, v)
431 setattr(users_group, k, v)
431
432
@@ -457,7 +458,6 b' class UsersGroup(Base, BaseModel):'
457 Session.rollback()
458 Session.rollback()
458 raise
459 raise
459
460
460
461 class UsersGroupMember(Base, BaseModel):
461 class UsersGroupMember(Base, BaseModel):
462 __tablename__ = 'users_groups_members'
462 __tablename__ = 'users_groups_members'
463 __table_args__ = {'extend_existing':True}
463 __table_args__ = {'extend_existing':True}
@@ -473,6 +473,15 b' class UsersGroupMember(Base, BaseModel):'
473 self.users_group_id = gr_id
473 self.users_group_id = gr_id
474 self.user_id = u_id
474 self.user_id = u_id
475
475
476 @staticmethod
477 def add_user_to_group(group, user):
478 ugm = UsersGroupMember()
479 ugm.users_group = group
480 ugm.user = user
481 Session.add(ugm)
482 Session.commit()
483 return ugm
484
476 class Repository(Base, BaseModel):
485 class Repository(Base, BaseModel):
477 __tablename__ = 'repositories'
486 __tablename__ = 'repositories'
478 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
487 __table_args__ = (UniqueConstraint('repo_name'), {'extend_existing':True},)
@@ -510,29 +519,27 b' class Repository(Base, BaseModel):'
510 @classmethod
519 @classmethod
511 def url_sep(cls):
520 def url_sep(cls):
512 return '/'
521 return '/'
513
522
514 @classmethod
523 @classmethod
515 def get_by_repo_name(cls, repo_name):
524 def get_by_repo_name(cls, repo_name):
516 q = Session.query(cls).filter(cls.repo_name == repo_name)
525 q = Session.query(cls).filter(cls.repo_name == repo_name)
517
518 q = q.options(joinedload(Repository.fork))\
526 q = q.options(joinedload(Repository.fork))\
519 .options(joinedload(Repository.user))\
527 .options(joinedload(Repository.user))\
520 .options(joinedload(Repository.group))\
528 .options(joinedload(Repository.group))
521
522 return q.one()
529 return q.one()
523
530
524 @classmethod
531 @classmethod
525 def get_repo_forks(cls, repo_id):
532 def get_repo_forks(cls, repo_id):
526 return Session.query(cls).filter(Repository.fork_id == repo_id)
533 return cls.query().filter(Repository.fork_id == repo_id)
527
534
528 @classmethod
535 @classmethod
529 def base_path(cls):
536 def base_path(cls):
530 """
537 """
531 Returns base path when all repos are stored
538 Returns base path when all repos are stored
532
539
533 :param cls:
540 :param cls:
534 """
541 """
535 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
542 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
536 cls.url_sep())
543 cls.url_sep())
537 q.options(FromCache("sql_cache_short", "repository_repo_path"))
544 q.options(FromCache("sql_cache_short", "repository_repo_path"))
538 return q.one().ui_value
545 return q.one().ui_value
@@ -568,7 +575,7 b' class Repository(Base, BaseModel):'
568 Returns base full path for that repository means where it actually
575 Returns base full path for that repository means where it actually
569 exists on a filesystem
576 exists on a filesystem
570 """
577 """
571 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
578 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
572 Repository.url_sep())
579 Repository.url_sep())
573 q.options(FromCache("sql_cache_short", "repository_repo_path"))
580 q.options(FromCache("sql_cache_short", "repository_repo_path"))
574 return q.one().ui_value
581 return q.one().ui_value
@@ -585,7 +592,7 b' class Repository(Base, BaseModel):'
585 def get_new_name(self, repo_name):
592 def get_new_name(self, repo_name):
586 """
593 """
587 returns new full repository name based on assigned group and new new
594 returns new full repository name based on assigned group and new new
588
595
589 :param group_name:
596 :param group_name:
590 """
597 """
591 path_prefix = self.group.full_path_splitted if self.group else []
598 path_prefix = self.group.full_path_splitted if self.group else []
@@ -606,7 +613,7 b' class Repository(Base, BaseModel):'
606 baseui._tcfg = config.config()
613 baseui._tcfg = config.config()
607
614
608
615
609 ret = Session.query(RhodeCodeUi)\
616 ret = RhodeCodeUi.query()\
610 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
617 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
611
618
612 hg_ui = ret
619 hg_ui = ret
@@ -622,7 +629,7 b' class Repository(Base, BaseModel):'
622 def is_valid(cls, repo_name):
629 def is_valid(cls, repo_name):
623 """
630 """
624 returns True if given repo name is a valid filesystem repository
631 returns True if given repo name is a valid filesystem repository
625
632
626 @param cls:
633 @param cls:
627 @param repo_name:
634 @param repo_name:
628 """
635 """
@@ -661,7 +668,7 b' class Repository(Base, BaseModel):'
661 None otherwise. `cache_active = False` means that this cache
668 None otherwise. `cache_active = False` means that this cache
662 state is not valid and needs to be invalidated
669 state is not valid and needs to be invalidated
663 """
670 """
664 return Session.query(CacheInvalidation)\
671 return CacheInvalidation.query()\
665 .filter(CacheInvalidation.cache_key == self.repo_name)\
672 .filter(CacheInvalidation.cache_key == self.repo_name)\
666 .filter(CacheInvalidation.cache_active == False)\
673 .filter(CacheInvalidation.cache_active == False)\
667 .scalar()
674 .scalar()
@@ -670,7 +677,7 b' class Repository(Base, BaseModel):'
670 """
677 """
671 set a cache for invalidation for this instance
678 set a cache for invalidation for this instance
672 """
679 """
673 inv = Session.query(CacheInvalidation)\
680 inv = CacheInvalidation.query()\
674 .filter(CacheInvalidation.cache_key == self.repo_name)\
681 .filter(CacheInvalidation.cache_key == self.repo_name)\
675 .scalar()
682 .scalar()
676
683
@@ -763,17 +770,26 b' class Group(Base, BaseModel):'
763
770
764 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
771 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
765 for x in cls.query().all()])
772 for x in cls.query().all()])
766
773
767 repo_groups = sorted(repo_groups,key=lambda t: t[1].split(sep)[0])
774 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
768 return repo_groups
775 return repo_groups
769
776
770 @classmethod
777 @classmethod
771 def url_sep(cls):
778 def url_sep(cls):
772 return '/'
779 return '/'
773
780
774 @classmethod
781 @classmethod
775 def get_by_group_name(cls, group_name):
782 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
776 return cls.query().filter(cls.group_name == group_name).scalar()
783 if case_insensitive:
784 gr = cls.query()\
785 .filter(cls.group_name.ilike(group_name))
786 else:
787 gr = cls.query()\
788 .filter(cls.group_name == group_name)
789 if cache:
790 gr = gr.options(FromCache("sql_cache_short",
791 "get_group_%s" % group_name))
792 return gr.scalar()
777
793
778 @property
794 @property
779 def parents(self):
795 def parents(self):
@@ -801,7 +817,7 b' class Group(Base, BaseModel):'
801
817
802 @property
818 @property
803 def children(self):
819 def children(self):
804 return Session.query(Group).filter(Group.parent_group == self)
820 return Group.query().filter(Group.parent_group == self)
805
821
806 @property
822 @property
807 def name(self):
823 def name(self):
@@ -817,7 +833,7 b' class Group(Base, BaseModel):'
817
833
818 @property
834 @property
819 def repositories(self):
835 def repositories(self):
820 return Session.query(Repository).filter(Repository.group == self)
836 return Repository.query().filter(Repository.group == self)
821
837
822 @property
838 @property
823 def repositories_recursive_count(self):
839 def repositories_recursive_count(self):
@@ -836,10 +852,11 b' class Group(Base, BaseModel):'
836 def get_new_name(self, group_name):
852 def get_new_name(self, group_name):
837 """
853 """
838 returns new full group name based on parent and new name
854 returns new full group name based on parent and new name
839
855
840 :param group_name:
856 :param group_name:
841 """
857 """
842 path_prefix = self.parent_group.full_path_splitted if self.parent_group else []
858 path_prefix = (self.parent_group.full_path_splitted if
859 self.parent_group else [])
843 return Group.url_sep().join(path_prefix + [group_name])
860 return Group.url_sep().join(path_prefix + [group_name])
844
861
845
862
@@ -856,7 +873,7 b' class Permission(Base, BaseModel):'
856
873
857 @classmethod
874 @classmethod
858 def get_by_key(cls, key):
875 def get_by_key(cls, key):
859 return Session.query(cls).filter(cls.permission_name == key).scalar()
876 return cls.query().filter(cls.permission_name == key).scalar()
860
877
861 class RepoToPerm(Base, BaseModel):
878 class RepoToPerm(Base, BaseModel):
862 __tablename__ = 'repo_to_perm'
879 __tablename__ = 'repo_to_perm'
@@ -885,7 +902,7 b' class UserToPerm(Base, BaseModel):'
885 if not isinstance(perm, Permission):
902 if not isinstance(perm, Permission):
886 raise Exception('perm needs to be an instance of Permission class')
903 raise Exception('perm needs to be an instance of Permission class')
887
904
888 return Session.query(cls).filter(cls.user_id == user_id)\
905 return cls.query().filter(cls.user_id == user_id)\
889 .filter(cls.permission == perm).scalar() is not None
906 .filter(cls.permission == perm).scalar() is not None
890
907
891 @classmethod
908 @classmethod
@@ -909,7 +926,7 b' class UserToPerm(Base, BaseModel):'
909 raise Exception('perm needs to be an instance of Permission class')
926 raise Exception('perm needs to be an instance of Permission class')
910
927
911 try:
928 try:
912 Session.query(cls).filter(cls.user_id == user_id)\
929 cls.query().filter(cls.user_id == user_id)\
913 .filter(cls.permission == perm).delete()
930 .filter(cls.permission == perm).delete()
914 Session.commit()
931 Session.commit()
915 except:
932 except:
@@ -945,7 +962,7 b' class UsersGroupToPerm(Base, BaseModel):'
945 if not isinstance(perm, Permission):
962 if not isinstance(perm, Permission):
946 raise Exception('perm needs to be an instance of Permission class')
963 raise Exception('perm needs to be an instance of Permission class')
947
964
948 return Session.query(cls).filter(cls.users_group_id ==
965 return cls.query().filter(cls.users_group_id ==
949 users_group_id)\
966 users_group_id)\
950 .filter(cls.permission == perm)\
967 .filter(cls.permission == perm)\
951 .scalar() is not None
968 .scalar() is not None
@@ -971,7 +988,7 b' class UsersGroupToPerm(Base, BaseModel):'
971 raise Exception('perm needs to be an instance of Permission class')
988 raise Exception('perm needs to be an instance of Permission class')
972
989
973 try:
990 try:
974 Session.query(cls).filter(cls.users_group_id == users_group_id)\
991 cls.query().filter(cls.users_group_id == users_group_id)\
975 .filter(cls.permission == perm).delete()
992 .filter(cls.permission == perm).delete()
976 Session.commit()
993 Session.commit()
977 except:
994 except:
@@ -1023,7 +1040,7 b' class UserFollowing(Base, BaseModel):'
1023
1040
1024 @classmethod
1041 @classmethod
1025 def get_repo_followers(cls, repo_id):
1042 def get_repo_followers(cls, repo_id):
1026 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
1043 return cls.query().filter(cls.follows_repo_id == repo_id)
1027
1044
1028 class CacheInvalidation(Base, BaseModel):
1045 class CacheInvalidation(Base, BaseModel):
1029 __tablename__ = 'cache_invalidation'
1046 __tablename__ = 'cache_invalidation'
@@ -1049,3 +1066,4 b' class DbMigrateVersion(Base, BaseModel):'
1049 repository_id = Column('repository_id', String(250), primary_key=True)
1066 repository_id = Column('repository_id', String(250), primary_key=True)
1050 repository_path = Column('repository_path', Text)
1067 repository_path = Column('repository_path', Text)
1051 version = Column('version', Integer)
1068 version = Column('version', Integer)
1069
@@ -185,20 +185,21 b' class ValidPassword(formencode.validator'
185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
186
186
187 def validate_python(self, value, state):
187 def validate_python(self, value, state):
188
188
189 if value['password'] != value['password_confirmation']:
189 pass_val = value.get('password') or value.get('new_password')
190 if pass_val != value['password_confirmation']:
190 e_dict = {'password_confirmation':
191 e_dict = {'password_confirmation':
191 _('Passwords do not match')}
192 _('Passwords do not match')}
192 raise formencode.Invalid('', value, state, error_dict=e_dict)
193 raise formencode.Invalid('', value, state, error_dict=e_dict)
193
194
194 class ValidAuth(formencode.validators.FancyValidator):
195 class ValidAuth(formencode.validators.FancyValidator):
195 messages = {
196 messages = {
196 'invalid_password':_('invalid password'),
197 'invalid_password':_('invalid password'),
197 'invalid_login':_('invalid user name'),
198 'invalid_login':_('invalid user name'),
198 'disabled_account':_('Your account is disabled')
199 'disabled_account':_('Your account is disabled')
199
200 }
200 }
201
201 #error mapping
202 # error mapping
202 e_dict = {'username':messages['invalid_login'],
203 e_dict = {'username':messages['invalid_login'],
203 'password':messages['invalid_password']}
204 'password':messages['invalid_password']}
204 e_dict_disable = {'username':messages['disabled_account']}
205 e_dict_disable = {'username':messages['disabled_account']}
@@ -253,6 +254,7 b' def ValidRepoName(edit, old_data):'
253 # db key This is an actual just the name to store in the
254 # db key This is an actual just the name to store in the
254 # database
255 # database
255 repo_name_full = group_path + Group.url_sep() + repo_name
256 repo_name_full = group_path + Group.url_sep() + repo_name
257
256 else:
258 else:
257 group_path = ''
259 group_path = ''
258 repo_name_full = repo_name
260 repo_name_full = repo_name
@@ -496,8 +498,6 b' class LoginForm(formencode.Schema):'
496 'tooShort':_('Enter %(min)i characters or more')}
498 'tooShort':_('Enter %(min)i characters or more')}
497 )
499 )
498
500
499
500 #chained validators have access to all data
501 chained_validators = [ValidAuth]
501 chained_validators = [ValidAuth]
502
502
503 def UserForm(edit=False, old_data={}):
503 def UserForm(edit=False, old_data={}):
@@ -508,15 +508,18 b' def UserForm(edit=False, old_data={}):'
508 ValidUsername(edit, old_data))
508 ValidUsername(edit, old_data))
509 if edit:
509 if edit:
510 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
510 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
511 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
511 admin = StringBoolean(if_missing=False)
512 admin = StringBoolean(if_missing=False)
512 else:
513 else:
513 password = All(UnicodeString(strip=True, min=6, not_empty=True))
514 password = All(UnicodeString(strip=True, min=6, not_empty=True))
515 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
516
514 active = StringBoolean(if_missing=False)
517 active = StringBoolean(if_missing=False)
515 name = UnicodeString(strip=True, min=1, not_empty=True)
518 name = UnicodeString(strip=True, min=1, not_empty=True)
516 lastname = UnicodeString(strip=True, min=1, not_empty=True)
519 lastname = UnicodeString(strip=True, min=1, not_empty=True)
517 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
520 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
518
521
519 chained_validators = [ValidPassword]
522 chained_validators = [ValidPasswordsMatch, ValidPassword]
520
523
521 return _UserForm
524 return _UserForm
522
525
@@ -616,16 +619,19 b' def RepoForkForm(edit=False, old_data={}'
616
619
617 return _RepoForkForm
620 return _RepoForkForm
618
621
619 def RepoSettingsForm(edit=False, old_data={}):
622 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
623 repo_groups=[]):
620 class _RepoForm(formencode.Schema):
624 class _RepoForm(formencode.Schema):
621 allow_extra_fields = True
625 allow_extra_fields = True
622 filter_extra_fields = False
626 filter_extra_fields = False
623 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
627 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
624 SlugifyName())
628 SlugifyName())
625 description = UnicodeString(strip=True, min=1, not_empty=True)
629 description = UnicodeString(strip=True, min=1, not_empty=True)
630 repo_group = OneOf(repo_groups, hideList=True)
626 private = StringBoolean(if_missing=False)
631 private = StringBoolean(if_missing=False)
627
632
628 chained_validators = [ValidRepoName(edit, old_data), ValidPerms, ValidSettings]
633 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
634 ValidSettings]
629 return _RepoForm
635 return _RepoForm
630
636
631
637
@@ -94,6 +94,46 b' class RepoModel(BaseModel):'
94 for gr in users_groups])
94 for gr in users_groups])
95 return users_groups_array
95 return users_groups_array
96
96
97 def _get_defaults(self, repo_name):
98 """
99 Get's information about repository, and returns a dict for
100 usage in forms
101
102 :param repo_name:
103 """
104
105 repo_info = Repository.get_by_repo_name(repo_name)
106
107 if repo_info is None:
108 return None
109
110 defaults = repo_info.get_dict()
111 group, repo_name = repo_info.groups_and_repo
112 defaults['repo_name'] = repo_name
113 defaults['repo_group'] = getattr(group[-1] if group else None,
114 'group_id', None)
115
116 # fill owner
117 if repo_info.user:
118 defaults.update({'user': repo_info.user.username})
119 else:
120 replacement_user = User.query().filter(User.admin ==
121 True).first().username
122 defaults.update({'user': replacement_user})
123
124 # fill repository users
125 for p in repo_info.repo_to_perm:
126 defaults.update({'u_perm_%s' % p.user.username:
127 p.permission.permission_name})
128
129 # fill repository groups
130 for p in repo_info.users_group_to_perm:
131 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
132 p.permission.permission_name})
133
134 return defaults
135
136
97 def update(self, repo_name, form_data):
137 def update(self, repo_name, form_data):
98 try:
138 try:
99 cur_repo = self.get_by_repo_name(repo_name, cache=False)
139 cur_repo = self.get_by_repo_name(repo_name, cache=False)
@@ -151,7 +191,7 b' class RepoModel(BaseModel):'
151 elif k == 'repo_name':
191 elif k == 'repo_name':
152 pass
192 pass
153 elif k == 'repo_group':
193 elif k == 'repo_group':
154 cur_repo.group_id = v
194 cur_repo.group = Group.get(v)
155
195
156 else:
196 else:
157 setattr(cur_repo, k, v)
197 setattr(cur_repo, k, v)
@@ -305,7 +345,7 b' class RepoModel(BaseModel):'
305 :param parent_id:
345 :param parent_id:
306 :param clone_uri:
346 :param clone_uri:
307 """
347 """
308 from rhodecode.lib.utils import is_valid_repo,is_valid_repos_group
348 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
309
349
310 if new_parent_id:
350 if new_parent_id:
311 paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
351 paths = Group.get(new_parent_id).full_path.split(Group.url_sep())
@@ -316,7 +356,7 b' class RepoModel(BaseModel):'
316 repo_path = os.path.join(*map(lambda x:safe_str(x),
356 repo_path = os.path.join(*map(lambda x:safe_str(x),
317 [self.repos_path, new_parent_path, repo_name]))
357 [self.repos_path, new_parent_path, repo_name]))
318
358
319
359
320 # check if this path is not a repository
360 # check if this path is not a repository
321 if is_valid_repo(repo_path, self.repos_path):
361 if is_valid_repo(repo_path, self.repos_path):
322 raise Exception('This path %s is a valid repository' % repo_path)
362 raise Exception('This path %s is a valid repository' % repo_path)
@@ -324,7 +364,7 b' class RepoModel(BaseModel):'
324 # check if this path is a group
364 # check if this path is a group
325 if is_valid_repos_group(repo_path, self.repos_path):
365 if is_valid_repos_group(repo_path, self.repos_path):
326 raise Exception('This path %s is a valid group' % repo_path)
366 raise Exception('This path %s is a valid group' % repo_path)
327
367
328 log.info('creating repo %s in %s @ %s', repo_name, repo_path,
368 log.info('creating repo %s in %s @ %s', repo_name, repo_path,
329 clone_uri)
369 clone_uri)
330 backend = get_backend(alias)
370 backend = get_backend(alias)
@@ -368,3 +408,4 b' class RepoModel(BaseModel):'
368 % (datetime.today()\
408 % (datetime.today()\
369 .strftime('%Y%m%d_%H%M%S_%f'),
409 .strftime('%Y%m%d_%H%M%S_%f'),
370 repo.repo_name)))
410 repo.repo_name)))
411
@@ -127,8 +127,8 b' class ReposGroupModel(BaseModel):'
127 try:
127 try:
128 repos_group = Group.get(repos_group_id)
128 repos_group = Group.get(repos_group_id)
129 old_path = repos_group.full_path
129 old_path = repos_group.full_path
130
130
131 #change properties
131 # change properties
132 repos_group.group_description = form_data['group_description']
132 repos_group.group_description = form_data['group_description']
133 repos_group.parent_group = Group.get(form_data['group_parent_id'])
133 repos_group.parent_group = Group.get(form_data['group_parent_id'])
134 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
134 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
@@ -49,7 +49,6 b" PERM_WEIGHTS = {'repository.none': 0,"
49
49
50
50
51 class UserModel(BaseModel):
51 class UserModel(BaseModel):
52
53 def get(self, user_id, cache=False):
52 def get(self, user_id, cache=False):
54 user = self.sa.query(User)
53 user = self.sa.query(User)
55 if cache:
54 if cache:
@@ -87,6 +86,7 b' class UserModel(BaseModel):'
87 new_user.api_key = generate_api_key(form_data['username'])
86 new_user.api_key = generate_api_key(form_data['username'])
88 self.sa.add(new_user)
87 self.sa.add(new_user)
89 self.sa.commit()
88 self.sa.commit()
89 return new_user
90 except:
90 except:
91 log.error(traceback.format_exc())
91 log.error(traceback.format_exc())
92 self.sa.rollback()
92 self.sa.rollback()
@@ -96,6 +96,7 b' class UserModel(BaseModel):'
96 """
96 """
97 Checks if user is in database, if not creates this user marked
97 Checks if user is in database, if not creates this user marked
98 as ldap user
98 as ldap user
99
99 :param username:
100 :param username:
100 :param password:
101 :param password:
101 :param user_dn:
102 :param user_dn:
@@ -386,3 +387,4 b' class UserModel(BaseModel):'
386 repository.repo_name] = p
387 repository.repo_name] = p
387
388
388 return user
389 return user
390
@@ -29,7 +29,7 b''
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="users_group_name">${_('Group name')}:</label>
32 <label for="group_name">${_('Group name')}:</label>
33 </div>
33 </div>
34 <div class="input">
34 <div class="input">
35 ${h.text('group_name',class_='medium')}
35 ${h.text('group_name',class_='medium')}
@@ -38,7 +38,7 b''
38
38
39 <div class="field">
39 <div class="field">
40 <div class="label label-textarea">
40 <div class="label label-textarea">
41 <label for="description">${_('Description')}:</label>
41 <label for="group_description">${_('Description')}:</label>
42 </div>
42 </div>
43 <div class="textarea text-area editor">
43 <div class="textarea text-area editor">
44 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
44 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
@@ -47,7 +47,7 b''
47
47
48 <div class="field">
48 <div class="field">
49 <div class="label">
49 <div class="label">
50 <label for="repo_group">${_('Group parent')}:</label>
50 <label for="group_parent_id">${_('Group parent')}:</label>
51 </div>
51 </div>
52 <div class="input">
52 <div class="input">
53 ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
53 ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
@@ -29,7 +29,7 b''
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="users_group_name">${_('Group name')}:</label>
32 <label for="group_name">${_('Group name')}:</label>
33 </div>
33 </div>
34 <div class="input">
34 <div class="input">
35 ${h.text('group_name',class_='medium')}
35 ${h.text('group_name',class_='medium')}
@@ -38,7 +38,7 b''
38
38
39 <div class="field">
39 <div class="field">
40 <div class="label label-textarea">
40 <div class="label label-textarea">
41 <label for="description">${_('Description')}:</label>
41 <label for="group_description">${_('Description')}:</label>
42 </div>
42 </div>
43 <div class="textarea text-area editor">
43 <div class="textarea text-area editor">
44 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
44 ${h.textarea('group_description',cols=23,rows=5,class_="medium")}
@@ -47,7 +47,7 b''
47
47
48 <div class="field">
48 <div class="field">
49 <div class="label">
49 <div class="label">
50 <label for="repo_group">${_('Group parent')}:</label>
50 <label for="group_parent_id">${_('Group parent')}:</label>
51 </div>
51 </div>
52 <div class="input">
52 <div class="input">
53 ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
53 ${h.select('group_parent_id','',c.repo_groups,class_="medium")}
@@ -34,7 +34,7 b''
34 <div class="checkboxes">
34 <div class="checkboxes">
35 <div class="checkbox">
35 <div class="checkbox">
36 ${h.checkbox('destroy',True)}
36 ${h.checkbox('destroy',True)}
37 <label for="checkbox-1">
37 <label for="destroy">
38 <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
38 <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
39 ${_('destroy old data')}</span> </label>
39 ${_('destroy old data')}</span> </label>
40 </div>
40 </div>
@@ -56,12 +56,12 b''
56 <div class="fields">
56 <div class="fields">
57 <div class="field">
57 <div class="field">
58 <div class="label label-checkbox">
58 <div class="label label-checkbox">
59 <label for="destroy">${_('index build option')}:</label>
59 <label>${_('index build option')}:</label>
60 </div>
60 </div>
61 <div class="checkboxes">
61 <div class="checkboxes">
62 <div class="checkbox">
62 <div class="checkbox">
63 ${h.checkbox('full_index',True)}
63 ${h.checkbox('full_index',True)}
64 <label for="checkbox-1">${_('build from scratch')}</label>
64 <label for="full_index">${_('build from scratch')}</label>
65 </div>
65 </div>
66 </div>
66 </div>
67 </div>
67 </div>
@@ -100,7 +100,7 b''
100
100
101 <div class="field">
101 <div class="field">
102 <div class="label">
102 <div class="label">
103 <label for="ga_code">${_('GA code')}:</label>
103 <label for="rhodecode_ga_code">${_('GA code')}:</label>
104 </div>
104 </div>
105 <div class="input">
105 <div class="input">
106 ${h.text('rhodecode_ga_code',size=30)}
106 ${h.text('rhodecode_ga_code',size=30)}
@@ -124,7 +124,7 b''
124
124
125 <div class="field">
125 <div class="field">
126 <div class="label label-checkbox">
126 <div class="label label-checkbox">
127 <label for="web_push_ssl">${_('Web')}:</label>
127 <label>${_('Web')}:</label>
128 </div>
128 </div>
129 <div class="checkboxes">
129 <div class="checkboxes">
130 <div class="checkbox">
130 <div class="checkbox">
@@ -136,7 +136,7 b''
136
136
137 <div class="field">
137 <div class="field">
138 <div class="label label-checkbox">
138 <div class="label label-checkbox">
139 <label for="web_push_ssl">${_('Hooks')}:</label>
139 <label>${_('Hooks')}:</label>
140 </div>
140 </div>
141 <div class="input">
141 <div class="input">
142 ${h.link_to(_('advanced setup'),url('admin_edit_setting',setting_id='hooks'))}
142 ${h.link_to(_('advanced setup'),url('admin_edit_setting',setting_id='hooks'))}
@@ -44,7 +44,16 b''
44 ${h.password('password',class_='small')}
44 ${h.password('password',class_='small')}
45 </div>
45 </div>
46 </div>
46 </div>
47
47
48 <div class="field">
49 <div class="label">
50 <label for="password_confirmation">${_('Password confirmation')}:</label>
51 </div>
52 <div class="input">
53 ${h.password('password_confirmation',class_="small",autocomplete="off")}
54 </div>
55 </div>
56
48 <div class="field">
57 <div class="field">
49 <div class="label">
58 <div class="label">
50 <label for="name">${_('First Name')}:</label>
59 <label for="name">${_('First Name')}:</label>
@@ -68,7 +68,16 b''
68 ${h.password('new_password',class_='medium',autocomplete="off")}
68 ${h.password('new_password',class_='medium',autocomplete="off")}
69 </div>
69 </div>
70 </div>
70 </div>
71
71
72 <div class="field">
73 <div class="label">
74 <label for="password_confirmation">${_('New password confirmation')}:</label>
75 </div>
76 <div class="input">
77 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
78 </div>
79 </div>
80
72 <div class="field">
81 <div class="field">
73 <div class="label">
82 <div class="label">
74 <label for="name">${_('First Name')}:</label>
83 <label for="name">${_('First Name')}:</label>
@@ -132,7 +141,7 b''
132 <div class="fields">
141 <div class="fields">
133 <div class="field">
142 <div class="field">
134 <div class="label label-checkbox">
143 <div class="label label-checkbox">
135 <label for="">${_('Create repositories')}:</label>
144 <label for="create_repo_perm">${_('Create repositories')}:</label>
136 </div>
145 </div>
137 <div class="checkboxes">
146 <div class="checkboxes">
138 ${h.checkbox('create_repo_perm',value=True)}
147 ${h.checkbox('create_repo_perm',value=True)}
@@ -57,7 +57,16 b''
57 ${h.password('new_password',class_="medium",autocomplete="off")}
57 ${h.password('new_password',class_="medium",autocomplete="off")}
58 </div>
58 </div>
59 </div>
59 </div>
60
60
61 <div class="field">
62 <div class="label">
63 <label for="password_confirmation">${_('New password confirmation')}:</label>
64 </div>
65 <div class="input">
66 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
67 </div>
68 </div>
69
61 <div class="field">
70 <div class="field">
62 <div class="label">
71 <div class="label">
63 <label for="name">${_('First Name')}:</label>
72 <label for="name">${_('First Name')}:</label>
@@ -154,10 +163,12 b''
154 </tr>
163 </tr>
155 %endfor
164 %endfor
156 %else:
165 %else:
166 <div style="padding:5px 0px 10px 0px;">
157 ${_('No repositories yet')}
167 ${_('No repositories yet')}
158 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
168 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
159 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'))}
169 ${h.link_to(_('create one now'),h.url('admin_settings_create_repository'),class_="ui-button-small")}
160 %endif
170 %endif
171 </div>
161 %endif
172 %endif
162 </tbody>
173 </tbody>
163 </table>
174 </table>
@@ -253,7 +253,7 b''
253 <div class="fields">
253 <div class="fields">
254 <div class="field">
254 <div class="field">
255 <div class="label label-checkbox">
255 <div class="label label-checkbox">
256 <label for="">${_('Create repositories')}:</label>
256 <label for="create_repo_perm">${_('Create repositories')}:</label>
257 </div>
257 </div>
258 <div class="checkboxes">
258 <div class="checkboxes">
259 ${h.checkbox('create_repo_perm',value=True)}
259 ${h.checkbox('create_repo_perm',value=True)}
@@ -34,7 +34,14 b''
34 ${h.text('repo_name',class_="small")}
34 ${h.text('repo_name',class_="small")}
35 </div>
35 </div>
36 </div>
36 </div>
37
37 <div class="field">
38 <div class="label">
39 <label for="repo_group">${_('Repository group')}:</label>
40 </div>
41 <div class="input">
42 ${h.select('repo_group','',c.repo_groups,class_="medium")}
43 </div>
44 </div>
38 <div class="field">
45 <div class="field">
39 <div class="label label-textarea">
46 <div class="label label-textarea">
40 <label for="description">${_('Description')}:</label>
47 <label for="description">${_('Description')}:</label>
@@ -77,8 +77,6 b' class TestController(TestCase):'
77 self.assertEqual(response.session['rhodecode_user'].username, username)
77 self.assertEqual(response.session['rhodecode_user'].username, username)
78 return response.follow()
78 return response.follow()
79
79
80
81
82 def checkSessionFlash(self, response, msg):
80 def checkSessionFlash(self, response, msg):
83 self.assertTrue('flash' in response.session)
81 self.assertTrue('flash' in response.session)
84 self.assertTrue(msg in response.session['flash'][0][1])
82 self.assertTrue(msg in response.session['flash'][0][1])
@@ -137,6 +137,7 b' class TestAdminSettingsController(TestCo'
137 params=dict(_method='put',
137 params=dict(_method='put',
138 username='test_admin',
138 username='test_admin',
139 new_password=new_password,
139 new_password=new_password,
140 password_confirmation = new_password,
140 password='',
141 password='',
141 name=new_name,
142 name=new_name,
142 lastname=new_lastname,
143 lastname=new_lastname,
@@ -160,6 +161,7 b' class TestAdminSettingsController(TestCo'
160 _method='put',
161 _method='put',
161 username='test_admin',
162 username='test_admin',
162 new_password=old_password,
163 new_password=old_password,
164 password_confirmation = old_password,
163 password='',
165 password='',
164 name=old_name,
166 name=old_name,
165 lastname=old_lastname,
167 lastname=old_lastname,
@@ -186,6 +188,7 b' class TestAdminSettingsController(TestCo'
186 _method='put',
188 _method='put',
187 username='test_admin',
189 username='test_admin',
188 new_password='test12',
190 new_password='test12',
191 password_confirmation = 'test122',
189 name='NewName',
192 name='NewName',
190 lastname='NewLastname',
193 lastname='NewLastname',
191 email=new_email,))
194 email=new_email,))
@@ -201,6 +204,7 b' class TestAdminSettingsController(TestCo'
201 _method='put',
204 _method='put',
202 username='test_admin',
205 username='test_admin',
203 new_password='test12',
206 new_password='test12',
207 password_confirmation = 'test122',
204 name='NewName',
208 name='NewName',
205 lastname='NewLastname',
209 lastname='NewLastname',
206 email=new_email,))
210 email=new_email,))
@@ -16,12 +16,14 b' class TestAdminUsersController(TestContr'
16 self.log_user()
16 self.log_user()
17 username = 'newtestuser'
17 username = 'newtestuser'
18 password = 'test12'
18 password = 'test12'
19 password_confirmation = password
19 name = 'name'
20 name = 'name'
20 lastname = 'lastname'
21 lastname = 'lastname'
21 email = 'mail@mail.com'
22 email = 'mail@mail.com'
22
23
23 response = self.app.post(url('users'), {'username':username,
24 response = self.app.post(url('users'), {'username':username,
24 'password':password,
25 'password':password,
26 'password_confirmation':password_confirmation,
25 'name':name,
27 'name':name,
26 'active':True,
28 'active':True,
27 'lastname':lastname,
29 'lastname':lastname,
@@ -90,6 +92,7 b' class TestAdminUsersController(TestContr'
90
92
91 response = self.app.post(url('users'), {'username':username,
93 response = self.app.post(url('users'), {'username':username,
92 'password':password,
94 'password':password,
95 'password_confirmation':password,
93 'name':name,
96 'name':name,
94 'active':True,
97 'active':True,
95 'lastname':lastname,
98 'lastname':lastname,
@@ -48,7 +48,8 b' from rhodecode.tests import TESTS_TMP_PA'
48 from rhodecode.config.environment import load_environment
48 from rhodecode.config.environment import load_environment
49
49
50 rel_path = dn(dn(dn(os.path.abspath(__file__))))
50 rel_path = dn(dn(dn(os.path.abspath(__file__))))
51 conf = appconfig('config:development.ini', relative_to=rel_path)
51
52 conf = appconfig('config:%s' % sys.argv[1], relative_to=rel_path)
52 load_environment(conf.global_conf, conf.local_conf)
53 load_environment(conf.global_conf, conf.local_conf)
53
54
54 add_cache(conf)
55 add_cache(conf)
@@ -56,10 +57,13 b' add_cache(conf)'
56 USER = 'test_admin'
57 USER = 'test_admin'
57 PASS = 'test12'
58 PASS = 'test12'
58 HOST = '127.0.0.1:5000'
59 HOST = '127.0.0.1:5000'
59 DEBUG = True if sys.argv[1:] else False
60 DEBUG = False
60 print 'DEBUG:', DEBUG
61 print 'DEBUG:', DEBUG
61 log = logging.getLogger(__name__)
62 log = logging.getLogger(__name__)
62
63
64 engine = engine_from_config(conf, 'sqlalchemy.db1.')
65 init_model(engine)
66 sa = meta.Session
63
67
64 class Command(object):
68 class Command(object):
65
69
@@ -96,22 +100,15 b' def test_wrapp(func):'
96 return res
100 return res
97 return __wrapp
101 return __wrapp
98
102
99 def get_session():
100 engine = engine_from_config(conf, 'sqlalchemy.db1.')
101 init_model(engine)
102 sa = meta.Session
103 return sa
104
105
103
106 def create_test_user(force=True):
104 def create_test_user(force=True):
107 print '\tcreating test user'
105 print '\tcreating test user'
108 sa = get_session()
109
106
110 user = sa.query(User).filter(User.username == USER).scalar()
107 user = User.get_by_username(USER)
111
108
112 if force and user is not None:
109 if force and user is not None:
113 print '\tremoving current user'
110 print '\tremoving current user'
114 for repo in sa.query(Repository).filter(Repository.user == user).all():
111 for repo in Repository.query().filter(Repository.user == user).all():
115 sa.delete(repo)
112 sa.delete(repo)
116 sa.delete(user)
113 sa.delete(user)
117 sa.commit()
114 sa.commit()
@@ -134,9 +131,8 b' def create_test_user(force=True):'
134
131
135 def create_test_repo(force=True):
132 def create_test_repo(force=True):
136 from rhodecode.model.repo import RepoModel
133 from rhodecode.model.repo import RepoModel
137 sa = get_session()
138
134
139 user = sa.query(User).filter(User.username == USER).scalar()
135 user = User.get_by_username(USER)
140 if user is None:
136 if user is None:
141 raise Exception('user not found')
137 raise Exception('user not found')
142
138
@@ -156,22 +152,17 b' def create_test_repo(force=True):'
156
152
157
153
158 def set_anonymous_access(enable=True):
154 def set_anonymous_access(enable=True):
159 sa = get_session()
155 user = User.get_by_username('default')
160 user = sa.query(User).filter(User.username == 'default').one()
161 sa.expire(user)
162 user.active = enable
156 user.active = enable
163 sa.add(user)
157 sa.add(user)
164 sa.commit()
158 sa.commit()
165 sa.remove()
166 import time;time.sleep(3)
167 print '\tanonymous access is now:', enable
159 print '\tanonymous access is now:', enable
168
160 if enable != User.get_by_username('default').active:
161 raise Exception('Cannot set anonymous access')
169
162
170 def get_anonymous_access():
163 def get_anonymous_access():
171 sa = get_session()
164 user = User.get_by_username('default')
172 obj1 = sa.query(User).filter(User.username == 'default').one()
165 return user.active
173 sa.expire(obj1)
174 return obj1.active
175
166
176
167
177 #==============================================================================
168 #==============================================================================
@@ -378,16 +369,15 b' def test_push_wrong_path():'
378
369
379 @test_wrapp
370 @test_wrapp
380 def get_logs():
371 def get_logs():
381 sa = get_session()
372 return UserLog.query().all()
382 return len(sa.query(UserLog).all())
383
373
384 @test_wrapp
374 @test_wrapp
385 def test_logs(initial):
375 def test_logs(initial):
386 sa = get_session()
376 logs = UserLog.query().all()
387 logs = sa.query(UserLog).all()
377 operations = 4
388 operations = 7
378 if len(initial) + operations != len(logs):
389 if initial + operations != len(logs):
379 raise Exception("missing number of logs initial:%s vs current:%s" % \
390 raise Exception("missing number of logs %s vs %s" % (initial, len(logs)))
380 (len(initial), len(logs)))
391
381
392
382
393 if __name__ == '__main__':
383 if __name__ == '__main__':
@@ -395,18 +385,17 b" if __name__ == '__main__':"
395 create_test_repo()
385 create_test_repo()
396
386
397 initial_logs = get_logs()
387 initial_logs = get_logs()
388 print 'initial activity logs: %s' % len(initial_logs)
398
389
399 # test_push_modify_file()
390 #test_push_modify_file()
400 test_clone_with_credentials()
391 test_clone_with_credentials()
401 test_clone_wrong_credentials()
392 test_clone_wrong_credentials()
402
393
403
404 test_push_new_file(commits=2, with_clone=True)
394 test_push_new_file(commits=2, with_clone=True)
405
395
406 test_clone_anonymous()
396 test_clone_anonymous()
407 test_push_wrong_path()
397 test_push_wrong_path()
408
398
409
410 test_push_wrong_credentials()
399 test_push_wrong_credentials()
411
400
412 test_logs(initial_logs)
401 test_logs(initial_logs)
General Comments 0
You need to be logged in to leave comments. Login now