Show More
@@ -59,6 +59,21 b' class TestCreateUser(object):' | |||
|
59 | 59 | expected = "email `%s` already exist" % (TEST_USER_REGULAR_EMAIL,) |
|
60 | 60 | assert_error(id_, expected, given=response.body) |
|
61 | 61 | |
|
62 | def test_api_create_user_with_wrong_username(self): | |
|
63 | bad_username = '<> HELLO WORLD <>' | |
|
64 | id_, params = build_data( | |
|
65 | self.apikey, 'create_user', | |
|
66 | username=bad_username, | |
|
67 | email='new@email.com', | |
|
68 | password='trololo') | |
|
69 | response = api_call(self.app, params) | |
|
70 | ||
|
71 | expected = {'username': | |
|
72 | "Username may only contain alphanumeric characters " | |
|
73 | "underscores, periods or dashes and must begin with " | |
|
74 | "alphanumeric character or underscore"} | |
|
75 | assert_error(id_, expected, given=response.body) | |
|
76 | ||
|
62 | 77 | def test_api_create_user(self): |
|
63 | 78 | username = 'test_new_api_user' |
|
64 | 79 | email = username + "@foo.com" |
@@ -175,7 +190,6 b' class TestCreateUser(object):' | |||
|
175 | 190 | fixture.destroy_repo_group(username) |
|
176 | 191 | fixture.destroy_user(usr.user_id) |
|
177 | 192 | |
|
178 | ||
|
179 | 193 | @mock.patch.object(UserModel, 'create_or_update', crash) |
|
180 | 194 | def test_api_create_user_when_exception_happened(self): |
|
181 | 195 |
@@ -20,7 +20,8 b'' | |||
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | |
|
23 | from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden | |
|
23 | from rhodecode.api import ( | |
|
24 | jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError) | |
|
24 | 25 | from rhodecode.api.utils import ( |
|
25 | 26 | Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update) |
|
26 | 27 | from rhodecode.lib import audit_logger |
@@ -29,6 +30,8 b' from rhodecode.lib.exceptions import Def' | |||
|
29 | 30 | from rhodecode.lib.utils2 import safe_int, str2bool |
|
30 | 31 | from rhodecode.model.db import Session, User, Repository |
|
31 | 32 | from rhodecode.model.user import UserModel |
|
33 | from rhodecode.model import validation_schema | |
|
34 | from rhodecode.model.validation_schema.schemas import user_schema | |
|
32 | 35 | |
|
33 | 36 | log = logging.getLogger(__name__) |
|
34 | 37 | |
@@ -238,17 +241,45 b' def create_user(request, apiuser, userna' | |||
|
238 | 241 | if isinstance(create_repo_group, basestring): |
|
239 | 242 | create_repo_group = str2bool(create_repo_group) |
|
240 | 243 | |
|
244 | username = Optional.extract(username) | |
|
245 | password = Optional.extract(password) | |
|
246 | email = Optional.extract(email) | |
|
247 | first_name = Optional.extract(firstname) | |
|
248 | last_name = Optional.extract(lastname) | |
|
249 | active = Optional.extract(active) | |
|
250 | admin = Optional.extract(admin) | |
|
251 | extern_type = Optional.extract(extern_type) | |
|
252 | extern_name = Optional.extract(extern_name) | |
|
253 | ||
|
254 | schema = user_schema.UserSchema().bind( | |
|
255 | # user caller | |
|
256 | user=apiuser) | |
|
257 | try: | |
|
258 | schema_data = schema.deserialize(dict( | |
|
259 | username=username, | |
|
260 | email=email, | |
|
261 | password=password, | |
|
262 | first_name=first_name, | |
|
263 | last_name=last_name, | |
|
264 | active=active, | |
|
265 | admin=admin, | |
|
266 | extern_type=extern_type, | |
|
267 | extern_name=extern_name, | |
|
268 | )) | |
|
269 | except validation_schema.Invalid as err: | |
|
270 | raise JSONRPCValidationError(colander_exc=err) | |
|
271 | ||
|
241 | 272 | try: |
|
242 | 273 | user = UserModel().create_or_update( |
|
243 |
username= |
|
|
244 |
password= |
|
|
245 |
email= |
|
|
246 |
firstname= |
|
|
247 |
lastname= |
|
|
248 |
active= |
|
|
249 |
admin= |
|
|
250 |
extern_type= |
|
|
251 |
extern_name= |
|
|
274 | username=schema_data['username'], | |
|
275 | password=schema_data['password'], | |
|
276 | email=schema_data['email'], | |
|
277 | firstname=schema_data['first_name'], | |
|
278 | lastname=schema_data['last_name'], | |
|
279 | active=schema_data['active'], | |
|
280 | admin=schema_data['admin'], | |
|
281 | extern_type=schema_data['extern_type'], | |
|
282 | extern_name=schema_data['extern_name'], | |
|
252 | 283 | force_password_change=Optional.extract(force_password_change), |
|
253 | 284 | create_repo_group=create_repo_group |
|
254 | 285 | ) |
@@ -20,8 +20,8 b'' | |||
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | |
|
23 | from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden, \ | |
|
24 | JSONRPCValidationError | |
|
23 | from rhodecode.api import ( | |
|
24 | jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError) | |
|
25 | 25 | from rhodecode.api.utils import ( |
|
26 | 26 | Optional, OAttr, store_update, has_superadmin_permission, get_origin, |
|
27 | 27 | get_user_or_error, get_user_group_or_error, get_perm_or_error) |
@@ -18,10 +18,12 b'' | |||
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | import re | |
|
21 | 22 | import colander |
|
22 | 23 | |
|
23 | 24 | from rhodecode import forms |
|
24 | 25 | from rhodecode.model.db import User |
|
26 | from rhodecode.model.validation_schema import types, validators | |
|
25 | 27 | from rhodecode.translation import _ |
|
26 | 28 | from rhodecode.lib.auth import check_password |
|
27 | 29 | |
@@ -52,10 +54,72 b' class ChangePasswordSchema(colander.Sche' | |||
|
52 | 54 | widget=forms.widget.CheckedPasswordWidget(redisplay=True), |
|
53 | 55 | validator=colander.Length(min=6)) |
|
54 | 56 | |
|
55 | ||
|
56 | 57 | def validator(self, form, values): |
|
57 | 58 | if values['current_password'] == values['new_password']: |
|
58 | 59 | exc = colander.Invalid(form) |
|
59 | 60 | exc['new_password'] = _('New password must be different ' |
|
60 | 61 | 'to old password') |
|
61 | 62 | raise exc |
|
63 | ||
|
64 | ||
|
65 | @colander.deferred | |
|
66 | def deferred_username_validator(node, kw): | |
|
67 | ||
|
68 | def name_validator(node, value): | |
|
69 | msg = _( | |
|
70 | u'Username may only contain alphanumeric characters ' | |
|
71 | u'underscores, periods or dashes and must begin with ' | |
|
72 | u'alphanumeric character or underscore') | |
|
73 | ||
|
74 | if not re.match(r'^[\w]{1}[\w\-\.]{0,254}$', value): | |
|
75 | raise colander.Invalid(node, msg) | |
|
76 | ||
|
77 | return name_validator | |
|
78 | ||
|
79 | ||
|
80 | @colander.deferred | |
|
81 | def deferred_email_validator(node, kw): | |
|
82 | # NOTE(marcink): we might provide uniqueness validation later here... | |
|
83 | return colander.Email() | |
|
84 | ||
|
85 | ||
|
86 | class UserSchema(colander.Schema): | |
|
87 | username = colander.SchemaNode( | |
|
88 | colander.String(), | |
|
89 | validator=deferred_username_validator) | |
|
90 | ||
|
91 | email = colander.SchemaNode( | |
|
92 | colander.String(), | |
|
93 | validator=deferred_email_validator) | |
|
94 | ||
|
95 | password = colander.SchemaNode( | |
|
96 | colander.String(), missing='') | |
|
97 | ||
|
98 | first_name = colander.SchemaNode( | |
|
99 | colander.String(), missing='') | |
|
100 | ||
|
101 | last_name = colander.SchemaNode( | |
|
102 | colander.String(), missing='') | |
|
103 | ||
|
104 | active = colander.SchemaNode( | |
|
105 | types.StringBooleanType(), | |
|
106 | missing=False) | |
|
107 | ||
|
108 | admin = colander.SchemaNode( | |
|
109 | types.StringBooleanType(), | |
|
110 | missing=False) | |
|
111 | ||
|
112 | extern_name = colander.SchemaNode( | |
|
113 | colander.String(), missing='') | |
|
114 | ||
|
115 | extern_type = colander.SchemaNode( | |
|
116 | colander.String(), missing='') | |
|
117 | ||
|
118 | def deserialize(self, cstruct): | |
|
119 | """ | |
|
120 | Custom deserialize that allows to chain validation, and verify | |
|
121 | permissions, and as last step uniqueness | |
|
122 | """ | |
|
123 | ||
|
124 | appstruct = super(UserSchema, self).deserialize(cstruct) | |
|
125 | return appstruct |
General Comments 0
You need to be logged in to leave comments.
Login now