##// END OF EJS Templates
user-api: use simple schema validator to be consistent how we validate between API and web views.
marcink -
r1832:d176880c default
parent child Browse files
Show More
@@ -59,6 +59,21 b' class TestCreateUser(object):'
59 expected = "email `%s` already exist" % (TEST_USER_REGULAR_EMAIL,)
59 expected = "email `%s` already exist" % (TEST_USER_REGULAR_EMAIL,)
60 assert_error(id_, expected, given=response.body)
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 def test_api_create_user(self):
77 def test_api_create_user(self):
63 username = 'test_new_api_user'
78 username = 'test_new_api_user'
64 email = username + "@foo.com"
79 email = username + "@foo.com"
@@ -175,7 +190,6 b' class TestCreateUser(object):'
175 fixture.destroy_repo_group(username)
190 fixture.destroy_repo_group(username)
176 fixture.destroy_user(usr.user_id)
191 fixture.destroy_user(usr.user_id)
177
192
178
179 @mock.patch.object(UserModel, 'create_or_update', crash)
193 @mock.patch.object(UserModel, 'create_or_update', crash)
180 def test_api_create_user_when_exception_happened(self):
194 def test_api_create_user_when_exception_happened(self):
181
195
@@ -20,7 +20,8 b''
20
20
21 import logging
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 from rhodecode.api.utils import (
25 from rhodecode.api.utils import (
25 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
26 Optional, OAttr, has_superadmin_permission, get_user_or_error, store_update)
26 from rhodecode.lib import audit_logger
27 from rhodecode.lib import audit_logger
@@ -29,6 +30,8 b' from rhodecode.lib.exceptions import Def'
29 from rhodecode.lib.utils2 import safe_int, str2bool
30 from rhodecode.lib.utils2 import safe_int, str2bool
30 from rhodecode.model.db import Session, User, Repository
31 from rhodecode.model.db import Session, User, Repository
31 from rhodecode.model.user import UserModel
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 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
34
37
@@ -238,17 +241,45 b' def create_user(request, apiuser, userna'
238 if isinstance(create_repo_group, basestring):
241 if isinstance(create_repo_group, basestring):
239 create_repo_group = str2bool(create_repo_group)
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 try:
272 try:
242 user = UserModel().create_or_update(
273 user = UserModel().create_or_update(
243 username=Optional.extract(username),
274 username=schema_data['username'],
244 password=Optional.extract(password),
275 password=schema_data['password'],
245 email=Optional.extract(email),
276 email=schema_data['email'],
246 firstname=Optional.extract(firstname),
277 firstname=schema_data['first_name'],
247 lastname=Optional.extract(lastname),
278 lastname=schema_data['last_name'],
248 active=Optional.extract(active),
279 active=schema_data['active'],
249 admin=Optional.extract(admin),
280 admin=schema_data['admin'],
250 extern_type=Optional.extract(extern_type),
281 extern_type=schema_data['extern_type'],
251 extern_name=Optional.extract(extern_name),
282 extern_name=schema_data['extern_name'],
252 force_password_change=Optional.extract(force_password_change),
283 force_password_change=Optional.extract(force_password_change),
253 create_repo_group=create_repo_group
284 create_repo_group=create_repo_group
254 )
285 )
@@ -20,8 +20,8 b''
20
20
21 import logging
21 import logging
22
22
23 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden, \
23 from rhodecode.api import (
24 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)
@@ -18,10 +18,12 b''
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 re
21 import colander
22 import colander
22
23
23 from rhodecode import forms
24 from rhodecode import forms
24 from rhodecode.model.db import User
25 from rhodecode.model.db import User
26 from rhodecode.model.validation_schema import types, validators
25 from rhodecode.translation import _
27 from rhodecode.translation import _
26 from rhodecode.lib.auth import check_password
28 from rhodecode.lib.auth import check_password
27
29
@@ -52,10 +54,72 b' class ChangePasswordSchema(colander.Sche'
52 widget=forms.widget.CheckedPasswordWidget(redisplay=True),
54 widget=forms.widget.CheckedPasswordWidget(redisplay=True),
53 validator=colander.Length(min=6))
55 validator=colander.Length(min=6))
54
56
55
56 def validator(self, form, values):
57 def validator(self, form, values):
57 if values['current_password'] == values['new_password']:
58 if values['current_password'] == values['new_password']:
58 exc = colander.Invalid(form)
59 exc = colander.Invalid(form)
59 exc['new_password'] = _('New password must be different '
60 exc['new_password'] = _('New password must be different '
60 'to old password')
61 'to old password')
61 raise exc
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