##// END OF EJS Templates
api: add consistent permissions_summary data for both user and user_groups that expose...
marcink -
r2437:31460ef8 default
parent child Browse files
Show More
@@ -1,560 +1,562 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from rhodecode.api import (
23 from rhodecode.api import (
24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
25 from rhodecode.api.utils import (
25 from rhodecode.api.utils import (
26 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
26 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
27 from rhodecode.lib import audit_logger
27 from rhodecode.lib import audit_logger
28 from rhodecode.lib.auth import AuthUser, PasswordGenerator
28 from rhodecode.lib.auth import AuthUser, PasswordGenerator
29 from rhodecode.lib.exceptions import DefaultUserException
29 from rhodecode.lib.exceptions import DefaultUserException
30 from rhodecode.lib.utils2 import safe_int, str2bool
30 from rhodecode.lib.utils2 import safe_int, str2bool
31 from rhodecode.model.db import Session, User, Repository
31 from rhodecode.model.db import Session, User, Repository
32 from rhodecode.model.user import UserModel
32 from rhodecode.model.user import UserModel
33 from rhodecode.model import validation_schema
33 from rhodecode.model import validation_schema
34 from rhodecode.model.validation_schema.schemas import user_schema
34 from rhodecode.model.validation_schema.schemas import user_schema
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 @jsonrpc_method()
39 @jsonrpc_method()
40 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
40 def get_user(request, apiuser, userid=Optional(OAttr('apiuser'))):
41 """
41 """
42 Returns the information associated with a username or userid.
42 Returns the information associated with a username or userid.
43
43
44 * If the ``userid`` is not set, this command returns the information
44 * If the ``userid`` is not set, this command returns the information
45 for the ``userid`` calling the method.
45 for the ``userid`` calling the method.
46
46
47 .. note::
47 .. note::
48
48
49 Normal users may only run this command against their ``userid``. For
49 Normal users may only run this command against their ``userid``. For
50 full privileges you must run this command using an |authtoken| with
50 full privileges you must run this command using an |authtoken| with
51 admin rights.
51 admin rights.
52
52
53 :param apiuser: This is filled automatically from the |authtoken|.
53 :param apiuser: This is filled automatically from the |authtoken|.
54 :type apiuser: AuthUser
54 :type apiuser: AuthUser
55 :param userid: Sets the userid for which data will be returned.
55 :param userid: Sets the userid for which data will be returned.
56 :type userid: Optional(str or int)
56 :type userid: Optional(str or int)
57
57
58 Example output:
58 Example output:
59
59
60 .. code-block:: bash
60 .. code-block:: bash
61
61
62 {
62 {
63 "error": null,
63 "error": null,
64 "id": <id>,
64 "id": <id>,
65 "result": {
65 "result": {
66 "active": true,
66 "active": true,
67 "admin": false,
67 "admin": false,
68 "api_keys": [ list of keys ],
68 "api_keys": [ list of keys ],
69 "auth_tokens": [ list of tokens with details ],
69 "auth_tokens": [ list of tokens with details ],
70 "email": "user@example.com",
70 "email": "user@example.com",
71 "emails": [
71 "emails": [
72 "user@example.com"
72 "user@example.com"
73 ],
73 ],
74 "extern_name": "rhodecode",
74 "extern_name": "rhodecode",
75 "extern_type": "rhodecode",
75 "extern_type": "rhodecode",
76 "firstname": "username",
76 "firstname": "username",
77 "ip_addresses": [],
77 "ip_addresses": [],
78 "language": null,
78 "language": null,
79 "last_login": "Timestamp",
79 "last_login": "Timestamp",
80 "last_activity": "Timestamp",
80 "last_activity": "Timestamp",
81 "lastname": "surnae",
81 "lastname": "surnae",
82 "permissions": {
82 "permissions": {
83 "global": [
83 "global": [
84 "hg.inherit_default_perms.true",
84 "hg.inherit_default_perms.true",
85 "usergroup.read",
85 "usergroup.read",
86 "hg.repogroup.create.false",
86 "hg.repogroup.create.false",
87 "hg.create.none",
87 "hg.create.none",
88 "hg.password_reset.enabled",
88 "hg.password_reset.enabled",
89 "hg.extern_activate.manual",
89 "hg.extern_activate.manual",
90 "hg.create.write_on_repogroup.false",
90 "hg.create.write_on_repogroup.false",
91 "hg.usergroup.create.false",
91 "hg.usergroup.create.false",
92 "group.none",
92 "group.none",
93 "repository.none",
93 "repository.none",
94 "hg.register.none",
94 "hg.register.none",
95 "hg.fork.repository"
95 "hg.fork.repository"
96 ],
96 ],
97 "repositories": { "username/example": "repository.write"},
97 "repositories": { "username/example": "repository.write"},
98 "repositories_groups": { "user-group/repo": "group.none" },
98 "repositories_groups": { "user-group/repo": "group.none" },
99 "user_groups": { "user_group_name": "usergroup.read" }
99 "user_groups": { "user_group_name": "usergroup.read" }
100 },
100 },
101 "user_id": 32,
101 "user_id": 32,
102 "username": "username"
102 "username": "username"
103 }
103 }
104 }
104 }
105 """
105 """
106
106
107 if not has_superadmin_permission(apiuser):
107 if not has_superadmin_permission(apiuser):
108 # make sure normal user does not pass someone else userid,
108 # make sure normal user does not pass someone else userid,
109 # he is not allowed to do that
109 # he is not allowed to do that
110 if not isinstance(userid, Optional) and userid != apiuser.user_id:
110 if not isinstance(userid, Optional) and userid != apiuser.user_id:
111 raise JSONRPCError('userid is not the same as your user')
111 raise JSONRPCError('userid is not the same as your user')
112
112
113 userid = Optional.extract(userid, evaluate_locals=locals())
113 userid = Optional.extract(userid, evaluate_locals=locals())
114 userid = getattr(userid, 'user_id', userid)
114 userid = getattr(userid, 'user_id', userid)
115
115
116 user = get_user_or_error(userid)
116 user = get_user_or_error(userid)
117 data = user.get_api_data(include_secrets=True)
117 data = user.get_api_data(include_secrets=True)
118 data['permissions'] = AuthUser(user_id=user.user_id).permissions
118 permissions = AuthUser(user_id=user.user_id).permissions
119 data['permissions'] = permissions # TODO(marcink): should be deprecated
120 data['permissions_summary'] = permissions
119 return data
121 return data
120
122
121
123
122 @jsonrpc_method()
124 @jsonrpc_method()
123 def get_users(request, apiuser):
125 def get_users(request, apiuser):
124 """
126 """
125 Lists all users in the |RCE| user database.
127 Lists all users in the |RCE| user database.
126
128
127 This command can only be run using an |authtoken| with admin rights to
129 This command can only be run using an |authtoken| with admin rights to
128 the specified repository.
130 the specified repository.
129
131
130 This command takes the following options:
132 This command takes the following options:
131
133
132 :param apiuser: This is filled automatically from the |authtoken|.
134 :param apiuser: This is filled automatically from the |authtoken|.
133 :type apiuser: AuthUser
135 :type apiuser: AuthUser
134
136
135 Example output:
137 Example output:
136
138
137 .. code-block:: bash
139 .. code-block:: bash
138
140
139 id : <id_given_in_input>
141 id : <id_given_in_input>
140 result: [<user_object>, ...]
142 result: [<user_object>, ...]
141 error: null
143 error: null
142 """
144 """
143
145
144 if not has_superadmin_permission(apiuser):
146 if not has_superadmin_permission(apiuser):
145 raise JSONRPCForbidden()
147 raise JSONRPCForbidden()
146
148
147 result = []
149 result = []
148 users_list = User.query().order_by(User.username) \
150 users_list = User.query().order_by(User.username) \
149 .filter(User.username != User.DEFAULT_USER) \
151 .filter(User.username != User.DEFAULT_USER) \
150 .all()
152 .all()
151 for user in users_list:
153 for user in users_list:
152 result.append(user.get_api_data(include_secrets=True))
154 result.append(user.get_api_data(include_secrets=True))
153 return result
155 return result
154
156
155
157
156 @jsonrpc_method()
158 @jsonrpc_method()
157 def create_user(request, apiuser, username, email, password=Optional(''),
159 def create_user(request, apiuser, username, email, password=Optional(''),
158 firstname=Optional(''), lastname=Optional(''),
160 firstname=Optional(''), lastname=Optional(''),
159 active=Optional(True), admin=Optional(False),
161 active=Optional(True), admin=Optional(False),
160 extern_name=Optional('rhodecode'),
162 extern_name=Optional('rhodecode'),
161 extern_type=Optional('rhodecode'),
163 extern_type=Optional('rhodecode'),
162 force_password_change=Optional(False),
164 force_password_change=Optional(False),
163 create_personal_repo_group=Optional(None)):
165 create_personal_repo_group=Optional(None)):
164 """
166 """
165 Creates a new user and returns the new user object.
167 Creates a new user and returns the new user object.
166
168
167 This command can only be run using an |authtoken| with admin rights to
169 This command can only be run using an |authtoken| with admin rights to
168 the specified repository.
170 the specified repository.
169
171
170 This command takes the following options:
172 This command takes the following options:
171
173
172 :param apiuser: This is filled automatically from the |authtoken|.
174 :param apiuser: This is filled automatically from the |authtoken|.
173 :type apiuser: AuthUser
175 :type apiuser: AuthUser
174 :param username: Set the new username.
176 :param username: Set the new username.
175 :type username: str or int
177 :type username: str or int
176 :param email: Set the user email address.
178 :param email: Set the user email address.
177 :type email: str
179 :type email: str
178 :param password: Set the new user password.
180 :param password: Set the new user password.
179 :type password: Optional(str)
181 :type password: Optional(str)
180 :param firstname: Set the new user firstname.
182 :param firstname: Set the new user firstname.
181 :type firstname: Optional(str)
183 :type firstname: Optional(str)
182 :param lastname: Set the new user surname.
184 :param lastname: Set the new user surname.
183 :type lastname: Optional(str)
185 :type lastname: Optional(str)
184 :param active: Set the user as active.
186 :param active: Set the user as active.
185 :type active: Optional(``True`` | ``False``)
187 :type active: Optional(``True`` | ``False``)
186 :param admin: Give the new user admin rights.
188 :param admin: Give the new user admin rights.
187 :type admin: Optional(``True`` | ``False``)
189 :type admin: Optional(``True`` | ``False``)
188 :param extern_name: Set the authentication plugin name.
190 :param extern_name: Set the authentication plugin name.
189 Using LDAP this is filled with LDAP UID.
191 Using LDAP this is filled with LDAP UID.
190 :type extern_name: Optional(str)
192 :type extern_name: Optional(str)
191 :param extern_type: Set the new user authentication plugin.
193 :param extern_type: Set the new user authentication plugin.
192 :type extern_type: Optional(str)
194 :type extern_type: Optional(str)
193 :param force_password_change: Force the new user to change password
195 :param force_password_change: Force the new user to change password
194 on next login.
196 on next login.
195 :type force_password_change: Optional(``True`` | ``False``)
197 :type force_password_change: Optional(``True`` | ``False``)
196 :param create_personal_repo_group: Create personal repo group for this user
198 :param create_personal_repo_group: Create personal repo group for this user
197 :type create_personal_repo_group: Optional(``True`` | ``False``)
199 :type create_personal_repo_group: Optional(``True`` | ``False``)
198
200
199 Example output:
201 Example output:
200
202
201 .. code-block:: bash
203 .. code-block:: bash
202
204
203 id : <id_given_in_input>
205 id : <id_given_in_input>
204 result: {
206 result: {
205 "msg" : "created new user `<username>`",
207 "msg" : "created new user `<username>`",
206 "user": <user_obj>
208 "user": <user_obj>
207 }
209 }
208 error: null
210 error: null
209
211
210 Example error output:
212 Example error output:
211
213
212 .. code-block:: bash
214 .. code-block:: bash
213
215
214 id : <id_given_in_input>
216 id : <id_given_in_input>
215 result : null
217 result : null
216 error : {
218 error : {
217 "user `<username>` already exist"
219 "user `<username>` already exist"
218 or
220 or
219 "email `<email>` already exist"
221 "email `<email>` already exist"
220 or
222 or
221 "failed to create user `<username>`"
223 "failed to create user `<username>`"
222 }
224 }
223
225
224 """
226 """
225 if not has_superadmin_permission(apiuser):
227 if not has_superadmin_permission(apiuser):
226 raise JSONRPCForbidden()
228 raise JSONRPCForbidden()
227
229
228 if UserModel().get_by_username(username):
230 if UserModel().get_by_username(username):
229 raise JSONRPCError("user `%s` already exist" % (username,))
231 raise JSONRPCError("user `%s` already exist" % (username,))
230
232
231 if UserModel().get_by_email(email, case_insensitive=True):
233 if UserModel().get_by_email(email, case_insensitive=True):
232 raise JSONRPCError("email `%s` already exist" % (email,))
234 raise JSONRPCError("email `%s` already exist" % (email,))
233
235
234 # generate random password if we actually given the
236 # generate random password if we actually given the
235 # extern_name and it's not rhodecode
237 # extern_name and it's not rhodecode
236 if (not isinstance(extern_name, Optional) and
238 if (not isinstance(extern_name, Optional) and
237 Optional.extract(extern_name) != 'rhodecode'):
239 Optional.extract(extern_name) != 'rhodecode'):
238 # generate temporary password if user is external
240 # generate temporary password if user is external
239 password = PasswordGenerator().gen_password(length=16)
241 password = PasswordGenerator().gen_password(length=16)
240 create_repo_group = Optional.extract(create_personal_repo_group)
242 create_repo_group = Optional.extract(create_personal_repo_group)
241 if isinstance(create_repo_group, basestring):
243 if isinstance(create_repo_group, basestring):
242 create_repo_group = str2bool(create_repo_group)
244 create_repo_group = str2bool(create_repo_group)
243
245
244 username = Optional.extract(username)
246 username = Optional.extract(username)
245 password = Optional.extract(password)
247 password = Optional.extract(password)
246 email = Optional.extract(email)
248 email = Optional.extract(email)
247 first_name = Optional.extract(firstname)
249 first_name = Optional.extract(firstname)
248 last_name = Optional.extract(lastname)
250 last_name = Optional.extract(lastname)
249 active = Optional.extract(active)
251 active = Optional.extract(active)
250 admin = Optional.extract(admin)
252 admin = Optional.extract(admin)
251 extern_type = Optional.extract(extern_type)
253 extern_type = Optional.extract(extern_type)
252 extern_name = Optional.extract(extern_name)
254 extern_name = Optional.extract(extern_name)
253
255
254 schema = user_schema.UserSchema().bind(
256 schema = user_schema.UserSchema().bind(
255 # user caller
257 # user caller
256 user=apiuser)
258 user=apiuser)
257 try:
259 try:
258 schema_data = schema.deserialize(dict(
260 schema_data = schema.deserialize(dict(
259 username=username,
261 username=username,
260 email=email,
262 email=email,
261 password=password,
263 password=password,
262 first_name=first_name,
264 first_name=first_name,
263 last_name=last_name,
265 last_name=last_name,
264 active=active,
266 active=active,
265 admin=admin,
267 admin=admin,
266 extern_type=extern_type,
268 extern_type=extern_type,
267 extern_name=extern_name,
269 extern_name=extern_name,
268 ))
270 ))
269 except validation_schema.Invalid as err:
271 except validation_schema.Invalid as err:
270 raise JSONRPCValidationError(colander_exc=err)
272 raise JSONRPCValidationError(colander_exc=err)
271
273
272 try:
274 try:
273 user = UserModel().create_or_update(
275 user = UserModel().create_or_update(
274 username=schema_data['username'],
276 username=schema_data['username'],
275 password=schema_data['password'],
277 password=schema_data['password'],
276 email=schema_data['email'],
278 email=schema_data['email'],
277 firstname=schema_data['first_name'],
279 firstname=schema_data['first_name'],
278 lastname=schema_data['last_name'],
280 lastname=schema_data['last_name'],
279 active=schema_data['active'],
281 active=schema_data['active'],
280 admin=schema_data['admin'],
282 admin=schema_data['admin'],
281 extern_type=schema_data['extern_type'],
283 extern_type=schema_data['extern_type'],
282 extern_name=schema_data['extern_name'],
284 extern_name=schema_data['extern_name'],
283 force_password_change=Optional.extract(force_password_change),
285 force_password_change=Optional.extract(force_password_change),
284 create_repo_group=create_repo_group
286 create_repo_group=create_repo_group
285 )
287 )
286 Session().flush()
288 Session().flush()
287 creation_data = user.get_api_data()
289 creation_data = user.get_api_data()
288 audit_logger.store_api(
290 audit_logger.store_api(
289 'user.create', action_data={'data': creation_data},
291 'user.create', action_data={'data': creation_data},
290 user=apiuser)
292 user=apiuser)
291
293
292 Session().commit()
294 Session().commit()
293 return {
295 return {
294 'msg': 'created new user `%s`' % username,
296 'msg': 'created new user `%s`' % username,
295 'user': user.get_api_data(include_secrets=True)
297 'user': user.get_api_data(include_secrets=True)
296 }
298 }
297 except Exception:
299 except Exception:
298 log.exception('Error occurred during creation of user')
300 log.exception('Error occurred during creation of user')
299 raise JSONRPCError('failed to create user `%s`' % (username,))
301 raise JSONRPCError('failed to create user `%s`' % (username,))
300
302
301
303
302 @jsonrpc_method()
304 @jsonrpc_method()
303 def update_user(request, apiuser, userid, username=Optional(None),
305 def update_user(request, apiuser, userid, username=Optional(None),
304 email=Optional(None), password=Optional(None),
306 email=Optional(None), password=Optional(None),
305 firstname=Optional(None), lastname=Optional(None),
307 firstname=Optional(None), lastname=Optional(None),
306 active=Optional(None), admin=Optional(None),
308 active=Optional(None), admin=Optional(None),
307 extern_type=Optional(None), extern_name=Optional(None), ):
309 extern_type=Optional(None), extern_name=Optional(None), ):
308 """
310 """
309 Updates the details for the specified user, if that user exists.
311 Updates the details for the specified user, if that user exists.
310
312
311 This command can only be run using an |authtoken| with admin rights to
313 This command can only be run using an |authtoken| with admin rights to
312 the specified repository.
314 the specified repository.
313
315
314 This command takes the following options:
316 This command takes the following options:
315
317
316 :param apiuser: This is filled automatically from |authtoken|.
318 :param apiuser: This is filled automatically from |authtoken|.
317 :type apiuser: AuthUser
319 :type apiuser: AuthUser
318 :param userid: Set the ``userid`` to update.
320 :param userid: Set the ``userid`` to update.
319 :type userid: str or int
321 :type userid: str or int
320 :param username: Set the new username.
322 :param username: Set the new username.
321 :type username: str or int
323 :type username: str or int
322 :param email: Set the new email.
324 :param email: Set the new email.
323 :type email: str
325 :type email: str
324 :param password: Set the new password.
326 :param password: Set the new password.
325 :type password: Optional(str)
327 :type password: Optional(str)
326 :param firstname: Set the new first name.
328 :param firstname: Set the new first name.
327 :type firstname: Optional(str)
329 :type firstname: Optional(str)
328 :param lastname: Set the new surname.
330 :param lastname: Set the new surname.
329 :type lastname: Optional(str)
331 :type lastname: Optional(str)
330 :param active: Set the new user as active.
332 :param active: Set the new user as active.
331 :type active: Optional(``True`` | ``False``)
333 :type active: Optional(``True`` | ``False``)
332 :param admin: Give the user admin rights.
334 :param admin: Give the user admin rights.
333 :type admin: Optional(``True`` | ``False``)
335 :type admin: Optional(``True`` | ``False``)
334 :param extern_name: Set the authentication plugin user name.
336 :param extern_name: Set the authentication plugin user name.
335 Using LDAP this is filled with LDAP UID.
337 Using LDAP this is filled with LDAP UID.
336 :type extern_name: Optional(str)
338 :type extern_name: Optional(str)
337 :param extern_type: Set the authentication plugin type.
339 :param extern_type: Set the authentication plugin type.
338 :type extern_type: Optional(str)
340 :type extern_type: Optional(str)
339
341
340
342
341 Example output:
343 Example output:
342
344
343 .. code-block:: bash
345 .. code-block:: bash
344
346
345 id : <id_given_in_input>
347 id : <id_given_in_input>
346 result: {
348 result: {
347 "msg" : "updated user ID:<userid> <username>",
349 "msg" : "updated user ID:<userid> <username>",
348 "user": <user_object>,
350 "user": <user_object>,
349 }
351 }
350 error: null
352 error: null
351
353
352 Example error output:
354 Example error output:
353
355
354 .. code-block:: bash
356 .. code-block:: bash
355
357
356 id : <id_given_in_input>
358 id : <id_given_in_input>
357 result : null
359 result : null
358 error : {
360 error : {
359 "failed to update user `<username>`"
361 "failed to update user `<username>`"
360 }
362 }
361
363
362 """
364 """
363 if not has_superadmin_permission(apiuser):
365 if not has_superadmin_permission(apiuser):
364 raise JSONRPCForbidden()
366 raise JSONRPCForbidden()
365
367
366 user = get_user_or_error(userid)
368 user = get_user_or_error(userid)
367 old_data = user.get_api_data()
369 old_data = user.get_api_data()
368 # only non optional arguments will be stored in updates
370 # only non optional arguments will be stored in updates
369 updates = {}
371 updates = {}
370
372
371 try:
373 try:
372
374
373 store_update(updates, username, 'username')
375 store_update(updates, username, 'username')
374 store_update(updates, password, 'password')
376 store_update(updates, password, 'password')
375 store_update(updates, email, 'email')
377 store_update(updates, email, 'email')
376 store_update(updates, firstname, 'name')
378 store_update(updates, firstname, 'name')
377 store_update(updates, lastname, 'lastname')
379 store_update(updates, lastname, 'lastname')
378 store_update(updates, active, 'active')
380 store_update(updates, active, 'active')
379 store_update(updates, admin, 'admin')
381 store_update(updates, admin, 'admin')
380 store_update(updates, extern_name, 'extern_name')
382 store_update(updates, extern_name, 'extern_name')
381 store_update(updates, extern_type, 'extern_type')
383 store_update(updates, extern_type, 'extern_type')
382
384
383 user = UserModel().update_user(user, **updates)
385 user = UserModel().update_user(user, **updates)
384 audit_logger.store_api(
386 audit_logger.store_api(
385 'user.edit', action_data={'old_data': old_data},
387 'user.edit', action_data={'old_data': old_data},
386 user=apiuser)
388 user=apiuser)
387 Session().commit()
389 Session().commit()
388 return {
390 return {
389 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
391 'msg': 'updated user ID:%s %s' % (user.user_id, user.username),
390 'user': user.get_api_data(include_secrets=True)
392 'user': user.get_api_data(include_secrets=True)
391 }
393 }
392 except DefaultUserException:
394 except DefaultUserException:
393 log.exception("Default user edit exception")
395 log.exception("Default user edit exception")
394 raise JSONRPCError('editing default user is forbidden')
396 raise JSONRPCError('editing default user is forbidden')
395 except Exception:
397 except Exception:
396 log.exception("Error occurred during update of user")
398 log.exception("Error occurred during update of user")
397 raise JSONRPCError('failed to update user `%s`' % (userid,))
399 raise JSONRPCError('failed to update user `%s`' % (userid,))
398
400
399
401
400 @jsonrpc_method()
402 @jsonrpc_method()
401 def delete_user(request, apiuser, userid):
403 def delete_user(request, apiuser, userid):
402 """
404 """
403 Deletes the specified user from the |RCE| user database.
405 Deletes the specified user from the |RCE| user database.
404
406
405 This command can only be run using an |authtoken| with admin rights to
407 This command can only be run using an |authtoken| with admin rights to
406 the specified repository.
408 the specified repository.
407
409
408 .. important::
410 .. important::
409
411
410 Ensure all open pull requests and open code review
412 Ensure all open pull requests and open code review
411 requests to this user are close.
413 requests to this user are close.
412
414
413 Also ensure all repositories, or repository groups owned by this
415 Also ensure all repositories, or repository groups owned by this
414 user are reassigned before deletion.
416 user are reassigned before deletion.
415
417
416 This command takes the following options:
418 This command takes the following options:
417
419
418 :param apiuser: This is filled automatically from the |authtoken|.
420 :param apiuser: This is filled automatically from the |authtoken|.
419 :type apiuser: AuthUser
421 :type apiuser: AuthUser
420 :param userid: Set the user to delete.
422 :param userid: Set the user to delete.
421 :type userid: str or int
423 :type userid: str or int
422
424
423 Example output:
425 Example output:
424
426
425 .. code-block:: bash
427 .. code-block:: bash
426
428
427 id : <id_given_in_input>
429 id : <id_given_in_input>
428 result: {
430 result: {
429 "msg" : "deleted user ID:<userid> <username>",
431 "msg" : "deleted user ID:<userid> <username>",
430 "user": null
432 "user": null
431 }
433 }
432 error: null
434 error: null
433
435
434 Example error output:
436 Example error output:
435
437
436 .. code-block:: bash
438 .. code-block:: bash
437
439
438 id : <id_given_in_input>
440 id : <id_given_in_input>
439 result : null
441 result : null
440 error : {
442 error : {
441 "failed to delete user ID:<userid> <username>"
443 "failed to delete user ID:<userid> <username>"
442 }
444 }
443
445
444 """
446 """
445 if not has_superadmin_permission(apiuser):
447 if not has_superadmin_permission(apiuser):
446 raise JSONRPCForbidden()
448 raise JSONRPCForbidden()
447
449
448 user = get_user_or_error(userid)
450 user = get_user_or_error(userid)
449 old_data = user.get_api_data()
451 old_data = user.get_api_data()
450 try:
452 try:
451 UserModel().delete(userid)
453 UserModel().delete(userid)
452 audit_logger.store_api(
454 audit_logger.store_api(
453 'user.delete', action_data={'old_data': old_data},
455 'user.delete', action_data={'old_data': old_data},
454 user=apiuser)
456 user=apiuser)
455
457
456 Session().commit()
458 Session().commit()
457 return {
459 return {
458 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
460 'msg': 'deleted user ID:%s %s' % (user.user_id, user.username),
459 'user': None
461 'user': None
460 }
462 }
461 except Exception:
463 except Exception:
462 log.exception("Error occurred during deleting of user")
464 log.exception("Error occurred during deleting of user")
463 raise JSONRPCError(
465 raise JSONRPCError(
464 'failed to delete user ID:%s %s' % (user.user_id, user.username))
466 'failed to delete user ID:%s %s' % (user.user_id, user.username))
465
467
466
468
467 @jsonrpc_method()
469 @jsonrpc_method()
468 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
470 def get_user_locks(request, apiuser, userid=Optional(OAttr('apiuser'))):
469 """
471 """
470 Displays all repositories locked by the specified user.
472 Displays all repositories locked by the specified user.
471
473
472 * If this command is run by a non-admin user, it returns
474 * If this command is run by a non-admin user, it returns
473 a list of |repos| locked by that user.
475 a list of |repos| locked by that user.
474
476
475 This command takes the following options:
477 This command takes the following options:
476
478
477 :param apiuser: This is filled automatically from the |authtoken|.
479 :param apiuser: This is filled automatically from the |authtoken|.
478 :type apiuser: AuthUser
480 :type apiuser: AuthUser
479 :param userid: Sets the userid whose list of locked |repos| will be
481 :param userid: Sets the userid whose list of locked |repos| will be
480 displayed.
482 displayed.
481 :type userid: Optional(str or int)
483 :type userid: Optional(str or int)
482
484
483 Example output:
485 Example output:
484
486
485 .. code-block:: bash
487 .. code-block:: bash
486
488
487 id : <id_given_in_input>
489 id : <id_given_in_input>
488 result : {
490 result : {
489 [repo_object, repo_object,...]
491 [repo_object, repo_object,...]
490 }
492 }
491 error : null
493 error : null
492 """
494 """
493
495
494 include_secrets = False
496 include_secrets = False
495 if not has_superadmin_permission(apiuser):
497 if not has_superadmin_permission(apiuser):
496 # make sure normal user does not pass someone else userid,
498 # make sure normal user does not pass someone else userid,
497 # he is not allowed to do that
499 # he is not allowed to do that
498 if not isinstance(userid, Optional) and userid != apiuser.user_id:
500 if not isinstance(userid, Optional) and userid != apiuser.user_id:
499 raise JSONRPCError('userid is not the same as your user')
501 raise JSONRPCError('userid is not the same as your user')
500 else:
502 else:
501 include_secrets = True
503 include_secrets = True
502
504
503 userid = Optional.extract(userid, evaluate_locals=locals())
505 userid = Optional.extract(userid, evaluate_locals=locals())
504 userid = getattr(userid, 'user_id', userid)
506 userid = getattr(userid, 'user_id', userid)
505 user = get_user_or_error(userid)
507 user = get_user_or_error(userid)
506
508
507 ret = []
509 ret = []
508
510
509 # show all locks
511 # show all locks
510 for r in Repository.getAll():
512 for r in Repository.getAll():
511 _user_id, _time, _reason = r.locked
513 _user_id, _time, _reason = r.locked
512 if _user_id and _time:
514 if _user_id and _time:
513 _api_data = r.get_api_data(include_secrets=include_secrets)
515 _api_data = r.get_api_data(include_secrets=include_secrets)
514 # if we use user filter just show the locks for this user
516 # if we use user filter just show the locks for this user
515 if safe_int(_user_id) == user.user_id:
517 if safe_int(_user_id) == user.user_id:
516 ret.append(_api_data)
518 ret.append(_api_data)
517
519
518 return ret
520 return ret
519
521
520
522
521 @jsonrpc_method()
523 @jsonrpc_method()
522 def get_user_audit_logs(request, apiuser, userid=Optional(OAttr('apiuser'))):
524 def get_user_audit_logs(request, apiuser, userid=Optional(OAttr('apiuser'))):
523 """
525 """
524 Fetches all action logs made by the specified user.
526 Fetches all action logs made by the specified user.
525
527
526 This command takes the following options:
528 This command takes the following options:
527
529
528 :param apiuser: This is filled automatically from the |authtoken|.
530 :param apiuser: This is filled automatically from the |authtoken|.
529 :type apiuser: AuthUser
531 :type apiuser: AuthUser
530 :param userid: Sets the userid whose list of locked |repos| will be
532 :param userid: Sets the userid whose list of locked |repos| will be
531 displayed.
533 displayed.
532 :type userid: Optional(str or int)
534 :type userid: Optional(str or int)
533
535
534 Example output:
536 Example output:
535
537
536 .. code-block:: bash
538 .. code-block:: bash
537
539
538 id : <id_given_in_input>
540 id : <id_given_in_input>
539 result : {
541 result : {
540 [action, action,...]
542 [action, action,...]
541 }
543 }
542 error : null
544 error : null
543 """
545 """
544
546
545 if not has_superadmin_permission(apiuser):
547 if not has_superadmin_permission(apiuser):
546 # make sure normal user does not pass someone else userid,
548 # make sure normal user does not pass someone else userid,
547 # he is not allowed to do that
549 # he is not allowed to do that
548 if not isinstance(userid, Optional) and userid != apiuser.user_id:
550 if not isinstance(userid, Optional) and userid != apiuser.user_id:
549 raise JSONRPCError('userid is not the same as your user')
551 raise JSONRPCError('userid is not the same as your user')
550
552
551 userid = Optional.extract(userid, evaluate_locals=locals())
553 userid = Optional.extract(userid, evaluate_locals=locals())
552 userid = getattr(userid, 'user_id', userid)
554 userid = getattr(userid, 'user_id', userid)
553 user = get_user_or_error(userid)
555 user = get_user_or_error(userid)
554
556
555 ret = []
557 ret = []
556
558
557 # show all user actions
559 # show all user actions
558 for entry in UserModel().get_user_log(user, filter_term=None):
560 for entry in UserModel().get_user_log(user, filter_term=None):
559 ret.append(entry)
561 ret.append(entry)
560 return ret
562 return ret
@@ -1,822 +1,823 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from rhodecode.api import (
23 from rhodecode.api import (
24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
25 from rhodecode.api.utils import (
25 from rhodecode.api.utils import (
26 Optional, OAttr, store_update, has_superadmin_permission, get_origin,
26 Optional, OAttr, store_update, has_superadmin_permission, get_origin,
27 get_user_or_error, get_user_group_or_error, get_perm_or_error)
27 get_user_or_error, get_user_group_or_error, get_perm_or_error)
28 from rhodecode.lib import audit_logger
28 from rhodecode.lib import audit_logger
29 from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi
29 from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi
30 from rhodecode.lib.exceptions import UserGroupAssignedException
30 from rhodecode.lib.exceptions import UserGroupAssignedException
31 from rhodecode.model.db import Session
31 from rhodecode.model.db import Session
32 from rhodecode.model.scm import UserGroupList
32 from rhodecode.model.scm import UserGroupList
33 from rhodecode.model.user_group import UserGroupModel
33 from rhodecode.model.user_group import UserGroupModel
34 from rhodecode.model import validation_schema
34 from rhodecode.model import validation_schema
35 from rhodecode.model.validation_schema.schemas import user_group_schema
35 from rhodecode.model.validation_schema.schemas import user_group_schema
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 @jsonrpc_method()
40 @jsonrpc_method()
41 def get_user_group(request, apiuser, usergroupid):
41 def get_user_group(request, apiuser, usergroupid):
42 """
42 """
43 Returns the data of an existing user group.
43 Returns the data of an existing user group.
44
44
45 This command can only be run using an |authtoken| with admin rights to
45 This command can only be run using an |authtoken| with admin rights to
46 the specified repository.
46 the specified repository.
47
47
48 :param apiuser: This is filled automatically from the |authtoken|.
48 :param apiuser: This is filled automatically from the |authtoken|.
49 :type apiuser: AuthUser
49 :type apiuser: AuthUser
50 :param usergroupid: Set the user group from which to return data.
50 :param usergroupid: Set the user group from which to return data.
51 :type usergroupid: str or int
51 :type usergroupid: str or int
52
52
53 Example error output:
53 Example error output:
54
54
55 .. code-block:: bash
55 .. code-block:: bash
56
56
57 {
57 {
58 "error": null,
58 "error": null,
59 "id": <id>,
59 "id": <id>,
60 "result": {
60 "result": {
61 "active": true,
61 "active": true,
62 "group_description": "group description",
62 "group_description": "group description",
63 "group_name": "group name",
63 "group_name": "group name",
64 "members": [
64 "members": [
65 {
65 {
66 "name": "owner-name",
66 "name": "owner-name",
67 "origin": "owner",
67 "origin": "owner",
68 "permission": "usergroup.admin",
68 "permission": "usergroup.admin",
69 "type": "user"
69 "type": "user"
70 },
70 },
71 {
71 {
72 {
72 {
73 "name": "user name",
73 "name": "user name",
74 "origin": "permission",
74 "origin": "permission",
75 "permission": "usergroup.admin",
75 "permission": "usergroup.admin",
76 "type": "user"
76 "type": "user"
77 },
77 },
78 {
78 {
79 "name": "user group name",
79 "name": "user group name",
80 "origin": "permission",
80 "origin": "permission",
81 "permission": "usergroup.write",
81 "permission": "usergroup.write",
82 "type": "user_group"
82 "type": "user_group"
83 }
83 }
84 ],
84 ],
85 "owner": "owner name",
85 "owner": "owner name",
86 "users": [],
86 "users": [],
87 "users_group_id": 2
87 "users_group_id": 2
88 }
88 }
89 }
89 }
90
90
91 """
91 """
92
92
93 user_group = get_user_group_or_error(usergroupid)
93 user_group = get_user_group_or_error(usergroupid)
94 if not has_superadmin_permission(apiuser):
94 if not has_superadmin_permission(apiuser):
95 # check if we have at least read permission for this user group !
95 # check if we have at least read permission for this user group !
96 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
96 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
97 if not HasUserGroupPermissionAnyApi(*_perms)(
97 if not HasUserGroupPermissionAnyApi(*_perms)(
98 user=apiuser, user_group_name=user_group.users_group_name):
98 user=apiuser, user_group_name=user_group.users_group_name):
99 raise JSONRPCError('user group `%s` does not exist' % (
99 raise JSONRPCError('user group `%s` does not exist' % (
100 usergroupid,))
100 usergroupid,))
101
101
102 permissions = []
102 permissions = []
103 for _user in user_group.permissions():
103 for _user in user_group.permissions():
104 user_data = {
104 user_data = {
105 'name': _user.username,
105 'name': _user.username,
106 'permission': _user.permission,
106 'permission': _user.permission,
107 'origin': get_origin(_user),
107 'origin': get_origin(_user),
108 'type': "user",
108 'type': "user",
109 }
109 }
110 permissions.append(user_data)
110 permissions.append(user_data)
111
111
112 for _user_group in user_group.permission_user_groups():
112 for _user_group in user_group.permission_user_groups():
113 user_group_data = {
113 user_group_data = {
114 'name': _user_group.users_group_name,
114 'name': _user_group.users_group_name,
115 'permission': _user_group.permission,
115 'permission': _user_group.permission,
116 'origin': get_origin(_user_group),
116 'origin': get_origin(_user_group),
117 'type': "user_group",
117 'type': "user_group",
118 }
118 }
119 permissions.append(user_group_data)
119 permissions.append(user_group_data)
120
120
121 data = user_group.get_api_data()
121 data = user_group.get_api_data()
122 data["permissions"] = permissions
122 data["permissions"] = permissions
123
123 data["Permissions_summary"] = UserGroupModel().get_perms_summary(
124 user_group.users_group_id)
124 return data
125 return data
125
126
126
127
127 @jsonrpc_method()
128 @jsonrpc_method()
128 def get_user_groups(request, apiuser):
129 def get_user_groups(request, apiuser):
129 """
130 """
130 Lists all the existing user groups within RhodeCode.
131 Lists all the existing user groups within RhodeCode.
131
132
132 This command can only be run using an |authtoken| with admin rights to
133 This command can only be run using an |authtoken| with admin rights to
133 the specified repository.
134 the specified repository.
134
135
135 This command takes the following options:
136 This command takes the following options:
136
137
137 :param apiuser: This is filled automatically from the |authtoken|.
138 :param apiuser: This is filled automatically from the |authtoken|.
138 :type apiuser: AuthUser
139 :type apiuser: AuthUser
139
140
140 Example error output:
141 Example error output:
141
142
142 .. code-block:: bash
143 .. code-block:: bash
143
144
144 id : <id_given_in_input>
145 id : <id_given_in_input>
145 result : [<user_group_obj>,...]
146 result : [<user_group_obj>,...]
146 error : null
147 error : null
147 """
148 """
148
149
149 include_secrets = has_superadmin_permission(apiuser)
150 include_secrets = has_superadmin_permission(apiuser)
150
151
151 result = []
152 result = []
152 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
153 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
153 extras = {'user': apiuser}
154 extras = {'user': apiuser}
154 for user_group in UserGroupList(UserGroupModel().get_all(),
155 for user_group in UserGroupList(UserGroupModel().get_all(),
155 perm_set=_perms, extra_kwargs=extras):
156 perm_set=_perms, extra_kwargs=extras):
156 result.append(
157 result.append(
157 user_group.get_api_data(include_secrets=include_secrets))
158 user_group.get_api_data(include_secrets=include_secrets))
158 return result
159 return result
159
160
160
161
161 @jsonrpc_method()
162 @jsonrpc_method()
162 def create_user_group(
163 def create_user_group(
163 request, apiuser, group_name, description=Optional(''),
164 request, apiuser, group_name, description=Optional(''),
164 owner=Optional(OAttr('apiuser')), active=Optional(True)):
165 owner=Optional(OAttr('apiuser')), active=Optional(True)):
165 """
166 """
166 Creates a new user group.
167 Creates a new user group.
167
168
168 This command can only be run using an |authtoken| with admin rights to
169 This command can only be run using an |authtoken| with admin rights to
169 the specified repository.
170 the specified repository.
170
171
171 This command takes the following options:
172 This command takes the following options:
172
173
173 :param apiuser: This is filled automatically from the |authtoken|.
174 :param apiuser: This is filled automatically from the |authtoken|.
174 :type apiuser: AuthUser
175 :type apiuser: AuthUser
175 :param group_name: Set the name of the new user group.
176 :param group_name: Set the name of the new user group.
176 :type group_name: str
177 :type group_name: str
177 :param description: Give a description of the new user group.
178 :param description: Give a description of the new user group.
178 :type description: str
179 :type description: str
179 :param owner: Set the owner of the new user group.
180 :param owner: Set the owner of the new user group.
180 If not set, the owner is the |authtoken| user.
181 If not set, the owner is the |authtoken| user.
181 :type owner: Optional(str or int)
182 :type owner: Optional(str or int)
182 :param active: Set this group as active.
183 :param active: Set this group as active.
183 :type active: Optional(``True`` | ``False``)
184 :type active: Optional(``True`` | ``False``)
184
185
185 Example output:
186 Example output:
186
187
187 .. code-block:: bash
188 .. code-block:: bash
188
189
189 id : <id_given_in_input>
190 id : <id_given_in_input>
190 result: {
191 result: {
191 "msg": "created new user group `<groupname>`",
192 "msg": "created new user group `<groupname>`",
192 "user_group": <user_group_object>
193 "user_group": <user_group_object>
193 }
194 }
194 error: null
195 error: null
195
196
196 Example error output:
197 Example error output:
197
198
198 .. code-block:: bash
199 .. code-block:: bash
199
200
200 id : <id_given_in_input>
201 id : <id_given_in_input>
201 result : null
202 result : null
202 error : {
203 error : {
203 "user group `<group name>` already exist"
204 "user group `<group name>` already exist"
204 or
205 or
205 "failed to create group `<group name>`"
206 "failed to create group `<group name>`"
206 }
207 }
207
208
208 """
209 """
209
210
210 if not has_superadmin_permission(apiuser):
211 if not has_superadmin_permission(apiuser):
211 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
212 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
212 raise JSONRPCForbidden()
213 raise JSONRPCForbidden()
213
214
214 if UserGroupModel().get_by_name(group_name):
215 if UserGroupModel().get_by_name(group_name):
215 raise JSONRPCError("user group `%s` already exist" % (group_name,))
216 raise JSONRPCError("user group `%s` already exist" % (group_name,))
216
217
217 if isinstance(owner, Optional):
218 if isinstance(owner, Optional):
218 owner = apiuser.user_id
219 owner = apiuser.user_id
219
220
220 owner = get_user_or_error(owner)
221 owner = get_user_or_error(owner)
221 active = Optional.extract(active)
222 active = Optional.extract(active)
222 description = Optional.extract(description)
223 description = Optional.extract(description)
223
224
224 schema = user_group_schema.UserGroupSchema().bind(
225 schema = user_group_schema.UserGroupSchema().bind(
225 # user caller
226 # user caller
226 user=apiuser)
227 user=apiuser)
227 try:
228 try:
228 schema_data = schema.deserialize(dict(
229 schema_data = schema.deserialize(dict(
229 user_group_name=group_name,
230 user_group_name=group_name,
230 user_group_description=description,
231 user_group_description=description,
231 user_group_owner=owner.username,
232 user_group_owner=owner.username,
232 user_group_active=active,
233 user_group_active=active,
233 ))
234 ))
234 except validation_schema.Invalid as err:
235 except validation_schema.Invalid as err:
235 raise JSONRPCValidationError(colander_exc=err)
236 raise JSONRPCValidationError(colander_exc=err)
236
237
237 try:
238 try:
238 user_group = UserGroupModel().create(
239 user_group = UserGroupModel().create(
239 name=schema_data['user_group_name'],
240 name=schema_data['user_group_name'],
240 description=schema_data['user_group_description'],
241 description=schema_data['user_group_description'],
241 owner=owner,
242 owner=owner,
242 active=schema_data['user_group_active'])
243 active=schema_data['user_group_active'])
243 Session().flush()
244 Session().flush()
244 creation_data = user_group.get_api_data()
245 creation_data = user_group.get_api_data()
245 audit_logger.store_api(
246 audit_logger.store_api(
246 'user_group.create', action_data={'data': creation_data},
247 'user_group.create', action_data={'data': creation_data},
247 user=apiuser)
248 user=apiuser)
248 Session().commit()
249 Session().commit()
249 return {
250 return {
250 'msg': 'created new user group `%s`' % group_name,
251 'msg': 'created new user group `%s`' % group_name,
251 'user_group': creation_data
252 'user_group': creation_data
252 }
253 }
253 except Exception:
254 except Exception:
254 log.exception("Error occurred during creation of user group")
255 log.exception("Error occurred during creation of user group")
255 raise JSONRPCError('failed to create group `%s`' % (group_name,))
256 raise JSONRPCError('failed to create group `%s`' % (group_name,))
256
257
257
258
258 @jsonrpc_method()
259 @jsonrpc_method()
259 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
260 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
260 description=Optional(''), owner=Optional(None),
261 description=Optional(''), owner=Optional(None),
261 active=Optional(True)):
262 active=Optional(True)):
262 """
263 """
263 Updates the specified `user group` with the details provided.
264 Updates the specified `user group` with the details provided.
264
265
265 This command can only be run using an |authtoken| with admin rights to
266 This command can only be run using an |authtoken| with admin rights to
266 the specified repository.
267 the specified repository.
267
268
268 :param apiuser: This is filled automatically from the |authtoken|.
269 :param apiuser: This is filled automatically from the |authtoken|.
269 :type apiuser: AuthUser
270 :type apiuser: AuthUser
270 :param usergroupid: Set the id of the `user group` to update.
271 :param usergroupid: Set the id of the `user group` to update.
271 :type usergroupid: str or int
272 :type usergroupid: str or int
272 :param group_name: Set the new name the `user group`
273 :param group_name: Set the new name the `user group`
273 :type group_name: str
274 :type group_name: str
274 :param description: Give a description for the `user group`
275 :param description: Give a description for the `user group`
275 :type description: str
276 :type description: str
276 :param owner: Set the owner of the `user group`.
277 :param owner: Set the owner of the `user group`.
277 :type owner: Optional(str or int)
278 :type owner: Optional(str or int)
278 :param active: Set the group as active.
279 :param active: Set the group as active.
279 :type active: Optional(``True`` | ``False``)
280 :type active: Optional(``True`` | ``False``)
280
281
281 Example output:
282 Example output:
282
283
283 .. code-block:: bash
284 .. code-block:: bash
284
285
285 id : <id_given_in_input>
286 id : <id_given_in_input>
286 result : {
287 result : {
287 "msg": 'updated user group ID:<user group id> <user group name>',
288 "msg": 'updated user group ID:<user group id> <user group name>',
288 "user_group": <user_group_object>
289 "user_group": <user_group_object>
289 }
290 }
290 error : null
291 error : null
291
292
292 Example error output:
293 Example error output:
293
294
294 .. code-block:: bash
295 .. code-block:: bash
295
296
296 id : <id_given_in_input>
297 id : <id_given_in_input>
297 result : null
298 result : null
298 error : {
299 error : {
299 "failed to update user group `<user group name>`"
300 "failed to update user group `<user group name>`"
300 }
301 }
301
302
302 """
303 """
303
304
304 user_group = get_user_group_or_error(usergroupid)
305 user_group = get_user_group_or_error(usergroupid)
305 include_secrets = False
306 include_secrets = False
306 if not has_superadmin_permission(apiuser):
307 if not has_superadmin_permission(apiuser):
307 # check if we have admin permission for this user group !
308 # check if we have admin permission for this user group !
308 _perms = ('usergroup.admin',)
309 _perms = ('usergroup.admin',)
309 if not HasUserGroupPermissionAnyApi(*_perms)(
310 if not HasUserGroupPermissionAnyApi(*_perms)(
310 user=apiuser, user_group_name=user_group.users_group_name):
311 user=apiuser, user_group_name=user_group.users_group_name):
311 raise JSONRPCError(
312 raise JSONRPCError(
312 'user group `%s` does not exist' % (usergroupid,))
313 'user group `%s` does not exist' % (usergroupid,))
313 else:
314 else:
314 include_secrets = True
315 include_secrets = True
315
316
316 if not isinstance(owner, Optional):
317 if not isinstance(owner, Optional):
317 owner = get_user_or_error(owner)
318 owner = get_user_or_error(owner)
318
319
319 old_data = user_group.get_api_data()
320 old_data = user_group.get_api_data()
320 updates = {}
321 updates = {}
321 store_update(updates, group_name, 'users_group_name')
322 store_update(updates, group_name, 'users_group_name')
322 store_update(updates, description, 'user_group_description')
323 store_update(updates, description, 'user_group_description')
323 store_update(updates, owner, 'user')
324 store_update(updates, owner, 'user')
324 store_update(updates, active, 'users_group_active')
325 store_update(updates, active, 'users_group_active')
325 try:
326 try:
326 UserGroupModel().update(user_group, updates)
327 UserGroupModel().update(user_group, updates)
327 audit_logger.store_api(
328 audit_logger.store_api(
328 'user_group.edit', action_data={'old_data': old_data},
329 'user_group.edit', action_data={'old_data': old_data},
329 user=apiuser)
330 user=apiuser)
330 Session().commit()
331 Session().commit()
331 return {
332 return {
332 'msg': 'updated user group ID:%s %s' % (
333 'msg': 'updated user group ID:%s %s' % (
333 user_group.users_group_id, user_group.users_group_name),
334 user_group.users_group_id, user_group.users_group_name),
334 'user_group': user_group.get_api_data(
335 'user_group': user_group.get_api_data(
335 include_secrets=include_secrets)
336 include_secrets=include_secrets)
336 }
337 }
337 except Exception:
338 except Exception:
338 log.exception("Error occurred during update of user group")
339 log.exception("Error occurred during update of user group")
339 raise JSONRPCError(
340 raise JSONRPCError(
340 'failed to update user group `%s`' % (usergroupid,))
341 'failed to update user group `%s`' % (usergroupid,))
341
342
342
343
343 @jsonrpc_method()
344 @jsonrpc_method()
344 def delete_user_group(request, apiuser, usergroupid):
345 def delete_user_group(request, apiuser, usergroupid):
345 """
346 """
346 Deletes the specified `user group`.
347 Deletes the specified `user group`.
347
348
348 This command can only be run using an |authtoken| with admin rights to
349 This command can only be run using an |authtoken| with admin rights to
349 the specified repository.
350 the specified repository.
350
351
351 This command takes the following options:
352 This command takes the following options:
352
353
353 :param apiuser: filled automatically from apikey
354 :param apiuser: filled automatically from apikey
354 :type apiuser: AuthUser
355 :type apiuser: AuthUser
355 :param usergroupid:
356 :param usergroupid:
356 :type usergroupid: int
357 :type usergroupid: int
357
358
358 Example output:
359 Example output:
359
360
360 .. code-block:: bash
361 .. code-block:: bash
361
362
362 id : <id_given_in_input>
363 id : <id_given_in_input>
363 result : {
364 result : {
364 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
365 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
365 }
366 }
366 error : null
367 error : null
367
368
368 Example error output:
369 Example error output:
369
370
370 .. code-block:: bash
371 .. code-block:: bash
371
372
372 id : <id_given_in_input>
373 id : <id_given_in_input>
373 result : null
374 result : null
374 error : {
375 error : {
375 "failed to delete user group ID:<user_group_id> <user_group_name>"
376 "failed to delete user group ID:<user_group_id> <user_group_name>"
376 or
377 or
377 "RepoGroup assigned to <repo_groups_list>"
378 "RepoGroup assigned to <repo_groups_list>"
378 }
379 }
379
380
380 """
381 """
381
382
382 user_group = get_user_group_or_error(usergroupid)
383 user_group = get_user_group_or_error(usergroupid)
383 if not has_superadmin_permission(apiuser):
384 if not has_superadmin_permission(apiuser):
384 # check if we have admin permission for this user group !
385 # check if we have admin permission for this user group !
385 _perms = ('usergroup.admin',)
386 _perms = ('usergroup.admin',)
386 if not HasUserGroupPermissionAnyApi(*_perms)(
387 if not HasUserGroupPermissionAnyApi(*_perms)(
387 user=apiuser, user_group_name=user_group.users_group_name):
388 user=apiuser, user_group_name=user_group.users_group_name):
388 raise JSONRPCError(
389 raise JSONRPCError(
389 'user group `%s` does not exist' % (usergroupid,))
390 'user group `%s` does not exist' % (usergroupid,))
390
391
391 old_data = user_group.get_api_data()
392 old_data = user_group.get_api_data()
392 try:
393 try:
393 UserGroupModel().delete(user_group)
394 UserGroupModel().delete(user_group)
394 audit_logger.store_api(
395 audit_logger.store_api(
395 'user_group.delete', action_data={'old_data': old_data},
396 'user_group.delete', action_data={'old_data': old_data},
396 user=apiuser)
397 user=apiuser)
397 Session().commit()
398 Session().commit()
398 return {
399 return {
399 'msg': 'deleted user group ID:%s %s' % (
400 'msg': 'deleted user group ID:%s %s' % (
400 user_group.users_group_id, user_group.users_group_name),
401 user_group.users_group_id, user_group.users_group_name),
401 'user_group': None
402 'user_group': None
402 }
403 }
403 except UserGroupAssignedException as e:
404 except UserGroupAssignedException as e:
404 log.exception("UserGroupAssigned error")
405 log.exception("UserGroupAssigned error")
405 raise JSONRPCError(str(e))
406 raise JSONRPCError(str(e))
406 except Exception:
407 except Exception:
407 log.exception("Error occurred during deletion of user group")
408 log.exception("Error occurred during deletion of user group")
408 raise JSONRPCError(
409 raise JSONRPCError(
409 'failed to delete user group ID:%s %s' %(
410 'failed to delete user group ID:%s %s' %(
410 user_group.users_group_id, user_group.users_group_name))
411 user_group.users_group_id, user_group.users_group_name))
411
412
412
413
413 @jsonrpc_method()
414 @jsonrpc_method()
414 def add_user_to_user_group(request, apiuser, usergroupid, userid):
415 def add_user_to_user_group(request, apiuser, usergroupid, userid):
415 """
416 """
416 Adds a user to a `user group`. If the user already exists in the group
417 Adds a user to a `user group`. If the user already exists in the group
417 this command will return false.
418 this command will return false.
418
419
419 This command can only be run using an |authtoken| with admin rights to
420 This command can only be run using an |authtoken| with admin rights to
420 the specified user group.
421 the specified user group.
421
422
422 This command takes the following options:
423 This command takes the following options:
423
424
424 :param apiuser: This is filled automatically from the |authtoken|.
425 :param apiuser: This is filled automatically from the |authtoken|.
425 :type apiuser: AuthUser
426 :type apiuser: AuthUser
426 :param usergroupid: Set the name of the `user group` to which a
427 :param usergroupid: Set the name of the `user group` to which a
427 user will be added.
428 user will be added.
428 :type usergroupid: int
429 :type usergroupid: int
429 :param userid: Set the `user_id` of the user to add to the group.
430 :param userid: Set the `user_id` of the user to add to the group.
430 :type userid: int
431 :type userid: int
431
432
432 Example output:
433 Example output:
433
434
434 .. code-block:: bash
435 .. code-block:: bash
435
436
436 id : <id_given_in_input>
437 id : <id_given_in_input>
437 result : {
438 result : {
438 "success": True|False # depends on if member is in group
439 "success": True|False # depends on if member is in group
439 "msg": "added member `<username>` to user group `<groupname>` |
440 "msg": "added member `<username>` to user group `<groupname>` |
440 User is already in that group"
441 User is already in that group"
441
442
442 }
443 }
443 error : null
444 error : null
444
445
445 Example error output:
446 Example error output:
446
447
447 .. code-block:: bash
448 .. code-block:: bash
448
449
449 id : <id_given_in_input>
450 id : <id_given_in_input>
450 result : null
451 result : null
451 error : {
452 error : {
452 "failed to add member to user group `<user_group_name>`"
453 "failed to add member to user group `<user_group_name>`"
453 }
454 }
454
455
455 """
456 """
456
457
457 user = get_user_or_error(userid)
458 user = get_user_or_error(userid)
458 user_group = get_user_group_or_error(usergroupid)
459 user_group = get_user_group_or_error(usergroupid)
459 if not has_superadmin_permission(apiuser):
460 if not has_superadmin_permission(apiuser):
460 # check if we have admin permission for this user group !
461 # check if we have admin permission for this user group !
461 _perms = ('usergroup.admin',)
462 _perms = ('usergroup.admin',)
462 if not HasUserGroupPermissionAnyApi(*_perms)(
463 if not HasUserGroupPermissionAnyApi(*_perms)(
463 user=apiuser, user_group_name=user_group.users_group_name):
464 user=apiuser, user_group_name=user_group.users_group_name):
464 raise JSONRPCError('user group `%s` does not exist' % (
465 raise JSONRPCError('user group `%s` does not exist' % (
465 usergroupid,))
466 usergroupid,))
466
467
467 old_values = user_group.get_api_data()
468 old_values = user_group.get_api_data()
468 try:
469 try:
469 ugm = UserGroupModel().add_user_to_group(user_group, user)
470 ugm = UserGroupModel().add_user_to_group(user_group, user)
470 success = True if ugm is not True else False
471 success = True if ugm is not True else False
471 msg = 'added member `%s` to user group `%s`' % (
472 msg = 'added member `%s` to user group `%s`' % (
472 user.username, user_group.users_group_name
473 user.username, user_group.users_group_name
473 )
474 )
474 msg = msg if success else 'User is already in that group'
475 msg = msg if success else 'User is already in that group'
475 if success:
476 if success:
476 user_data = user.get_api_data()
477 user_data = user.get_api_data()
477 audit_logger.store_api(
478 audit_logger.store_api(
478 'user_group.edit.member.add',
479 'user_group.edit.member.add',
479 action_data={'user': user_data, 'old_data': old_values},
480 action_data={'user': user_data, 'old_data': old_values},
480 user=apiuser)
481 user=apiuser)
481
482
482 Session().commit()
483 Session().commit()
483
484
484 return {
485 return {
485 'success': success,
486 'success': success,
486 'msg': msg
487 'msg': msg
487 }
488 }
488 except Exception:
489 except Exception:
489 log.exception("Error occurred during adding a member to user group")
490 log.exception("Error occurred during adding a member to user group")
490 raise JSONRPCError(
491 raise JSONRPCError(
491 'failed to add member to user group `%s`' % (
492 'failed to add member to user group `%s`' % (
492 user_group.users_group_name,
493 user_group.users_group_name,
493 )
494 )
494 )
495 )
495
496
496
497
497 @jsonrpc_method()
498 @jsonrpc_method()
498 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
499 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
499 """
500 """
500 Removes a user from a user group.
501 Removes a user from a user group.
501
502
502 * If the specified user is not in the group, this command will return
503 * If the specified user is not in the group, this command will return
503 `false`.
504 `false`.
504
505
505 This command can only be run using an |authtoken| with admin rights to
506 This command can only be run using an |authtoken| with admin rights to
506 the specified user group.
507 the specified user group.
507
508
508 :param apiuser: This is filled automatically from the |authtoken|.
509 :param apiuser: This is filled automatically from the |authtoken|.
509 :type apiuser: AuthUser
510 :type apiuser: AuthUser
510 :param usergroupid: Sets the user group name.
511 :param usergroupid: Sets the user group name.
511 :type usergroupid: str or int
512 :type usergroupid: str or int
512 :param userid: The user you wish to remove from |RCE|.
513 :param userid: The user you wish to remove from |RCE|.
513 :type userid: str or int
514 :type userid: str or int
514
515
515 Example output:
516 Example output:
516
517
517 .. code-block:: bash
518 .. code-block:: bash
518
519
519 id : <id_given_in_input>
520 id : <id_given_in_input>
520 result: {
521 result: {
521 "success": True|False, # depends on if member is in group
522 "success": True|False, # depends on if member is in group
522 "msg": "removed member <username> from user group <groupname> |
523 "msg": "removed member <username> from user group <groupname> |
523 User wasn't in group"
524 User wasn't in group"
524 }
525 }
525 error: null
526 error: null
526
527
527 """
528 """
528
529
529 user = get_user_or_error(userid)
530 user = get_user_or_error(userid)
530 user_group = get_user_group_or_error(usergroupid)
531 user_group = get_user_group_or_error(usergroupid)
531 if not has_superadmin_permission(apiuser):
532 if not has_superadmin_permission(apiuser):
532 # check if we have admin permission for this user group !
533 # check if we have admin permission for this user group !
533 _perms = ('usergroup.admin',)
534 _perms = ('usergroup.admin',)
534 if not HasUserGroupPermissionAnyApi(*_perms)(
535 if not HasUserGroupPermissionAnyApi(*_perms)(
535 user=apiuser, user_group_name=user_group.users_group_name):
536 user=apiuser, user_group_name=user_group.users_group_name):
536 raise JSONRPCError(
537 raise JSONRPCError(
537 'user group `%s` does not exist' % (usergroupid,))
538 'user group `%s` does not exist' % (usergroupid,))
538
539
539 old_values = user_group.get_api_data()
540 old_values = user_group.get_api_data()
540 try:
541 try:
541 success = UserGroupModel().remove_user_from_group(user_group, user)
542 success = UserGroupModel().remove_user_from_group(user_group, user)
542 msg = 'removed member `%s` from user group `%s`' % (
543 msg = 'removed member `%s` from user group `%s`' % (
543 user.username, user_group.users_group_name
544 user.username, user_group.users_group_name
544 )
545 )
545 msg = msg if success else "User wasn't in group"
546 msg = msg if success else "User wasn't in group"
546 if success:
547 if success:
547 user_data = user.get_api_data()
548 user_data = user.get_api_data()
548 audit_logger.store_api(
549 audit_logger.store_api(
549 'user_group.edit.member.delete',
550 'user_group.edit.member.delete',
550 action_data={'user': user_data, 'old_data': old_values},
551 action_data={'user': user_data, 'old_data': old_values},
551 user=apiuser)
552 user=apiuser)
552
553
553 Session().commit()
554 Session().commit()
554 return {'success': success, 'msg': msg}
555 return {'success': success, 'msg': msg}
555 except Exception:
556 except Exception:
556 log.exception("Error occurred during removing an member from user group")
557 log.exception("Error occurred during removing an member from user group")
557 raise JSONRPCError(
558 raise JSONRPCError(
558 'failed to remove member from user group `%s`' % (
559 'failed to remove member from user group `%s`' % (
559 user_group.users_group_name,
560 user_group.users_group_name,
560 )
561 )
561 )
562 )
562
563
563
564
564 @jsonrpc_method()
565 @jsonrpc_method()
565 def grant_user_permission_to_user_group(
566 def grant_user_permission_to_user_group(
566 request, apiuser, usergroupid, userid, perm):
567 request, apiuser, usergroupid, userid, perm):
567 """
568 """
568 Set permissions for a user in a user group.
569 Set permissions for a user in a user group.
569
570
570 :param apiuser: This is filled automatically from the |authtoken|.
571 :param apiuser: This is filled automatically from the |authtoken|.
571 :type apiuser: AuthUser
572 :type apiuser: AuthUser
572 :param usergroupid: Set the user group to edit permissions on.
573 :param usergroupid: Set the user group to edit permissions on.
573 :type usergroupid: str or int
574 :type usergroupid: str or int
574 :param userid: Set the user from whom you wish to set permissions.
575 :param userid: Set the user from whom you wish to set permissions.
575 :type userid: str
576 :type userid: str
576 :param perm: (usergroup.(none|read|write|admin))
577 :param perm: (usergroup.(none|read|write|admin))
577 :type perm: str
578 :type perm: str
578
579
579 Example output:
580 Example output:
580
581
581 .. code-block:: bash
582 .. code-block:: bash
582
583
583 id : <id_given_in_input>
584 id : <id_given_in_input>
584 result : {
585 result : {
585 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
586 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
586 "success": true
587 "success": true
587 }
588 }
588 error : null
589 error : null
589 """
590 """
590
591
591 user_group = get_user_group_or_error(usergroupid)
592 user_group = get_user_group_or_error(usergroupid)
592
593
593 if not has_superadmin_permission(apiuser):
594 if not has_superadmin_permission(apiuser):
594 # check if we have admin permission for this user group !
595 # check if we have admin permission for this user group !
595 _perms = ('usergroup.admin',)
596 _perms = ('usergroup.admin',)
596 if not HasUserGroupPermissionAnyApi(*_perms)(
597 if not HasUserGroupPermissionAnyApi(*_perms)(
597 user=apiuser, user_group_name=user_group.users_group_name):
598 user=apiuser, user_group_name=user_group.users_group_name):
598 raise JSONRPCError(
599 raise JSONRPCError(
599 'user group `%s` does not exist' % (usergroupid,))
600 'user group `%s` does not exist' % (usergroupid,))
600
601
601 user = get_user_or_error(userid)
602 user = get_user_or_error(userid)
602 perm = get_perm_or_error(perm, prefix='usergroup.')
603 perm = get_perm_or_error(perm, prefix='usergroup.')
603
604
604 try:
605 try:
605 UserGroupModel().grant_user_permission(
606 UserGroupModel().grant_user_permission(
606 user_group=user_group, user=user, perm=perm)
607 user_group=user_group, user=user, perm=perm)
607 Session().commit()
608 Session().commit()
608 return {
609 return {
609 'msg':
610 'msg':
610 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
611 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
611 perm.permission_name, user.username,
612 perm.permission_name, user.username,
612 user_group.users_group_name
613 user_group.users_group_name
613 ),
614 ),
614 'success': True
615 'success': True
615 }
616 }
616 except Exception:
617 except Exception:
617 log.exception("Error occurred during editing permissions "
618 log.exception("Error occurred during editing permissions "
618 "for user in user group")
619 "for user in user group")
619 raise JSONRPCError(
620 raise JSONRPCError(
620 'failed to edit permission for user: '
621 'failed to edit permission for user: '
621 '`%s` in user group: `%s`' % (
622 '`%s` in user group: `%s`' % (
622 userid, user_group.users_group_name))
623 userid, user_group.users_group_name))
623
624
624
625
625 @jsonrpc_method()
626 @jsonrpc_method()
626 def revoke_user_permission_from_user_group(
627 def revoke_user_permission_from_user_group(
627 request, apiuser, usergroupid, userid):
628 request, apiuser, usergroupid, userid):
628 """
629 """
629 Revoke a users permissions in a user group.
630 Revoke a users permissions in a user group.
630
631
631 :param apiuser: This is filled automatically from the |authtoken|.
632 :param apiuser: This is filled automatically from the |authtoken|.
632 :type apiuser: AuthUser
633 :type apiuser: AuthUser
633 :param usergroupid: Set the user group from which to revoke the user
634 :param usergroupid: Set the user group from which to revoke the user
634 permissions.
635 permissions.
635 :type: usergroupid: str or int
636 :type: usergroupid: str or int
636 :param userid: Set the userid of the user whose permissions will be
637 :param userid: Set the userid of the user whose permissions will be
637 revoked.
638 revoked.
638 :type userid: str
639 :type userid: str
639
640
640 Example output:
641 Example output:
641
642
642 .. code-block:: bash
643 .. code-block:: bash
643
644
644 id : <id_given_in_input>
645 id : <id_given_in_input>
645 result : {
646 result : {
646 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
647 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
647 "success": true
648 "success": true
648 }
649 }
649 error : null
650 error : null
650 """
651 """
651
652
652 user_group = get_user_group_or_error(usergroupid)
653 user_group = get_user_group_or_error(usergroupid)
653
654
654 if not has_superadmin_permission(apiuser):
655 if not has_superadmin_permission(apiuser):
655 # check if we have admin permission for this user group !
656 # check if we have admin permission for this user group !
656 _perms = ('usergroup.admin',)
657 _perms = ('usergroup.admin',)
657 if not HasUserGroupPermissionAnyApi(*_perms)(
658 if not HasUserGroupPermissionAnyApi(*_perms)(
658 user=apiuser, user_group_name=user_group.users_group_name):
659 user=apiuser, user_group_name=user_group.users_group_name):
659 raise JSONRPCError(
660 raise JSONRPCError(
660 'user group `%s` does not exist' % (usergroupid,))
661 'user group `%s` does not exist' % (usergroupid,))
661
662
662 user = get_user_or_error(userid)
663 user = get_user_or_error(userid)
663
664
664 try:
665 try:
665 UserGroupModel().revoke_user_permission(
666 UserGroupModel().revoke_user_permission(
666 user_group=user_group, user=user)
667 user_group=user_group, user=user)
667 Session().commit()
668 Session().commit()
668 return {
669 return {
669 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
670 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
670 user.username, user_group.users_group_name
671 user.username, user_group.users_group_name
671 ),
672 ),
672 'success': True
673 'success': True
673 }
674 }
674 except Exception:
675 except Exception:
675 log.exception("Error occurred during editing permissions "
676 log.exception("Error occurred during editing permissions "
676 "for user in user group")
677 "for user in user group")
677 raise JSONRPCError(
678 raise JSONRPCError(
678 'failed to edit permission for user: `%s` in user group: `%s`'
679 'failed to edit permission for user: `%s` in user group: `%s`'
679 % (userid, user_group.users_group_name))
680 % (userid, user_group.users_group_name))
680
681
681
682
682 @jsonrpc_method()
683 @jsonrpc_method()
683 def grant_user_group_permission_to_user_group(
684 def grant_user_group_permission_to_user_group(
684 request, apiuser, usergroupid, sourceusergroupid, perm):
685 request, apiuser, usergroupid, sourceusergroupid, perm):
685 """
686 """
686 Give one user group permissions to another user group.
687 Give one user group permissions to another user group.
687
688
688 :param apiuser: This is filled automatically from the |authtoken|.
689 :param apiuser: This is filled automatically from the |authtoken|.
689 :type apiuser: AuthUser
690 :type apiuser: AuthUser
690 :param usergroupid: Set the user group on which to edit permissions.
691 :param usergroupid: Set the user group on which to edit permissions.
691 :type usergroupid: str or int
692 :type usergroupid: str or int
692 :param sourceusergroupid: Set the source user group to which
693 :param sourceusergroupid: Set the source user group to which
693 access/permissions will be granted.
694 access/permissions will be granted.
694 :type sourceusergroupid: str or int
695 :type sourceusergroupid: str or int
695 :param perm: (usergroup.(none|read|write|admin))
696 :param perm: (usergroup.(none|read|write|admin))
696 :type perm: str
697 :type perm: str
697
698
698 Example output:
699 Example output:
699
700
700 .. code-block:: bash
701 .. code-block:: bash
701
702
702 id : <id_given_in_input>
703 id : <id_given_in_input>
703 result : {
704 result : {
704 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
705 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
705 "success": true
706 "success": true
706 }
707 }
707 error : null
708 error : null
708 """
709 """
709
710
710 user_group = get_user_group_or_error(sourceusergroupid)
711 user_group = get_user_group_or_error(sourceusergroupid)
711 target_user_group = get_user_group_or_error(usergroupid)
712 target_user_group = get_user_group_or_error(usergroupid)
712 perm = get_perm_or_error(perm, prefix='usergroup.')
713 perm = get_perm_or_error(perm, prefix='usergroup.')
713
714
714 if not has_superadmin_permission(apiuser):
715 if not has_superadmin_permission(apiuser):
715 # check if we have admin permission for this user group !
716 # check if we have admin permission for this user group !
716 _perms = ('usergroup.admin',)
717 _perms = ('usergroup.admin',)
717 if not HasUserGroupPermissionAnyApi(*_perms)(
718 if not HasUserGroupPermissionAnyApi(*_perms)(
718 user=apiuser,
719 user=apiuser,
719 user_group_name=target_user_group.users_group_name):
720 user_group_name=target_user_group.users_group_name):
720 raise JSONRPCError(
721 raise JSONRPCError(
721 'to user group `%s` does not exist' % (usergroupid,))
722 'to user group `%s` does not exist' % (usergroupid,))
722
723
723 # check if we have at least read permission for source user group !
724 # check if we have at least read permission for source user group !
724 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
725 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
725 if not HasUserGroupPermissionAnyApi(*_perms)(
726 if not HasUserGroupPermissionAnyApi(*_perms)(
726 user=apiuser, user_group_name=user_group.users_group_name):
727 user=apiuser, user_group_name=user_group.users_group_name):
727 raise JSONRPCError(
728 raise JSONRPCError(
728 'user group `%s` does not exist' % (sourceusergroupid,))
729 'user group `%s` does not exist' % (sourceusergroupid,))
729
730
730 try:
731 try:
731 UserGroupModel().grant_user_group_permission(
732 UserGroupModel().grant_user_group_permission(
732 target_user_group=target_user_group,
733 target_user_group=target_user_group,
733 user_group=user_group, perm=perm)
734 user_group=user_group, perm=perm)
734 Session().commit()
735 Session().commit()
735
736
736 return {
737 return {
737 'msg': 'Granted perm: `%s` for user group: `%s` '
738 'msg': 'Granted perm: `%s` for user group: `%s` '
738 'in user group: `%s`' % (
739 'in user group: `%s`' % (
739 perm.permission_name, user_group.users_group_name,
740 perm.permission_name, user_group.users_group_name,
740 target_user_group.users_group_name
741 target_user_group.users_group_name
741 ),
742 ),
742 'success': True
743 'success': True
743 }
744 }
744 except Exception:
745 except Exception:
745 log.exception("Error occurred during editing permissions "
746 log.exception("Error occurred during editing permissions "
746 "for user group in user group")
747 "for user group in user group")
747 raise JSONRPCError(
748 raise JSONRPCError(
748 'failed to edit permission for user group: `%s` in '
749 'failed to edit permission for user group: `%s` in '
749 'user group: `%s`' % (
750 'user group: `%s`' % (
750 sourceusergroupid, target_user_group.users_group_name
751 sourceusergroupid, target_user_group.users_group_name
751 )
752 )
752 )
753 )
753
754
754
755
755 @jsonrpc_method()
756 @jsonrpc_method()
756 def revoke_user_group_permission_from_user_group(
757 def revoke_user_group_permission_from_user_group(
757 request, apiuser, usergroupid, sourceusergroupid):
758 request, apiuser, usergroupid, sourceusergroupid):
758 """
759 """
759 Revoke the permissions that one user group has to another.
760 Revoke the permissions that one user group has to another.
760
761
761 :param apiuser: This is filled automatically from the |authtoken|.
762 :param apiuser: This is filled automatically from the |authtoken|.
762 :type apiuser: AuthUser
763 :type apiuser: AuthUser
763 :param usergroupid: Set the user group on which to edit permissions.
764 :param usergroupid: Set the user group on which to edit permissions.
764 :type usergroupid: str or int
765 :type usergroupid: str or int
765 :param sourceusergroupid: Set the user group from which permissions
766 :param sourceusergroupid: Set the user group from which permissions
766 are revoked.
767 are revoked.
767 :type sourceusergroupid: str or int
768 :type sourceusergroupid: str or int
768
769
769 Example output:
770 Example output:
770
771
771 .. code-block:: bash
772 .. code-block:: bash
772
773
773 id : <id_given_in_input>
774 id : <id_given_in_input>
774 result : {
775 result : {
775 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
776 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
776 "success": true
777 "success": true
777 }
778 }
778 error : null
779 error : null
779 """
780 """
780
781
781 user_group = get_user_group_or_error(sourceusergroupid)
782 user_group = get_user_group_or_error(sourceusergroupid)
782 target_user_group = get_user_group_or_error(usergroupid)
783 target_user_group = get_user_group_or_error(usergroupid)
783
784
784 if not has_superadmin_permission(apiuser):
785 if not has_superadmin_permission(apiuser):
785 # check if we have admin permission for this user group !
786 # check if we have admin permission for this user group !
786 _perms = ('usergroup.admin',)
787 _perms = ('usergroup.admin',)
787 if not HasUserGroupPermissionAnyApi(*_perms)(
788 if not HasUserGroupPermissionAnyApi(*_perms)(
788 user=apiuser,
789 user=apiuser,
789 user_group_name=target_user_group.users_group_name):
790 user_group_name=target_user_group.users_group_name):
790 raise JSONRPCError(
791 raise JSONRPCError(
791 'to user group `%s` does not exist' % (usergroupid,))
792 'to user group `%s` does not exist' % (usergroupid,))
792
793
793 # check if we have at least read permission
794 # check if we have at least read permission
794 # for the source user group !
795 # for the source user group !
795 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
796 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
796 if not HasUserGroupPermissionAnyApi(*_perms)(
797 if not HasUserGroupPermissionAnyApi(*_perms)(
797 user=apiuser, user_group_name=user_group.users_group_name):
798 user=apiuser, user_group_name=user_group.users_group_name):
798 raise JSONRPCError(
799 raise JSONRPCError(
799 'user group `%s` does not exist' % (sourceusergroupid,))
800 'user group `%s` does not exist' % (sourceusergroupid,))
800
801
801 try:
802 try:
802 UserGroupModel().revoke_user_group_permission(
803 UserGroupModel().revoke_user_group_permission(
803 target_user_group=target_user_group, user_group=user_group)
804 target_user_group=target_user_group, user_group=user_group)
804 Session().commit()
805 Session().commit()
805
806
806 return {
807 return {
807 'msg': 'Revoked perm for user group: '
808 'msg': 'Revoked perm for user group: '
808 '`%s` in user group: `%s`' % (
809 '`%s` in user group: `%s`' % (
809 user_group.users_group_name,
810 user_group.users_group_name,
810 target_user_group.users_group_name
811 target_user_group.users_group_name
811 ),
812 ),
812 'success': True
813 'success': True
813 }
814 }
814 except Exception:
815 except Exception:
815 log.exception("Error occurred during editing permissions "
816 log.exception("Error occurred during editing permissions "
816 "for user group in user group")
817 "for user group in user group")
817 raise JSONRPCError(
818 raise JSONRPCError(
818 'failed to edit permission for user group: '
819 'failed to edit permission for user group: '
819 '`%s` in user group: `%s`' % (
820 '`%s` in user group: `%s`' % (
820 sourceusergroupid, target_user_group.users_group_name
821 sourceusergroupid, target_user_group.users_group_name
821 )
822 )
822 )
823 )
@@ -1,546 +1,519 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 import peppercorn
23 import peppercorn
24 import formencode
24 import formencode
25 import formencode.htmlfill
25 import formencode.htmlfill
26 from pyramid.httpexceptions import HTTPFound
26 from pyramid.httpexceptions import HTTPFound
27 from pyramid.view import view_config
27 from pyramid.view import view_config
28 from pyramid.response import Response
28 from pyramid.response import Response
29 from pyramid.renderers import render
29 from pyramid.renderers import render
30
30
31 from rhodecode.lib.exceptions import (
31 from rhodecode.lib.exceptions import (
32 RepoGroupAssignmentError, UserGroupAssignedException)
32 RepoGroupAssignmentError, UserGroupAssignedException)
33 from rhodecode.model.forms import (
33 from rhodecode.model.forms import (
34 UserGroupPermsForm, UserGroupForm, UserIndividualPermissionsForm,
34 UserGroupPermsForm, UserGroupForm, UserIndividualPermissionsForm,
35 UserPermissionsForm)
35 UserPermissionsForm)
36 from rhodecode.model.permission import PermissionModel
36 from rhodecode.model.permission import PermissionModel
37
37
38 from rhodecode.apps._base import UserGroupAppView
38 from rhodecode.apps._base import UserGroupAppView
39 from rhodecode.lib.auth import (
39 from rhodecode.lib.auth import (
40 LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired)
40 LoginRequired, HasUserGroupPermissionAnyDecorator, CSRFRequired)
41 from rhodecode.lib import helpers as h, audit_logger
41 from rhodecode.lib import helpers as h, audit_logger
42 from rhodecode.lib.utils2 import str2bool
42 from rhodecode.lib.utils2 import str2bool
43 from rhodecode.model.db import (
43 from rhodecode.model.db import User
44 joinedload, User, UserGroupRepoToPerm, UserGroupRepoGroupToPerm)
45 from rhodecode.model.meta import Session
44 from rhodecode.model.meta import Session
46 from rhodecode.model.user_group import UserGroupModel
45 from rhodecode.model.user_group import UserGroupModel
47
46
48 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
49
48
50
49
51 class UserGroupsView(UserGroupAppView):
50 class UserGroupsView(UserGroupAppView):
52
51
53 def load_default_context(self):
52 def load_default_context(self):
54 c = self._get_local_tmpl_context()
53 c = self._get_local_tmpl_context()
55
54
56 PermissionModel().set_global_permission_choices(
55 PermissionModel().set_global_permission_choices(
57 c, gettext_translator=self.request.translate)
56 c, gettext_translator=self.request.translate)
58
57
59
60 return c
58 return c
61
59
62 def _get_perms_summary(self, user_group_id):
63 permissions = {
64 'repositories': {},
65 'repositories_groups': {},
66 }
67 ugroup_repo_perms = UserGroupRepoToPerm.query()\
68 .options(joinedload(UserGroupRepoToPerm.permission))\
69 .options(joinedload(UserGroupRepoToPerm.repository))\
70 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
71 .all()
72
73 for gr in ugroup_repo_perms:
74 permissions['repositories'][gr.repository.repo_name] \
75 = gr.permission.permission_name
76
77 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
78 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
79 .options(joinedload(UserGroupRepoGroupToPerm.group))\
80 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
81 .all()
82
83 for gr in ugroup_group_perms:
84 permissions['repositories_groups'][gr.group.group_name] \
85 = gr.permission.permission_name
86 return permissions
87
88 @LoginRequired()
60 @LoginRequired()
89 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
61 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
90 @view_config(
62 @view_config(
91 route_name='user_group_members_data', request_method='GET',
63 route_name='user_group_members_data', request_method='GET',
92 renderer='json_ext', xhr=True)
64 renderer='json_ext', xhr=True)
93 def user_group_members(self):
65 def user_group_members(self):
94 """
66 """
95 Return members of given user group
67 Return members of given user group
96 """
68 """
97 self.load_default_context()
69 self.load_default_context()
98 user_group = self.db_user_group
70 user_group = self.db_user_group
99 group_members_obj = sorted((x.user for x in user_group.members),
71 group_members_obj = sorted((x.user for x in user_group.members),
100 key=lambda u: u.username.lower())
72 key=lambda u: u.username.lower())
101
73
102 group_members = [
74 group_members = [
103 {
75 {
104 'id': user.user_id,
76 'id': user.user_id,
105 'first_name': user.first_name,
77 'first_name': user.first_name,
106 'last_name': user.last_name,
78 'last_name': user.last_name,
107 'username': user.username,
79 'username': user.username,
108 'icon_link': h.gravatar_url(user.email, 30),
80 'icon_link': h.gravatar_url(user.email, 30),
109 'value_display': h.person(user.email),
81 'value_display': h.person(user.email),
110 'value': user.username,
82 'value': user.username,
111 'value_type': 'user',
83 'value_type': 'user',
112 'active': user.active,
84 'active': user.active,
113 }
85 }
114 for user in group_members_obj
86 for user in group_members_obj
115 ]
87 ]
116
88
117 return {
89 return {
118 'members': group_members
90 'members': group_members
119 }
91 }
120
92
121 @LoginRequired()
93 @LoginRequired()
122 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
94 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
123 @view_config(
95 @view_config(
124 route_name='edit_user_group_perms_summary', request_method='GET',
96 route_name='edit_user_group_perms_summary', request_method='GET',
125 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
97 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
126 def user_group_perms_summary(self):
98 def user_group_perms_summary(self):
127 c = self.load_default_context()
99 c = self.load_default_context()
128 c.user_group = self.db_user_group
100 c.user_group = self.db_user_group
129 c.active = 'perms_summary'
101 c.active = 'perms_summary'
130 c.permissions = self._get_perms_summary(c.user_group.users_group_id)
102 c.permissions = UserGroupModel().get_perms_summary(
103 c.user_group.users_group_id)
131 return self._get_template_context(c)
104 return self._get_template_context(c)
132
105
133 @LoginRequired()
106 @LoginRequired()
134 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
107 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
135 @view_config(
108 @view_config(
136 route_name='edit_user_group_perms_summary_json', request_method='GET',
109 route_name='edit_user_group_perms_summary_json', request_method='GET',
137 renderer='json_ext')
110 renderer='json_ext')
138 def user_group_perms_summary_json(self):
111 def user_group_perms_summary_json(self):
139 self.load_default_context()
112 self.load_default_context()
140 user_group = self.db_user_group
113 user_group = self.db_user_group
141 return self._get_perms_summary(user_group.users_group_id)
114 return UserGroupModel().get_perms_summary(user_group.users_group_id)
142
115
143 def _revoke_perms_on_yourself(self, form_result):
116 def _revoke_perms_on_yourself(self, form_result):
144 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
117 _updates = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
145 form_result['perm_updates'])
118 form_result['perm_updates'])
146 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
119 _additions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
147 form_result['perm_additions'])
120 form_result['perm_additions'])
148 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
121 _deletions = filter(lambda u: self._rhodecode_user.user_id == int(u[0]),
149 form_result['perm_deletions'])
122 form_result['perm_deletions'])
150 admin_perm = 'usergroup.admin'
123 admin_perm = 'usergroup.admin'
151 if _updates and _updates[0][1] != admin_perm or \
124 if _updates and _updates[0][1] != admin_perm or \
152 _additions and _additions[0][1] != admin_perm or \
125 _additions and _additions[0][1] != admin_perm or \
153 _deletions and _deletions[0][1] != admin_perm:
126 _deletions and _deletions[0][1] != admin_perm:
154 return True
127 return True
155 return False
128 return False
156
129
157 @LoginRequired()
130 @LoginRequired()
158 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
131 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
159 @CSRFRequired()
132 @CSRFRequired()
160 @view_config(
133 @view_config(
161 route_name='user_groups_update', request_method='POST',
134 route_name='user_groups_update', request_method='POST',
162 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
135 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
163 def user_group_update(self):
136 def user_group_update(self):
164 _ = self.request.translate
137 _ = self.request.translate
165
138
166 user_group = self.db_user_group
139 user_group = self.db_user_group
167 user_group_id = user_group.users_group_id
140 user_group_id = user_group.users_group_id
168
141
169 c = self.load_default_context()
142 c = self.load_default_context()
170 c.user_group = user_group
143 c.user_group = user_group
171 c.group_members_obj = [x.user for x in c.user_group.members]
144 c.group_members_obj = [x.user for x in c.user_group.members]
172 c.group_members_obj.sort(key=lambda u: u.username.lower())
145 c.group_members_obj.sort(key=lambda u: u.username.lower())
173 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
146 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
174 c.active = 'settings'
147 c.active = 'settings'
175
148
176 users_group_form = UserGroupForm(
149 users_group_form = UserGroupForm(
177 self.request.translate, edit=True,
150 self.request.translate, edit=True,
178 old_data=c.user_group.get_dict(), allow_disabled=True)()
151 old_data=c.user_group.get_dict(), allow_disabled=True)()
179
152
180 old_values = c.user_group.get_api_data()
153 old_values = c.user_group.get_api_data()
181 user_group_name = self.request.POST.get('users_group_name')
154 user_group_name = self.request.POST.get('users_group_name')
182 try:
155 try:
183 form_result = users_group_form.to_python(self.request.POST)
156 form_result = users_group_form.to_python(self.request.POST)
184 pstruct = peppercorn.parse(self.request.POST.items())
157 pstruct = peppercorn.parse(self.request.POST.items())
185 form_result['users_group_members'] = pstruct['user_group_members']
158 form_result['users_group_members'] = pstruct['user_group_members']
186
159
187 user_group, added_members, removed_members = \
160 user_group, added_members, removed_members = \
188 UserGroupModel().update(c.user_group, form_result)
161 UserGroupModel().update(c.user_group, form_result)
189 updated_user_group = form_result['users_group_name']
162 updated_user_group = form_result['users_group_name']
190
163
191 for user_id in added_members:
164 for user_id in added_members:
192 user = User.get(user_id)
165 user = User.get(user_id)
193 user_data = user.get_api_data()
166 user_data = user.get_api_data()
194 audit_logger.store_web(
167 audit_logger.store_web(
195 'user_group.edit.member.add',
168 'user_group.edit.member.add',
196 action_data={'user': user_data, 'old_data': old_values},
169 action_data={'user': user_data, 'old_data': old_values},
197 user=self._rhodecode_user)
170 user=self._rhodecode_user)
198
171
199 for user_id in removed_members:
172 for user_id in removed_members:
200 user = User.get(user_id)
173 user = User.get(user_id)
201 user_data = user.get_api_data()
174 user_data = user.get_api_data()
202 audit_logger.store_web(
175 audit_logger.store_web(
203 'user_group.edit.member.delete',
176 'user_group.edit.member.delete',
204 action_data={'user': user_data, 'old_data': old_values},
177 action_data={'user': user_data, 'old_data': old_values},
205 user=self._rhodecode_user)
178 user=self._rhodecode_user)
206
179
207 audit_logger.store_web(
180 audit_logger.store_web(
208 'user_group.edit', action_data={'old_data': old_values},
181 'user_group.edit', action_data={'old_data': old_values},
209 user=self._rhodecode_user)
182 user=self._rhodecode_user)
210
183
211 h.flash(_('Updated user group %s') % updated_user_group,
184 h.flash(_('Updated user group %s') % updated_user_group,
212 category='success')
185 category='success')
213 Session().commit()
186 Session().commit()
214 except formencode.Invalid as errors:
187 except formencode.Invalid as errors:
215 defaults = errors.value
188 defaults = errors.value
216 e = errors.error_dict or {}
189 e = errors.error_dict or {}
217
190
218 data = render(
191 data = render(
219 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
192 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
220 self._get_template_context(c), self.request)
193 self._get_template_context(c), self.request)
221 html = formencode.htmlfill.render(
194 html = formencode.htmlfill.render(
222 data,
195 data,
223 defaults=defaults,
196 defaults=defaults,
224 errors=e,
197 errors=e,
225 prefix_error=False,
198 prefix_error=False,
226 encoding="UTF-8",
199 encoding="UTF-8",
227 force_defaults=False
200 force_defaults=False
228 )
201 )
229 return Response(html)
202 return Response(html)
230
203
231 except Exception:
204 except Exception:
232 log.exception("Exception during update of user group")
205 log.exception("Exception during update of user group")
233 h.flash(_('Error occurred during update of user group %s')
206 h.flash(_('Error occurred during update of user group %s')
234 % user_group_name, category='error')
207 % user_group_name, category='error')
235
208
236 raise HTTPFound(
209 raise HTTPFound(
237 h.route_path('edit_user_group', user_group_id=user_group_id))
210 h.route_path('edit_user_group', user_group_id=user_group_id))
238
211
239 @LoginRequired()
212 @LoginRequired()
240 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
213 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
241 @CSRFRequired()
214 @CSRFRequired()
242 @view_config(
215 @view_config(
243 route_name='user_groups_delete', request_method='POST',
216 route_name='user_groups_delete', request_method='POST',
244 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
217 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
245 def user_group_delete(self):
218 def user_group_delete(self):
246 _ = self.request.translate
219 _ = self.request.translate
247 user_group = self.db_user_group
220 user_group = self.db_user_group
248
221
249 self.load_default_context()
222 self.load_default_context()
250 force = str2bool(self.request.POST.get('force'))
223 force = str2bool(self.request.POST.get('force'))
251
224
252 old_values = user_group.get_api_data()
225 old_values = user_group.get_api_data()
253 try:
226 try:
254 UserGroupModel().delete(user_group, force=force)
227 UserGroupModel().delete(user_group, force=force)
255 audit_logger.store_web(
228 audit_logger.store_web(
256 'user.delete', action_data={'old_data': old_values},
229 'user.delete', action_data={'old_data': old_values},
257 user=self._rhodecode_user)
230 user=self._rhodecode_user)
258 Session().commit()
231 Session().commit()
259 h.flash(_('Successfully deleted user group'), category='success')
232 h.flash(_('Successfully deleted user group'), category='success')
260 except UserGroupAssignedException as e:
233 except UserGroupAssignedException as e:
261 h.flash(str(e), category='error')
234 h.flash(str(e), category='error')
262 except Exception:
235 except Exception:
263 log.exception("Exception during deletion of user group")
236 log.exception("Exception during deletion of user group")
264 h.flash(_('An error occurred during deletion of user group'),
237 h.flash(_('An error occurred during deletion of user group'),
265 category='error')
238 category='error')
266 raise HTTPFound(h.route_path('user_groups'))
239 raise HTTPFound(h.route_path('user_groups'))
267
240
268 @LoginRequired()
241 @LoginRequired()
269 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
242 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
270 @view_config(
243 @view_config(
271 route_name='edit_user_group', request_method='GET',
244 route_name='edit_user_group', request_method='GET',
272 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
245 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
273 def user_group_edit(self):
246 def user_group_edit(self):
274 user_group = self.db_user_group
247 user_group = self.db_user_group
275
248
276 c = self.load_default_context()
249 c = self.load_default_context()
277 c.user_group = user_group
250 c.user_group = user_group
278 c.group_members_obj = [x.user for x in c.user_group.members]
251 c.group_members_obj = [x.user for x in c.user_group.members]
279 c.group_members_obj.sort(key=lambda u: u.username.lower())
252 c.group_members_obj.sort(key=lambda u: u.username.lower())
280 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
253 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
281
254
282 c.active = 'settings'
255 c.active = 'settings'
283
256
284 defaults = user_group.get_dict()
257 defaults = user_group.get_dict()
285 # fill owner
258 # fill owner
286 if user_group.user:
259 if user_group.user:
287 defaults.update({'user': user_group.user.username})
260 defaults.update({'user': user_group.user.username})
288 else:
261 else:
289 replacement_user = User.get_first_super_admin().username
262 replacement_user = User.get_first_super_admin().username
290 defaults.update({'user': replacement_user})
263 defaults.update({'user': replacement_user})
291
264
292 data = render(
265 data = render(
293 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
266 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
294 self._get_template_context(c), self.request)
267 self._get_template_context(c), self.request)
295 html = formencode.htmlfill.render(
268 html = formencode.htmlfill.render(
296 data,
269 data,
297 defaults=defaults,
270 defaults=defaults,
298 encoding="UTF-8",
271 encoding="UTF-8",
299 force_defaults=False
272 force_defaults=False
300 )
273 )
301 return Response(html)
274 return Response(html)
302
275
303 @LoginRequired()
276 @LoginRequired()
304 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
277 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
305 @view_config(
278 @view_config(
306 route_name='edit_user_group_perms', request_method='GET',
279 route_name='edit_user_group_perms', request_method='GET',
307 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
280 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
308 def user_group_edit_perms(self):
281 def user_group_edit_perms(self):
309 user_group = self.db_user_group
282 user_group = self.db_user_group
310 c = self.load_default_context()
283 c = self.load_default_context()
311 c.user_group = user_group
284 c.user_group = user_group
312 c.active = 'perms'
285 c.active = 'perms'
313
286
314 defaults = {}
287 defaults = {}
315 # fill user group users
288 # fill user group users
316 for p in c.user_group.user_user_group_to_perm:
289 for p in c.user_group.user_user_group_to_perm:
317 defaults.update({'u_perm_%s' % p.user.user_id:
290 defaults.update({'u_perm_%s' % p.user.user_id:
318 p.permission.permission_name})
291 p.permission.permission_name})
319
292
320 for p in c.user_group.user_group_user_group_to_perm:
293 for p in c.user_group.user_group_user_group_to_perm:
321 defaults.update({'g_perm_%s' % p.user_group.users_group_id:
294 defaults.update({'g_perm_%s' % p.user_group.users_group_id:
322 p.permission.permission_name})
295 p.permission.permission_name})
323
296
324 data = render(
297 data = render(
325 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
298 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
326 self._get_template_context(c), self.request)
299 self._get_template_context(c), self.request)
327 html = formencode.htmlfill.render(
300 html = formencode.htmlfill.render(
328 data,
301 data,
329 defaults=defaults,
302 defaults=defaults,
330 encoding="UTF-8",
303 encoding="UTF-8",
331 force_defaults=False
304 force_defaults=False
332 )
305 )
333 return Response(html)
306 return Response(html)
334
307
335 @LoginRequired()
308 @LoginRequired()
336 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
309 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
337 @CSRFRequired()
310 @CSRFRequired()
338 @view_config(
311 @view_config(
339 route_name='edit_user_group_perms_update', request_method='POST',
312 route_name='edit_user_group_perms_update', request_method='POST',
340 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
313 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
341 def user_group_update_perms(self):
314 def user_group_update_perms(self):
342 """
315 """
343 grant permission for given user group
316 grant permission for given user group
344 """
317 """
345 _ = self.request.translate
318 _ = self.request.translate
346
319
347 user_group = self.db_user_group
320 user_group = self.db_user_group
348 user_group_id = user_group.users_group_id
321 user_group_id = user_group.users_group_id
349 c = self.load_default_context()
322 c = self.load_default_context()
350 c.user_group = user_group
323 c.user_group = user_group
351 form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST)
324 form = UserGroupPermsForm(self.request.translate)().to_python(self.request.POST)
352
325
353 if not self._rhodecode_user.is_admin:
326 if not self._rhodecode_user.is_admin:
354 if self._revoke_perms_on_yourself(form):
327 if self._revoke_perms_on_yourself(form):
355 msg = _('Cannot change permission for yourself as admin')
328 msg = _('Cannot change permission for yourself as admin')
356 h.flash(msg, category='warning')
329 h.flash(msg, category='warning')
357 raise HTTPFound(
330 raise HTTPFound(
358 h.route_path('edit_user_group_perms',
331 h.route_path('edit_user_group_perms',
359 user_group_id=user_group_id))
332 user_group_id=user_group_id))
360
333
361 try:
334 try:
362 changes = UserGroupModel().update_permissions(
335 changes = UserGroupModel().update_permissions(
363 user_group_id,
336 user_group_id,
364 form['perm_additions'], form['perm_updates'],
337 form['perm_additions'], form['perm_updates'],
365 form['perm_deletions'])
338 form['perm_deletions'])
366
339
367 except RepoGroupAssignmentError:
340 except RepoGroupAssignmentError:
368 h.flash(_('Target group cannot be the same'), category='error')
341 h.flash(_('Target group cannot be the same'), category='error')
369 raise HTTPFound(
342 raise HTTPFound(
370 h.route_path('edit_user_group_perms',
343 h.route_path('edit_user_group_perms',
371 user_group_id=user_group_id))
344 user_group_id=user_group_id))
372
345
373 action_data = {
346 action_data = {
374 'added': changes['added'],
347 'added': changes['added'],
375 'updated': changes['updated'],
348 'updated': changes['updated'],
376 'deleted': changes['deleted'],
349 'deleted': changes['deleted'],
377 }
350 }
378 audit_logger.store_web(
351 audit_logger.store_web(
379 'user_group.edit.permissions', action_data=action_data,
352 'user_group.edit.permissions', action_data=action_data,
380 user=self._rhodecode_user)
353 user=self._rhodecode_user)
381
354
382 Session().commit()
355 Session().commit()
383 h.flash(_('User Group permissions updated'), category='success')
356 h.flash(_('User Group permissions updated'), category='success')
384 raise HTTPFound(
357 raise HTTPFound(
385 h.route_path('edit_user_group_perms', user_group_id=user_group_id))
358 h.route_path('edit_user_group_perms', user_group_id=user_group_id))
386
359
387 @LoginRequired()
360 @LoginRequired()
388 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
361 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
389 @view_config(
362 @view_config(
390 route_name='edit_user_group_global_perms', request_method='GET',
363 route_name='edit_user_group_global_perms', request_method='GET',
391 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
364 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
392 def user_group_global_perms_edit(self):
365 def user_group_global_perms_edit(self):
393 user_group = self.db_user_group
366 user_group = self.db_user_group
394 c = self.load_default_context()
367 c = self.load_default_context()
395 c.user_group = user_group
368 c.user_group = user_group
396 c.active = 'global_perms'
369 c.active = 'global_perms'
397
370
398 c.default_user = User.get_default_user()
371 c.default_user = User.get_default_user()
399 defaults = c.user_group.get_dict()
372 defaults = c.user_group.get_dict()
400 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
373 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
401 defaults.update(c.user_group.get_default_perms())
374 defaults.update(c.user_group.get_default_perms())
402
375
403 data = render(
376 data = render(
404 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
377 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
405 self._get_template_context(c), self.request)
378 self._get_template_context(c), self.request)
406 html = formencode.htmlfill.render(
379 html = formencode.htmlfill.render(
407 data,
380 data,
408 defaults=defaults,
381 defaults=defaults,
409 encoding="UTF-8",
382 encoding="UTF-8",
410 force_defaults=False
383 force_defaults=False
411 )
384 )
412 return Response(html)
385 return Response(html)
413
386
414 @LoginRequired()
387 @LoginRequired()
415 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
388 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
416 @CSRFRequired()
389 @CSRFRequired()
417 @view_config(
390 @view_config(
418 route_name='edit_user_group_global_perms_update', request_method='POST',
391 route_name='edit_user_group_global_perms_update', request_method='POST',
419 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
392 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
420 def user_group_global_perms_update(self):
393 def user_group_global_perms_update(self):
421 _ = self.request.translate
394 _ = self.request.translate
422 user_group = self.db_user_group
395 user_group = self.db_user_group
423 user_group_id = self.db_user_group.users_group_id
396 user_group_id = self.db_user_group.users_group_id
424
397
425 c = self.load_default_context()
398 c = self.load_default_context()
426 c.user_group = user_group
399 c.user_group = user_group
427 c.active = 'global_perms'
400 c.active = 'global_perms'
428
401
429 try:
402 try:
430 # first stage that verifies the checkbox
403 # first stage that verifies the checkbox
431 _form = UserIndividualPermissionsForm(self.request.translate)
404 _form = UserIndividualPermissionsForm(self.request.translate)
432 form_result = _form.to_python(dict(self.request.POST))
405 form_result = _form.to_python(dict(self.request.POST))
433 inherit_perms = form_result['inherit_default_permissions']
406 inherit_perms = form_result['inherit_default_permissions']
434 user_group.inherit_default_permissions = inherit_perms
407 user_group.inherit_default_permissions = inherit_perms
435 Session().add(user_group)
408 Session().add(user_group)
436
409
437 if not inherit_perms:
410 if not inherit_perms:
438 # only update the individual ones if we un check the flag
411 # only update the individual ones if we un check the flag
439 _form = UserPermissionsForm(
412 _form = UserPermissionsForm(
440 self.request.translate,
413 self.request.translate,
441 [x[0] for x in c.repo_create_choices],
414 [x[0] for x in c.repo_create_choices],
442 [x[0] for x in c.repo_create_on_write_choices],
415 [x[0] for x in c.repo_create_on_write_choices],
443 [x[0] for x in c.repo_group_create_choices],
416 [x[0] for x in c.repo_group_create_choices],
444 [x[0] for x in c.user_group_create_choices],
417 [x[0] for x in c.user_group_create_choices],
445 [x[0] for x in c.fork_choices],
418 [x[0] for x in c.fork_choices],
446 [x[0] for x in c.inherit_default_permission_choices])()
419 [x[0] for x in c.inherit_default_permission_choices])()
447
420
448 form_result = _form.to_python(dict(self.request.POST))
421 form_result = _form.to_python(dict(self.request.POST))
449 form_result.update(
422 form_result.update(
450 {'perm_user_group_id': user_group.users_group_id})
423 {'perm_user_group_id': user_group.users_group_id})
451
424
452 PermissionModel().update_user_group_permissions(form_result)
425 PermissionModel().update_user_group_permissions(form_result)
453
426
454 Session().commit()
427 Session().commit()
455 h.flash(_('User Group global permissions updated successfully'),
428 h.flash(_('User Group global permissions updated successfully'),
456 category='success')
429 category='success')
457
430
458 except formencode.Invalid as errors:
431 except formencode.Invalid as errors:
459 defaults = errors.value
432 defaults = errors.value
460
433
461 data = render(
434 data = render(
462 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
435 'rhodecode:templates/admin/user_groups/user_group_edit.mako',
463 self._get_template_context(c), self.request)
436 self._get_template_context(c), self.request)
464 html = formencode.htmlfill.render(
437 html = formencode.htmlfill.render(
465 data,
438 data,
466 defaults=defaults,
439 defaults=defaults,
467 errors=errors.error_dict or {},
440 errors=errors.error_dict or {},
468 prefix_error=False,
441 prefix_error=False,
469 encoding="UTF-8",
442 encoding="UTF-8",
470 force_defaults=False
443 force_defaults=False
471 )
444 )
472 return Response(html)
445 return Response(html)
473 except Exception:
446 except Exception:
474 log.exception("Exception during permissions saving")
447 log.exception("Exception during permissions saving")
475 h.flash(_('An error occurred during permissions saving'),
448 h.flash(_('An error occurred during permissions saving'),
476 category='error')
449 category='error')
477
450
478 raise HTTPFound(
451 raise HTTPFound(
479 h.route_path('edit_user_group_global_perms',
452 h.route_path('edit_user_group_global_perms',
480 user_group_id=user_group_id))
453 user_group_id=user_group_id))
481
454
482 @LoginRequired()
455 @LoginRequired()
483 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
456 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
484 @view_config(
457 @view_config(
485 route_name='edit_user_group_advanced', request_method='GET',
458 route_name='edit_user_group_advanced', request_method='GET',
486 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
459 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
487 def user_group_edit_advanced(self):
460 def user_group_edit_advanced(self):
488 user_group = self.db_user_group
461 user_group = self.db_user_group
489
462
490 c = self.load_default_context()
463 c = self.load_default_context()
491 c.user_group = user_group
464 c.user_group = user_group
492 c.active = 'advanced'
465 c.active = 'advanced'
493 c.group_members_obj = sorted(
466 c.group_members_obj = sorted(
494 (x.user for x in c.user_group.members),
467 (x.user for x in c.user_group.members),
495 key=lambda u: u.username.lower())
468 key=lambda u: u.username.lower())
496
469
497 c.group_to_repos = sorted(
470 c.group_to_repos = sorted(
498 (x.repository for x in c.user_group.users_group_repo_to_perm),
471 (x.repository for x in c.user_group.users_group_repo_to_perm),
499 key=lambda u: u.repo_name.lower())
472 key=lambda u: u.repo_name.lower())
500
473
501 c.group_to_repo_groups = sorted(
474 c.group_to_repo_groups = sorted(
502 (x.group for x in c.user_group.users_group_repo_group_to_perm),
475 (x.group for x in c.user_group.users_group_repo_group_to_perm),
503 key=lambda u: u.group_name.lower())
476 key=lambda u: u.group_name.lower())
504
477
505 c.group_to_review_rules = sorted(
478 c.group_to_review_rules = sorted(
506 (x.users_group for x in c.user_group.user_group_review_rules),
479 (x.users_group for x in c.user_group.user_group_review_rules),
507 key=lambda u: u.users_group_name.lower())
480 key=lambda u: u.users_group_name.lower())
508
481
509 return self._get_template_context(c)
482 return self._get_template_context(c)
510
483
511 @LoginRequired()
484 @LoginRequired()
512 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
485 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
513 @CSRFRequired()
486 @CSRFRequired()
514 @view_config(
487 @view_config(
515 route_name='edit_user_group_advanced_sync', request_method='POST',
488 route_name='edit_user_group_advanced_sync', request_method='POST',
516 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
489 renderer='rhodecode:templates/admin/user_groups/user_group_edit.mako')
517 def user_group_edit_advanced_set_synchronization(self):
490 def user_group_edit_advanced_set_synchronization(self):
518 _ = self.request.translate
491 _ = self.request.translate
519 user_group = self.db_user_group
492 user_group = self.db_user_group
520 user_group_id = user_group.users_group_id
493 user_group_id = user_group.users_group_id
521
494
522 existing = user_group.group_data.get('extern_type')
495 existing = user_group.group_data.get('extern_type')
523
496
524 if existing:
497 if existing:
525 new_state = user_group.group_data
498 new_state = user_group.group_data
526 new_state['extern_type'] = None
499 new_state['extern_type'] = None
527 else:
500 else:
528 new_state = user_group.group_data
501 new_state = user_group.group_data
529 new_state['extern_type'] = 'manual'
502 new_state['extern_type'] = 'manual'
530 new_state['extern_type_set_by'] = self._rhodecode_user.username
503 new_state['extern_type_set_by'] = self._rhodecode_user.username
531
504
532 try:
505 try:
533 user_group.group_data = new_state
506 user_group.group_data = new_state
534 Session().add(user_group)
507 Session().add(user_group)
535 Session().commit()
508 Session().commit()
536
509
537 h.flash(_('User Group synchronization updated successfully'),
510 h.flash(_('User Group synchronization updated successfully'),
538 category='success')
511 category='success')
539 except Exception:
512 except Exception:
540 log.exception("Exception during sync settings saving")
513 log.exception("Exception during sync settings saving")
541 h.flash(_('An error occurred during synchronization update'),
514 h.flash(_('An error occurred during synchronization update'),
542 category='error')
515 category='error')
543
516
544 raise HTTPFound(
517 raise HTTPFound(
545 h.route_path('edit_user_group_advanced',
518 h.route_path('edit_user_group_advanced',
546 user_group_id=user_group_id))
519 user_group_id=user_group_id))
@@ -1,647 +1,673 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import traceback
22 import traceback
23
23
24 from rhodecode.lib.utils2 import safe_str, safe_unicode
24 from rhodecode.lib.utils2 import safe_str, safe_unicode
25 from rhodecode.lib.exceptions import (
25 from rhodecode.lib.exceptions import (
26 UserGroupAssignedException, RepoGroupAssignmentError)
26 UserGroupAssignedException, RepoGroupAssignmentError)
27 from rhodecode.lib.utils2 import (
27 from rhodecode.lib.utils2 import (
28 get_current_rhodecode_user, action_logger_generic)
28 get_current_rhodecode_user, action_logger_generic)
29 from rhodecode.model import BaseModel
29 from rhodecode.model import BaseModel
30 from rhodecode.model.scm import UserGroupList
30 from rhodecode.model.scm import UserGroupList
31 from rhodecode.model.db import (
31 from rhodecode.model.db import (
32 true, func, User, UserGroupMember, UserGroup,
32 joinedload, true, func, User, UserGroupMember, UserGroup,
33 UserGroupRepoToPerm, Permission, UserGroupToPerm, UserUserGroupToPerm,
33 UserGroupRepoToPerm, Permission, UserGroupToPerm, UserUserGroupToPerm,
34 UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm)
34 UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm)
35
35
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 class UserGroupModel(BaseModel):
40 class UserGroupModel(BaseModel):
41
41
42 cls = UserGroup
42 cls = UserGroup
43
43
44 def _get_user_group(self, user_group):
44 def _get_user_group(self, user_group):
45 return self._get_instance(UserGroup, user_group,
45 return self._get_instance(UserGroup, user_group,
46 callback=UserGroup.get_by_group_name)
46 callback=UserGroup.get_by_group_name)
47
47
48 def _create_default_perms(self, user_group):
48 def _create_default_perms(self, user_group):
49 # create default permission
49 # create default permission
50 default_perm = 'usergroup.read'
50 default_perm = 'usergroup.read'
51 def_user = User.get_default_user()
51 def_user = User.get_default_user()
52 for p in def_user.user_perms:
52 for p in def_user.user_perms:
53 if p.permission.permission_name.startswith('usergroup.'):
53 if p.permission.permission_name.startswith('usergroup.'):
54 default_perm = p.permission.permission_name
54 default_perm = p.permission.permission_name
55 break
55 break
56
56
57 user_group_to_perm = UserUserGroupToPerm()
57 user_group_to_perm = UserUserGroupToPerm()
58 user_group_to_perm.permission = Permission.get_by_key(default_perm)
58 user_group_to_perm.permission = Permission.get_by_key(default_perm)
59
59
60 user_group_to_perm.user_group = user_group
60 user_group_to_perm.user_group = user_group
61 user_group_to_perm.user_id = def_user.user_id
61 user_group_to_perm.user_id = def_user.user_id
62 return user_group_to_perm
62 return user_group_to_perm
63
63
64 def update_permissions(
64 def update_permissions(
65 self, user_group, perm_additions=None, perm_updates=None,
65 self, user_group, perm_additions=None, perm_updates=None,
66 perm_deletions=None, check_perms=True, cur_user=None):
66 perm_deletions=None, check_perms=True, cur_user=None):
67
67
68 from rhodecode.lib.auth import HasUserGroupPermissionAny
68 from rhodecode.lib.auth import HasUserGroupPermissionAny
69 if not perm_additions:
69 if not perm_additions:
70 perm_additions = []
70 perm_additions = []
71 if not perm_updates:
71 if not perm_updates:
72 perm_updates = []
72 perm_updates = []
73 if not perm_deletions:
73 if not perm_deletions:
74 perm_deletions = []
74 perm_deletions = []
75
75
76 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
76 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
77
77
78 changes = {
78 changes = {
79 'added': [],
79 'added': [],
80 'updated': [],
80 'updated': [],
81 'deleted': []
81 'deleted': []
82 }
82 }
83 # update permissions
83 # update permissions
84 for member_id, perm, member_type in perm_updates:
84 for member_id, perm, member_type in perm_updates:
85 member_id = int(member_id)
85 member_id = int(member_id)
86 if member_type == 'user':
86 if member_type == 'user':
87 member_name = User.get(member_id).username
87 member_name = User.get(member_id).username
88 # this updates existing one
88 # this updates existing one
89 self.grant_user_permission(
89 self.grant_user_permission(
90 user_group=user_group, user=member_id, perm=perm
90 user_group=user_group, user=member_id, perm=perm
91 )
91 )
92 else:
92 else:
93 # check if we have permissions to alter this usergroup
93 # check if we have permissions to alter this usergroup
94 member_name = UserGroup.get(member_id).users_group_name
94 member_name = UserGroup.get(member_id).users_group_name
95 if not check_perms or HasUserGroupPermissionAny(
95 if not check_perms or HasUserGroupPermissionAny(
96 *req_perms)(member_name, user=cur_user):
96 *req_perms)(member_name, user=cur_user):
97 self.grant_user_group_permission(
97 self.grant_user_group_permission(
98 target_user_group=user_group, user_group=member_id, perm=perm)
98 target_user_group=user_group, user_group=member_id, perm=perm)
99
99
100 changes['updated'].append({'type': member_type, 'id': member_id,
100 changes['updated'].append({'type': member_type, 'id': member_id,
101 'name': member_name, 'new_perm': perm})
101 'name': member_name, 'new_perm': perm})
102
102
103 # set new permissions
103 # set new permissions
104 for member_id, perm, member_type in perm_additions:
104 for member_id, perm, member_type in perm_additions:
105 member_id = int(member_id)
105 member_id = int(member_id)
106 if member_type == 'user':
106 if member_type == 'user':
107 member_name = User.get(member_id).username
107 member_name = User.get(member_id).username
108 self.grant_user_permission(
108 self.grant_user_permission(
109 user_group=user_group, user=member_id, perm=perm)
109 user_group=user_group, user=member_id, perm=perm)
110 else:
110 else:
111 # check if we have permissions to alter this usergroup
111 # check if we have permissions to alter this usergroup
112 member_name = UserGroup.get(member_id).users_group_name
112 member_name = UserGroup.get(member_id).users_group_name
113 if not check_perms or HasUserGroupPermissionAny(
113 if not check_perms or HasUserGroupPermissionAny(
114 *req_perms)(member_name, user=cur_user):
114 *req_perms)(member_name, user=cur_user):
115 self.grant_user_group_permission(
115 self.grant_user_group_permission(
116 target_user_group=user_group, user_group=member_id, perm=perm)
116 target_user_group=user_group, user_group=member_id, perm=perm)
117
117
118 changes['added'].append({'type': member_type, 'id': member_id,
118 changes['added'].append({'type': member_type, 'id': member_id,
119 'name': member_name, 'new_perm': perm})
119 'name': member_name, 'new_perm': perm})
120
120
121 # delete permissions
121 # delete permissions
122 for member_id, perm, member_type in perm_deletions:
122 for member_id, perm, member_type in perm_deletions:
123 member_id = int(member_id)
123 member_id = int(member_id)
124 if member_type == 'user':
124 if member_type == 'user':
125 member_name = User.get(member_id).username
125 member_name = User.get(member_id).username
126 self.revoke_user_permission(user_group=user_group, user=member_id)
126 self.revoke_user_permission(user_group=user_group, user=member_id)
127 else:
127 else:
128 # check if we have permissions to alter this usergroup
128 # check if we have permissions to alter this usergroup
129 member_name = UserGroup.get(member_id).users_group_name
129 member_name = UserGroup.get(member_id).users_group_name
130 if not check_perms or HasUserGroupPermissionAny(
130 if not check_perms or HasUserGroupPermissionAny(
131 *req_perms)(member_name, user=cur_user):
131 *req_perms)(member_name, user=cur_user):
132 self.revoke_user_group_permission(
132 self.revoke_user_group_permission(
133 target_user_group=user_group, user_group=member_id)
133 target_user_group=user_group, user_group=member_id)
134
134
135 changes['deleted'].append({'type': member_type, 'id': member_id,
135 changes['deleted'].append({'type': member_type, 'id': member_id,
136 'name': member_name, 'new_perm': perm})
136 'name': member_name, 'new_perm': perm})
137 return changes
137 return changes
138
138
139 def get(self, user_group_id, cache=False):
139 def get(self, user_group_id, cache=False):
140 return UserGroup.get(user_group_id)
140 return UserGroup.get(user_group_id)
141
141
142 def get_group(self, user_group):
142 def get_group(self, user_group):
143 return self._get_user_group(user_group)
143 return self._get_user_group(user_group)
144
144
145 def get_by_name(self, name, cache=False, case_insensitive=False):
145 def get_by_name(self, name, cache=False, case_insensitive=False):
146 return UserGroup.get_by_group_name(name, cache, case_insensitive)
146 return UserGroup.get_by_group_name(name, cache, case_insensitive)
147
147
148 def create(self, name, description, owner, active=True, group_data=None):
148 def create(self, name, description, owner, active=True, group_data=None):
149 try:
149 try:
150 new_user_group = UserGroup()
150 new_user_group = UserGroup()
151 new_user_group.user = self._get_user(owner)
151 new_user_group.user = self._get_user(owner)
152 new_user_group.users_group_name = name
152 new_user_group.users_group_name = name
153 new_user_group.user_group_description = description
153 new_user_group.user_group_description = description
154 new_user_group.users_group_active = active
154 new_user_group.users_group_active = active
155 if group_data:
155 if group_data:
156 new_user_group.group_data = group_data
156 new_user_group.group_data = group_data
157 self.sa.add(new_user_group)
157 self.sa.add(new_user_group)
158 perm_obj = self._create_default_perms(new_user_group)
158 perm_obj = self._create_default_perms(new_user_group)
159 self.sa.add(perm_obj)
159 self.sa.add(perm_obj)
160
160
161 self.grant_user_permission(user_group=new_user_group,
161 self.grant_user_permission(user_group=new_user_group,
162 user=owner, perm='usergroup.admin')
162 user=owner, perm='usergroup.admin')
163
163
164 return new_user_group
164 return new_user_group
165 except Exception:
165 except Exception:
166 log.error(traceback.format_exc())
166 log.error(traceback.format_exc())
167 raise
167 raise
168
168
169 def _get_memberships_for_user_ids(self, user_group, user_id_list):
169 def _get_memberships_for_user_ids(self, user_group, user_id_list):
170 members = []
170 members = []
171 for user_id in user_id_list:
171 for user_id in user_id_list:
172 member = self._get_membership(user_group.users_group_id, user_id)
172 member = self._get_membership(user_group.users_group_id, user_id)
173 members.append(member)
173 members.append(member)
174 return members
174 return members
175
175
176 def _get_added_and_removed_user_ids(self, user_group, user_id_list):
176 def _get_added_and_removed_user_ids(self, user_group, user_id_list):
177 current_members = user_group.members or []
177 current_members = user_group.members or []
178 current_members_ids = [m.user.user_id for m in current_members]
178 current_members_ids = [m.user.user_id for m in current_members]
179
179
180 added_members = [
180 added_members = [
181 user_id for user_id in user_id_list
181 user_id for user_id in user_id_list
182 if user_id not in current_members_ids]
182 if user_id not in current_members_ids]
183 if user_id_list == []:
183 if user_id_list == []:
184 # all members were deleted
184 # all members were deleted
185 deleted_members = current_members_ids
185 deleted_members = current_members_ids
186 else:
186 else:
187 deleted_members = [
187 deleted_members = [
188 user_id for user_id in current_members_ids
188 user_id for user_id in current_members_ids
189 if user_id not in user_id_list]
189 if user_id not in user_id_list]
190
190
191 return added_members, deleted_members
191 return added_members, deleted_members
192
192
193 def _set_users_as_members(self, user_group, user_ids):
193 def _set_users_as_members(self, user_group, user_ids):
194 user_group.members = []
194 user_group.members = []
195 self.sa.flush()
195 self.sa.flush()
196 members = self._get_memberships_for_user_ids(
196 members = self._get_memberships_for_user_ids(
197 user_group, user_ids)
197 user_group, user_ids)
198 user_group.members = members
198 user_group.members = members
199 self.sa.add(user_group)
199 self.sa.add(user_group)
200
200
201 def _update_members_from_user_ids(self, user_group, user_ids):
201 def _update_members_from_user_ids(self, user_group, user_ids):
202 added, removed = self._get_added_and_removed_user_ids(
202 added, removed = self._get_added_and_removed_user_ids(
203 user_group, user_ids)
203 user_group, user_ids)
204 self._set_users_as_members(user_group, user_ids)
204 self._set_users_as_members(user_group, user_ids)
205 self._log_user_changes('added to', user_group, added)
205 self._log_user_changes('added to', user_group, added)
206 self._log_user_changes('removed from', user_group, removed)
206 self._log_user_changes('removed from', user_group, removed)
207 return added, removed
207 return added, removed
208
208
209 def _clean_members_data(self, members_data):
209 def _clean_members_data(self, members_data):
210 if not members_data:
210 if not members_data:
211 members_data = []
211 members_data = []
212
212
213 members = []
213 members = []
214 for user in members_data:
214 for user in members_data:
215 uid = int(user['member_user_id'])
215 uid = int(user['member_user_id'])
216 if uid not in members and user['type'] in ['new', 'existing']:
216 if uid not in members and user['type'] in ['new', 'existing']:
217 members.append(uid)
217 members.append(uid)
218 return members
218 return members
219
219
220 def update(self, user_group, form_data):
220 def update(self, user_group, form_data):
221 user_group = self._get_user_group(user_group)
221 user_group = self._get_user_group(user_group)
222 if 'users_group_name' in form_data:
222 if 'users_group_name' in form_data:
223 user_group.users_group_name = form_data['users_group_name']
223 user_group.users_group_name = form_data['users_group_name']
224 if 'users_group_active' in form_data:
224 if 'users_group_active' in form_data:
225 user_group.users_group_active = form_data['users_group_active']
225 user_group.users_group_active = form_data['users_group_active']
226 if 'user_group_description' in form_data:
226 if 'user_group_description' in form_data:
227 user_group.user_group_description = form_data[
227 user_group.user_group_description = form_data[
228 'user_group_description']
228 'user_group_description']
229
229
230 # handle owner change
230 # handle owner change
231 if 'user' in form_data:
231 if 'user' in form_data:
232 owner = form_data['user']
232 owner = form_data['user']
233 if isinstance(owner, basestring):
233 if isinstance(owner, basestring):
234 owner = User.get_by_username(form_data['user'])
234 owner = User.get_by_username(form_data['user'])
235
235
236 if not isinstance(owner, User):
236 if not isinstance(owner, User):
237 raise ValueError(
237 raise ValueError(
238 'invalid owner for user group: %s' % form_data['user'])
238 'invalid owner for user group: %s' % form_data['user'])
239
239
240 user_group.user = owner
240 user_group.user = owner
241
241
242 added_user_ids = []
242 added_user_ids = []
243 removed_user_ids = []
243 removed_user_ids = []
244 if 'users_group_members' in form_data:
244 if 'users_group_members' in form_data:
245 members_id_list = self._clean_members_data(
245 members_id_list = self._clean_members_data(
246 form_data['users_group_members'])
246 form_data['users_group_members'])
247 added_user_ids, removed_user_ids = \
247 added_user_ids, removed_user_ids = \
248 self._update_members_from_user_ids(user_group, members_id_list)
248 self._update_members_from_user_ids(user_group, members_id_list)
249
249
250 self.sa.add(user_group)
250 self.sa.add(user_group)
251 return user_group, added_user_ids, removed_user_ids
251 return user_group, added_user_ids, removed_user_ids
252
252
253 def delete(self, user_group, force=False):
253 def delete(self, user_group, force=False):
254 """
254 """
255 Deletes repository group, unless force flag is used
255 Deletes repository group, unless force flag is used
256 raises exception if there are members in that group, else deletes
256 raises exception if there are members in that group, else deletes
257 group and users
257 group and users
258
258
259 :param user_group:
259 :param user_group:
260 :param force:
260 :param force:
261 """
261 """
262 user_group = self._get_user_group(user_group)
262 user_group = self._get_user_group(user_group)
263 if not user_group:
263 if not user_group:
264 return
264 return
265
265
266 try:
266 try:
267 # check if this group is not assigned to repo
267 # check if this group is not assigned to repo
268 assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\
268 assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\
269 .filter(UserGroupRepoToPerm.users_group == user_group).all()]
269 .filter(UserGroupRepoToPerm.users_group == user_group).all()]
270 # check if this group is not assigned to repo
270 # check if this group is not assigned to repo
271 assigned_to_repo_group = [x.group for x in UserGroupRepoGroupToPerm.query()\
271 assigned_to_repo_group = [x.group for x in UserGroupRepoGroupToPerm.query()\
272 .filter(UserGroupRepoGroupToPerm.users_group == user_group).all()]
272 .filter(UserGroupRepoGroupToPerm.users_group == user_group).all()]
273
273
274 if (assigned_to_repo or assigned_to_repo_group) and not force:
274 if (assigned_to_repo or assigned_to_repo_group) and not force:
275 assigned = ','.join(map(safe_str,
275 assigned = ','.join(map(safe_str,
276 assigned_to_repo+assigned_to_repo_group))
276 assigned_to_repo+assigned_to_repo_group))
277
277
278 raise UserGroupAssignedException(
278 raise UserGroupAssignedException(
279 'UserGroup assigned to %s' % (assigned,))
279 'UserGroup assigned to %s' % (assigned,))
280 self.sa.delete(user_group)
280 self.sa.delete(user_group)
281 except Exception:
281 except Exception:
282 log.error(traceback.format_exc())
282 log.error(traceback.format_exc())
283 raise
283 raise
284
284
285 def _log_user_changes(self, action, user_group, user_or_users):
285 def _log_user_changes(self, action, user_group, user_or_users):
286 users = user_or_users
286 users = user_or_users
287 if not isinstance(users, (list, tuple)):
287 if not isinstance(users, (list, tuple)):
288 users = [users]
288 users = [users]
289
289
290 group_name = user_group.users_group_name
290 group_name = user_group.users_group_name
291
291
292 for user_or_user_id in users:
292 for user_or_user_id in users:
293 user = self._get_user(user_or_user_id)
293 user = self._get_user(user_or_user_id)
294 log_text = 'User {user} {action} {group}'.format(
294 log_text = 'User {user} {action} {group}'.format(
295 action=action, user=user.username, group=group_name)
295 action=action, user=user.username, group=group_name)
296 action_logger_generic(log_text)
296 action_logger_generic(log_text)
297
297
298 def _find_user_in_group(self, user, user_group):
298 def _find_user_in_group(self, user, user_group):
299 user_group_member = None
299 user_group_member = None
300 for m in user_group.members:
300 for m in user_group.members:
301 if m.user_id == user.user_id:
301 if m.user_id == user.user_id:
302 # Found this user's membership row
302 # Found this user's membership row
303 user_group_member = m
303 user_group_member = m
304 break
304 break
305
305
306 return user_group_member
306 return user_group_member
307
307
308 def _get_membership(self, user_group_id, user_id):
308 def _get_membership(self, user_group_id, user_id):
309 user_group_member = UserGroupMember(user_group_id, user_id)
309 user_group_member = UserGroupMember(user_group_id, user_id)
310 return user_group_member
310 return user_group_member
311
311
312 def add_user_to_group(self, user_group, user):
312 def add_user_to_group(self, user_group, user):
313 user_group = self._get_user_group(user_group)
313 user_group = self._get_user_group(user_group)
314 user = self._get_user(user)
314 user = self._get_user(user)
315 user_member = self._find_user_in_group(user, user_group)
315 user_member = self._find_user_in_group(user, user_group)
316 if user_member:
316 if user_member:
317 # user already in the group, skip
317 # user already in the group, skip
318 return True
318 return True
319
319
320 member = self._get_membership(
320 member = self._get_membership(
321 user_group.users_group_id, user.user_id)
321 user_group.users_group_id, user.user_id)
322 user_group.members.append(member)
322 user_group.members.append(member)
323
323
324 try:
324 try:
325 self.sa.add(member)
325 self.sa.add(member)
326 except Exception:
326 except Exception:
327 # what could go wrong here?
327 # what could go wrong here?
328 log.error(traceback.format_exc())
328 log.error(traceback.format_exc())
329 raise
329 raise
330
330
331 self._log_user_changes('added to', user_group, user)
331 self._log_user_changes('added to', user_group, user)
332 return member
332 return member
333
333
334 def remove_user_from_group(self, user_group, user):
334 def remove_user_from_group(self, user_group, user):
335 user_group = self._get_user_group(user_group)
335 user_group = self._get_user_group(user_group)
336 user = self._get_user(user)
336 user = self._get_user(user)
337 user_group_member = self._find_user_in_group(user, user_group)
337 user_group_member = self._find_user_in_group(user, user_group)
338
338
339 if not user_group_member:
339 if not user_group_member:
340 # User isn't in that group
340 # User isn't in that group
341 return False
341 return False
342
342
343 try:
343 try:
344 self.sa.delete(user_group_member)
344 self.sa.delete(user_group_member)
345 except Exception:
345 except Exception:
346 log.error(traceback.format_exc())
346 log.error(traceback.format_exc())
347 raise
347 raise
348
348
349 self._log_user_changes('removed from', user_group, user)
349 self._log_user_changes('removed from', user_group, user)
350 return True
350 return True
351
351
352 def has_perm(self, user_group, perm):
352 def has_perm(self, user_group, perm):
353 user_group = self._get_user_group(user_group)
353 user_group = self._get_user_group(user_group)
354 perm = self._get_perm(perm)
354 perm = self._get_perm(perm)
355
355
356 return UserGroupToPerm.query()\
356 return UserGroupToPerm.query()\
357 .filter(UserGroupToPerm.users_group == user_group)\
357 .filter(UserGroupToPerm.users_group == user_group)\
358 .filter(UserGroupToPerm.permission == perm).scalar() is not None
358 .filter(UserGroupToPerm.permission == perm).scalar() is not None
359
359
360 def grant_perm(self, user_group, perm):
360 def grant_perm(self, user_group, perm):
361 user_group = self._get_user_group(user_group)
361 user_group = self._get_user_group(user_group)
362 perm = self._get_perm(perm)
362 perm = self._get_perm(perm)
363
363
364 # if this permission is already granted skip it
364 # if this permission is already granted skip it
365 _perm = UserGroupToPerm.query()\
365 _perm = UserGroupToPerm.query()\
366 .filter(UserGroupToPerm.users_group == user_group)\
366 .filter(UserGroupToPerm.users_group == user_group)\
367 .filter(UserGroupToPerm.permission == perm)\
367 .filter(UserGroupToPerm.permission == perm)\
368 .scalar()
368 .scalar()
369 if _perm:
369 if _perm:
370 return
370 return
371
371
372 new = UserGroupToPerm()
372 new = UserGroupToPerm()
373 new.users_group = user_group
373 new.users_group = user_group
374 new.permission = perm
374 new.permission = perm
375 self.sa.add(new)
375 self.sa.add(new)
376 return new
376 return new
377
377
378 def revoke_perm(self, user_group, perm):
378 def revoke_perm(self, user_group, perm):
379 user_group = self._get_user_group(user_group)
379 user_group = self._get_user_group(user_group)
380 perm = self._get_perm(perm)
380 perm = self._get_perm(perm)
381
381
382 obj = UserGroupToPerm.query()\
382 obj = UserGroupToPerm.query()\
383 .filter(UserGroupToPerm.users_group == user_group)\
383 .filter(UserGroupToPerm.users_group == user_group)\
384 .filter(UserGroupToPerm.permission == perm).scalar()
384 .filter(UserGroupToPerm.permission == perm).scalar()
385 if obj:
385 if obj:
386 self.sa.delete(obj)
386 self.sa.delete(obj)
387
387
388 def grant_user_permission(self, user_group, user, perm):
388 def grant_user_permission(self, user_group, user, perm):
389 """
389 """
390 Grant permission for user on given user group, or update
390 Grant permission for user on given user group, or update
391 existing one if found
391 existing one if found
392
392
393 :param user_group: Instance of UserGroup, users_group_id,
393 :param user_group: Instance of UserGroup, users_group_id,
394 or users_group_name
394 or users_group_name
395 :param user: Instance of User, user_id or username
395 :param user: Instance of User, user_id or username
396 :param perm: Instance of Permission, or permission_name
396 :param perm: Instance of Permission, or permission_name
397 """
397 """
398
398
399 user_group = self._get_user_group(user_group)
399 user_group = self._get_user_group(user_group)
400 user = self._get_user(user)
400 user = self._get_user(user)
401 permission = self._get_perm(perm)
401 permission = self._get_perm(perm)
402
402
403 # check if we have that permission already
403 # check if we have that permission already
404 obj = self.sa.query(UserUserGroupToPerm)\
404 obj = self.sa.query(UserUserGroupToPerm)\
405 .filter(UserUserGroupToPerm.user == user)\
405 .filter(UserUserGroupToPerm.user == user)\
406 .filter(UserUserGroupToPerm.user_group == user_group)\
406 .filter(UserUserGroupToPerm.user_group == user_group)\
407 .scalar()
407 .scalar()
408 if obj is None:
408 if obj is None:
409 # create new !
409 # create new !
410 obj = UserUserGroupToPerm()
410 obj = UserUserGroupToPerm()
411 obj.user_group = user_group
411 obj.user_group = user_group
412 obj.user = user
412 obj.user = user
413 obj.permission = permission
413 obj.permission = permission
414 self.sa.add(obj)
414 self.sa.add(obj)
415 log.debug('Granted perm %s to %s on %s', perm, user, user_group)
415 log.debug('Granted perm %s to %s on %s', perm, user, user_group)
416 action_logger_generic(
416 action_logger_generic(
417 'granted permission: {} to user: {} on usergroup: {}'.format(
417 'granted permission: {} to user: {} on usergroup: {}'.format(
418 perm, user, user_group), namespace='security.usergroup')
418 perm, user, user_group), namespace='security.usergroup')
419
419
420 return obj
420 return obj
421
421
422 def revoke_user_permission(self, user_group, user):
422 def revoke_user_permission(self, user_group, user):
423 """
423 """
424 Revoke permission for user on given user group
424 Revoke permission for user on given user group
425
425
426 :param user_group: Instance of UserGroup, users_group_id,
426 :param user_group: Instance of UserGroup, users_group_id,
427 or users_group name
427 or users_group name
428 :param user: Instance of User, user_id or username
428 :param user: Instance of User, user_id or username
429 """
429 """
430
430
431 user_group = self._get_user_group(user_group)
431 user_group = self._get_user_group(user_group)
432 user = self._get_user(user)
432 user = self._get_user(user)
433
433
434 obj = self.sa.query(UserUserGroupToPerm)\
434 obj = self.sa.query(UserUserGroupToPerm)\
435 .filter(UserUserGroupToPerm.user == user)\
435 .filter(UserUserGroupToPerm.user == user)\
436 .filter(UserUserGroupToPerm.user_group == user_group)\
436 .filter(UserUserGroupToPerm.user_group == user_group)\
437 .scalar()
437 .scalar()
438 if obj:
438 if obj:
439 self.sa.delete(obj)
439 self.sa.delete(obj)
440 log.debug('Revoked perm on %s on %s', user_group, user)
440 log.debug('Revoked perm on %s on %s', user_group, user)
441 action_logger_generic(
441 action_logger_generic(
442 'revoked permission from user: {} on usergroup: {}'.format(
442 'revoked permission from user: {} on usergroup: {}'.format(
443 user, user_group), namespace='security.usergroup')
443 user, user_group), namespace='security.usergroup')
444
444
445 def grant_user_group_permission(self, target_user_group, user_group, perm):
445 def grant_user_group_permission(self, target_user_group, user_group, perm):
446 """
446 """
447 Grant user group permission for given target_user_group
447 Grant user group permission for given target_user_group
448
448
449 :param target_user_group:
449 :param target_user_group:
450 :param user_group:
450 :param user_group:
451 :param perm:
451 :param perm:
452 """
452 """
453 target_user_group = self._get_user_group(target_user_group)
453 target_user_group = self._get_user_group(target_user_group)
454 user_group = self._get_user_group(user_group)
454 user_group = self._get_user_group(user_group)
455 permission = self._get_perm(perm)
455 permission = self._get_perm(perm)
456 # forbid assigning same user group to itself
456 # forbid assigning same user group to itself
457 if target_user_group == user_group:
457 if target_user_group == user_group:
458 raise RepoGroupAssignmentError('target repo:%s cannot be '
458 raise RepoGroupAssignmentError('target repo:%s cannot be '
459 'assigned to itself' % target_user_group)
459 'assigned to itself' % target_user_group)
460
460
461 # check if we have that permission already
461 # check if we have that permission already
462 obj = self.sa.query(UserGroupUserGroupToPerm)\
462 obj = self.sa.query(UserGroupUserGroupToPerm)\
463 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
463 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
464 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
464 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
465 .scalar()
465 .scalar()
466 if obj is None:
466 if obj is None:
467 # create new !
467 # create new !
468 obj = UserGroupUserGroupToPerm()
468 obj = UserGroupUserGroupToPerm()
469 obj.user_group = user_group
469 obj.user_group = user_group
470 obj.target_user_group = target_user_group
470 obj.target_user_group = target_user_group
471 obj.permission = permission
471 obj.permission = permission
472 self.sa.add(obj)
472 self.sa.add(obj)
473 log.debug(
473 log.debug(
474 'Granted perm %s to %s on %s', perm, target_user_group, user_group)
474 'Granted perm %s to %s on %s', perm, target_user_group, user_group)
475 action_logger_generic(
475 action_logger_generic(
476 'granted permission: {} to usergroup: {} on usergroup: {}'.format(
476 'granted permission: {} to usergroup: {} on usergroup: {}'.format(
477 perm, user_group, target_user_group),
477 perm, user_group, target_user_group),
478 namespace='security.usergroup')
478 namespace='security.usergroup')
479
479
480 return obj
480 return obj
481
481
482 def revoke_user_group_permission(self, target_user_group, user_group):
482 def revoke_user_group_permission(self, target_user_group, user_group):
483 """
483 """
484 Revoke user group permission for given target_user_group
484 Revoke user group permission for given target_user_group
485
485
486 :param target_user_group:
486 :param target_user_group:
487 :param user_group:
487 :param user_group:
488 """
488 """
489 target_user_group = self._get_user_group(target_user_group)
489 target_user_group = self._get_user_group(target_user_group)
490 user_group = self._get_user_group(user_group)
490 user_group = self._get_user_group(user_group)
491
491
492 obj = self.sa.query(UserGroupUserGroupToPerm)\
492 obj = self.sa.query(UserGroupUserGroupToPerm)\
493 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
493 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
494 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
494 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
495 .scalar()
495 .scalar()
496 if obj:
496 if obj:
497 self.sa.delete(obj)
497 self.sa.delete(obj)
498 log.debug(
498 log.debug(
499 'Revoked perm on %s on %s', target_user_group, user_group)
499 'Revoked perm on %s on %s', target_user_group, user_group)
500 action_logger_generic(
500 action_logger_generic(
501 'revoked permission from usergroup: {} on usergroup: {}'.format(
501 'revoked permission from usergroup: {} on usergroup: {}'.format(
502 user_group, target_user_group),
502 user_group, target_user_group),
503 namespace='security.repogroup')
503 namespace='security.repogroup')
504
504
505 def get_perms_summary(self, user_group_id):
506 permissions = {
507 'repositories': {},
508 'repositories_groups': {},
509 }
510 ugroup_repo_perms = UserGroupRepoToPerm.query()\
511 .options(joinedload(UserGroupRepoToPerm.permission))\
512 .options(joinedload(UserGroupRepoToPerm.repository))\
513 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
514 .all()
515
516 for gr in ugroup_repo_perms:
517 permissions['repositories'][gr.repository.repo_name] \
518 = gr.permission.permission_name
519
520 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
521 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
522 .options(joinedload(UserGroupRepoGroupToPerm.group))\
523 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
524 .all()
525
526 for gr in ugroup_group_perms:
527 permissions['repositories_groups'][gr.group.group_name] \
528 = gr.permission.permission_name
529 return permissions
530
505 def enforce_groups(self, user, groups, extern_type=None):
531 def enforce_groups(self, user, groups, extern_type=None):
506 user = self._get_user(user)
532 user = self._get_user(user)
507 current_groups = user.group_member
533 current_groups = user.group_member
508
534
509 # find the external created groups, i.e automatically created
535 # find the external created groups, i.e automatically created
510 log.debug('Enforcing user group set `%s` on user %s', groups, user)
536 log.debug('Enforcing user group set `%s` on user %s', groups, user)
511 # calculate from what groups user should be removed
537 # calculate from what groups user should be removed
512 # external_groups that are not in groups
538 # external_groups that are not in groups
513 for gr in [x.users_group for x in current_groups]:
539 for gr in [x.users_group for x in current_groups]:
514 managed = gr.group_data.get('extern_type')
540 managed = gr.group_data.get('extern_type')
515 if managed:
541 if managed:
516 if gr.users_group_name not in groups:
542 if gr.users_group_name not in groups:
517 log.debug('Removing user %s from user group %s. '
543 log.debug('Removing user %s from user group %s. '
518 'Group sync managed by: %s', user, gr, managed)
544 'Group sync managed by: %s', user, gr, managed)
519 self.remove_user_from_group(gr, user)
545 self.remove_user_from_group(gr, user)
520 else:
546 else:
521 log.debug('Skipping removal from group %s since it is '
547 log.debug('Skipping removal from group %s since it is '
522 'not set to be automatically synchronized' % gr)
548 'not set to be automatically synchronized' % gr)
523
549
524 # now we calculate in which groups user should be == groups params
550 # now we calculate in which groups user should be == groups params
525 owner = User.get_first_super_admin().username
551 owner = User.get_first_super_admin().username
526 for gr in set(groups):
552 for gr in set(groups):
527 existing_group = UserGroup.get_by_group_name(gr)
553 existing_group = UserGroup.get_by_group_name(gr)
528 if not existing_group:
554 if not existing_group:
529 desc = 'Automatically created from plugin:%s' % extern_type
555 desc = 'Automatically created from plugin:%s' % extern_type
530 # we use first admin account to set the owner of the group
556 # we use first admin account to set the owner of the group
531 existing_group = UserGroupModel().create(
557 existing_group = UserGroupModel().create(
532 gr, desc, owner, group_data={'extern_type': extern_type})
558 gr, desc, owner, group_data={'extern_type': extern_type})
533
559
534 # we can only add users to groups which have set sync flag via
560 # we can only add users to groups which have set sync flag via
535 # extern_type attribute.
561 # extern_type attribute.
536 # This is either set and created via plugins, or manually
562 # This is either set and created via plugins, or manually
537 managed = existing_group.group_data.get('extern_type')
563 managed = existing_group.group_data.get('extern_type')
538 if managed:
564 if managed:
539 log.debug('Adding user %s to user group %s', user, gr)
565 log.debug('Adding user %s to user group %s', user, gr)
540 UserGroupModel().add_user_to_group(existing_group, user)
566 UserGroupModel().add_user_to_group(existing_group, user)
541 else:
567 else:
542 log.debug('Skipping addition to group %s since it is '
568 log.debug('Skipping addition to group %s since it is '
543 'not set to be automatically synchronized' % gr)
569 'not set to be automatically synchronized' % gr)
544
570
545 def change_groups(self, user, groups):
571 def change_groups(self, user, groups):
546 """
572 """
547 This method changes user group assignment
573 This method changes user group assignment
548 :param user: User
574 :param user: User
549 :param groups: array of UserGroupModel
575 :param groups: array of UserGroupModel
550 """
576 """
551 user = self._get_user(user)
577 user = self._get_user(user)
552 log.debug('Changing user(%s) assignment to groups(%s)', user, groups)
578 log.debug('Changing user(%s) assignment to groups(%s)', user, groups)
553 current_groups = user.group_member
579 current_groups = user.group_member
554 current_groups = [x.users_group for x in current_groups]
580 current_groups = [x.users_group for x in current_groups]
555
581
556 # calculate from what groups user should be removed/add
582 # calculate from what groups user should be removed/add
557 groups = set(groups)
583 groups = set(groups)
558 current_groups = set(current_groups)
584 current_groups = set(current_groups)
559
585
560 groups_to_remove = current_groups - groups
586 groups_to_remove = current_groups - groups
561 groups_to_add = groups - current_groups
587 groups_to_add = groups - current_groups
562
588
563 removed_from_groups = []
589 removed_from_groups = []
564 added_to_groups = []
590 added_to_groups = []
565 for gr in groups_to_remove:
591 for gr in groups_to_remove:
566 log.debug('Removing user %s from user group %s',
592 log.debug('Removing user %s from user group %s',
567 user.username, gr.users_group_name)
593 user.username, gr.users_group_name)
568 removed_from_groups.append(gr.users_group_id)
594 removed_from_groups.append(gr.users_group_id)
569 self.remove_user_from_group(gr.users_group_name, user.username)
595 self.remove_user_from_group(gr.users_group_name, user.username)
570 for gr in groups_to_add:
596 for gr in groups_to_add:
571 log.debug('Adding user %s to user group %s',
597 log.debug('Adding user %s to user group %s',
572 user.username, gr.users_group_name)
598 user.username, gr.users_group_name)
573 added_to_groups.append(gr.users_group_id)
599 added_to_groups.append(gr.users_group_id)
574 UserGroupModel().add_user_to_group(
600 UserGroupModel().add_user_to_group(
575 gr.users_group_name, user.username)
601 gr.users_group_name, user.username)
576
602
577 return added_to_groups, removed_from_groups
603 return added_to_groups, removed_from_groups
578
604
579 def _serialize_user_group(self, user_group):
605 def _serialize_user_group(self, user_group):
580 import rhodecode.lib.helpers as h
606 import rhodecode.lib.helpers as h
581 return {
607 return {
582 'id': user_group.users_group_id,
608 'id': user_group.users_group_id,
583 # TODO: marcink figure out a way to generate the url for the
609 # TODO: marcink figure out a way to generate the url for the
584 # icon
610 # icon
585 'icon_link': '',
611 'icon_link': '',
586 'value_display': 'Group: %s (%d members)' % (
612 'value_display': 'Group: %s (%d members)' % (
587 user_group.users_group_name, len(user_group.members),),
613 user_group.users_group_name, len(user_group.members),),
588 'value': user_group.users_group_name,
614 'value': user_group.users_group_name,
589 'description': user_group.user_group_description,
615 'description': user_group.user_group_description,
590 'owner': user_group.user.username,
616 'owner': user_group.user.username,
591
617
592 'owner_icon': h.gravatar_url(user_group.user.email, 30),
618 'owner_icon': h.gravatar_url(user_group.user.email, 30),
593 'value_display_owner': h.person(user_group.user.email),
619 'value_display_owner': h.person(user_group.user.email),
594
620
595 'value_type': 'user_group',
621 'value_type': 'user_group',
596 'active': user_group.users_group_active,
622 'active': user_group.users_group_active,
597 }
623 }
598
624
599 def get_user_groups(self, name_contains=None, limit=20, only_active=True,
625 def get_user_groups(self, name_contains=None, limit=20, only_active=True,
600 expand_groups=False):
626 expand_groups=False):
601 query = self.sa.query(UserGroup)
627 query = self.sa.query(UserGroup)
602 if only_active:
628 if only_active:
603 query = query.filter(UserGroup.users_group_active == true())
629 query = query.filter(UserGroup.users_group_active == true())
604
630
605 if name_contains:
631 if name_contains:
606 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
632 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
607 query = query.filter(
633 query = query.filter(
608 UserGroup.users_group_name.ilike(ilike_expression))\
634 UserGroup.users_group_name.ilike(ilike_expression))\
609 .order_by(func.length(UserGroup.users_group_name))\
635 .order_by(func.length(UserGroup.users_group_name))\
610 .order_by(UserGroup.users_group_name)
636 .order_by(UserGroup.users_group_name)
611
637
612 query = query.limit(limit)
638 query = query.limit(limit)
613 user_groups = query.all()
639 user_groups = query.all()
614 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
640 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
615 user_groups = UserGroupList(user_groups, perm_set=perm_set)
641 user_groups = UserGroupList(user_groups, perm_set=perm_set)
616
642
617 # store same serialize method to extract data from User
643 # store same serialize method to extract data from User
618 from rhodecode.model.user import UserModel
644 from rhodecode.model.user import UserModel
619 serialize_user = UserModel()._serialize_user
645 serialize_user = UserModel()._serialize_user
620
646
621 _groups = []
647 _groups = []
622 for group in user_groups:
648 for group in user_groups:
623 entry = self._serialize_user_group(group)
649 entry = self._serialize_user_group(group)
624 if expand_groups:
650 if expand_groups:
625 expanded_members = []
651 expanded_members = []
626 for member in group.members:
652 for member in group.members:
627 expanded_members.append(serialize_user(member.user))
653 expanded_members.append(serialize_user(member.user))
628 entry['members'] = expanded_members
654 entry['members'] = expanded_members
629 _groups.append(entry)
655 _groups.append(entry)
630 return _groups
656 return _groups
631
657
632 @staticmethod
658 @staticmethod
633 def get_user_groups_as_dict(user_group):
659 def get_user_groups_as_dict(user_group):
634 import rhodecode.lib.helpers as h
660 import rhodecode.lib.helpers as h
635
661
636 data = {
662 data = {
637 'users_group_id': user_group.users_group_id,
663 'users_group_id': user_group.users_group_id,
638 'group_name': user_group.users_group_name,
664 'group_name': user_group.users_group_name,
639 'group_description': user_group.user_group_description,
665 'group_description': user_group.user_group_description,
640 'active': user_group.users_group_active,
666 'active': user_group.users_group_active,
641 "owner": user_group.user.username,
667 "owner": user_group.user.username,
642 'owner_icon': h.gravatar_url(user_group.user.email, 30),
668 'owner_icon': h.gravatar_url(user_group.user.email, 30),
643 "owner_data": {
669 "owner_data": {
644 'owner': user_group.user.username,
670 'owner': user_group.user.username,
645 'owner_icon': h.gravatar_url(user_group.user.email, 30)}
671 'owner_icon': h.gravatar_url(user_group.user.email, 30)}
646 }
672 }
647 return data
673 return data
General Comments 0
You need to be logged in to leave comments. Login now