##// END OF EJS Templates
Switched forms to new validators
marcink -
r2467:4419551b codereview
parent child Browse files
Show More
@@ -1,247 +1,247 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.users
3 rhodecode.controllers.admin.users
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Users crud controller for pylons
6 Users crud controller for pylons
7
7
8 :created_on: Apr 4, 2010
8 :created_on: Apr 4, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31 from pylons import request, session, tmpl_context as c, url, config
31 from pylons import request, session, tmpl_context as c, url, config
32 from pylons.controllers.util import redirect
32 from pylons.controllers.util import redirect
33 from pylons.i18n.translation import _
33 from pylons.i18n.translation import _
34
34
35 from rhodecode.lib.exceptions import DefaultUserException, \
35 from rhodecode.lib.exceptions import DefaultUserException, \
36 UserOwnsReposException
36 UserOwnsReposException
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator,\
38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator,\
39 AuthUser
39 AuthUser
40 from rhodecode.lib.base import BaseController, render
40 from rhodecode.lib.base import BaseController, render
41
41
42 from rhodecode.model.db import User, Permission, UserEmailMap
42 from rhodecode.model.db import User, Permission, UserEmailMap
43 from rhodecode.model.forms import UserForm
43 from rhodecode.model.forms import UserForm
44 from rhodecode.model.user import UserModel
44 from rhodecode.model.user import UserModel
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.lib.utils import action_logger
46 from rhodecode.lib.utils import action_logger
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50
51 class UsersController(BaseController):
51 class UsersController(BaseController):
52 """REST Controller styled on the Atom Publishing Protocol"""
52 """REST Controller styled on the Atom Publishing Protocol"""
53 # To properly map this controller, ensure your config/routing.py
53 # To properly map this controller, ensure your config/routing.py
54 # file has a resource setup:
54 # file has a resource setup:
55 # map.resource('user', 'users')
55 # map.resource('user', 'users')
56
56
57 @LoginRequired()
57 @LoginRequired()
58 @HasPermissionAllDecorator('hg.admin')
58 @HasPermissionAllDecorator('hg.admin')
59 def __before__(self):
59 def __before__(self):
60 c.admin_user = session.get('admin_user')
60 c.admin_user = session.get('admin_user')
61 c.admin_username = session.get('admin_username')
61 c.admin_username = session.get('admin_username')
62 super(UsersController, self).__before__()
62 super(UsersController, self).__before__()
63 c.available_permissions = config['available_permissions']
63 c.available_permissions = config['available_permissions']
64
64
65 def index(self, format='html'):
65 def index(self, format='html'):
66 """GET /users: All items in the collection"""
66 """GET /users: All items in the collection"""
67 # url('users')
67 # url('users')
68
68
69 c.users_list = self.sa.query(User).all()
69 c.users_list = self.sa.query(User).all()
70 return render('admin/users/users.html')
70 return render('admin/users/users.html')
71
71
72 def create(self):
72 def create(self):
73 """POST /users: Create a new item"""
73 """POST /users: Create a new item"""
74 # url('users')
74 # url('users')
75
75
76 user_model = UserModel()
76 user_model = UserModel()
77 user_form = UserForm()()
77 user_form = UserForm()()
78 try:
78 try:
79 form_result = user_form.to_python(dict(request.POST))
79 form_result = user_form.to_python(dict(request.POST))
80 user_model.create(form_result)
80 user_model.create(form_result)
81 usr = form_result['username']
81 usr = form_result['username']
82 action_logger(self.rhodecode_user, 'admin_created_user:%s' % usr,
82 action_logger(self.rhodecode_user, 'admin_created_user:%s' % usr,
83 None, self.ip_addr, self.sa)
83 None, self.ip_addr, self.sa)
84 h.flash(_('created user %s') % usr,
84 h.flash(_('created user %s') % usr,
85 category='success')
85 category='success')
86 Session.commit()
86 Session.commit()
87 except formencode.Invalid, errors:
87 except formencode.Invalid, errors:
88 return htmlfill.render(
88 return htmlfill.render(
89 render('admin/users/user_add.html'),
89 render('admin/users/user_add.html'),
90 defaults=errors.value,
90 defaults=errors.value,
91 errors=errors.error_dict or {},
91 errors=errors.error_dict or {},
92 prefix_error=False,
92 prefix_error=False,
93 encoding="UTF-8")
93 encoding="UTF-8")
94 except Exception:
94 except Exception:
95 log.error(traceback.format_exc())
95 log.error(traceback.format_exc())
96 h.flash(_('error occurred during creation of user %s') \
96 h.flash(_('error occurred during creation of user %s') \
97 % request.POST.get('username'), category='error')
97 % request.POST.get('username'), category='error')
98 return redirect(url('users'))
98 return redirect(url('users'))
99
99
100 def new(self, format='html'):
100 def new(self, format='html'):
101 """GET /users/new: Form to create a new item"""
101 """GET /users/new: Form to create a new item"""
102 # url('new_user')
102 # url('new_user')
103 return render('admin/users/user_add.html')
103 return render('admin/users/user_add.html')
104
104
105 def update(self, id):
105 def update(self, id):
106 """PUT /users/id: Update an existing item"""
106 """PUT /users/id: Update an existing item"""
107 # Forms posted to this method should contain a hidden field:
107 # Forms posted to this method should contain a hidden field:
108 # <input type="hidden" name="_method" value="PUT" />
108 # <input type="hidden" name="_method" value="PUT" />
109 # Or using helpers:
109 # Or using helpers:
110 # h.form(url('update_user', id=ID),
110 # h.form(url('update_user', id=ID),
111 # method='put')
111 # method='put')
112 # url('user', id=ID)
112 # url('user', id=ID)
113 user_model = UserModel()
113 user_model = UserModel()
114 c.user = user_model.get(id)
114 c.user = user_model.get(id)
115 c.perm_user = AuthUser(user_id=id)
115 c.perm_user = AuthUser(user_id=id)
116 _form = UserForm(edit=True, old_data={'user_id': id,
116 _form = UserForm(edit=True, old_data={'user_id': id,
117 'email': c.user.email})()
117 'email': c.user.email})()
118 form_result = {}
118 form_result = {}
119 try:
119 try:
120 form_result = _form.to_python(dict(request.POST))
120 form_result = _form.to_python(dict(request.POST))
121 user_model.update(id, form_result)
121 user_model.update(id, form_result)
122 usr = form_result['username']
122 usr = form_result['username']
123 action_logger(self.rhodecode_user, 'admin_updated_user:%s' % usr,
123 action_logger(self.rhodecode_user, 'admin_updated_user:%s' % usr,
124 None, self.ip_addr, self.sa)
124 None, self.ip_addr, self.sa)
125 h.flash(_('User updated successfully'), category='success')
125 h.flash(_('User updated successfully'), category='success')
126 Session.commit()
126 Session.commit()
127 except formencode.Invalid, errors:
127 except formencode.Invalid, errors:
128 e = errors.error_dict or {}
128 e = errors.error_dict or {}
129 perm = Permission.get_by_key('hg.create.repository')
129 perm = Permission.get_by_key('hg.create.repository')
130 e.update({'create_repo_perm': user_model.has_perm(id, perm)})
130 e.update({'create_repo_perm': user_model.has_perm(id, perm)})
131 return htmlfill.render(
131 return htmlfill.render(
132 render('admin/users/user_edit.html'),
132 render('admin/users/user_edit.html'),
133 defaults=errors.value,
133 defaults=errors.value,
134 errors=e,
134 errors=e,
135 prefix_error=False,
135 prefix_error=False,
136 encoding="UTF-8")
136 encoding="UTF-8")
137 except Exception:
137 except Exception:
138 log.error(traceback.format_exc())
138 log.error(traceback.format_exc())
139 h.flash(_('error occurred during update of user %s') \
139 h.flash(_('error occurred during update of user %s') \
140 % form_result.get('username'), category='error')
140 % form_result.get('username'), category='error')
141
141
142 return redirect(url('users'))
142 return redirect(url('users'))
143
143
144 def delete(self, id):
144 def delete(self, id):
145 """DELETE /users/id: Delete an existing item"""
145 """DELETE /users/id: Delete an existing item"""
146 # Forms posted to this method should contain a hidden field:
146 # Forms posted to this method should contain a hidden field:
147 # <input type="hidden" name="_method" value="DELETE" />
147 # <input type="hidden" name="_method" value="DELETE" />
148 # Or using helpers:
148 # Or using helpers:
149 # h.form(url('delete_user', id=ID),
149 # h.form(url('delete_user', id=ID),
150 # method='delete')
150 # method='delete')
151 # url('user', id=ID)
151 # url('user', id=ID)
152 user_model = UserModel()
152 user_model = UserModel()
153 try:
153 try:
154 user_model.delete(id)
154 user_model.delete(id)
155 Session.commit()
155 Session.commit()
156 h.flash(_('successfully deleted user'), category='success')
156 h.flash(_('successfully deleted user'), category='success')
157 except (UserOwnsReposException, DefaultUserException), e:
157 except (UserOwnsReposException, DefaultUserException), e:
158 h.flash(e, category='warning')
158 h.flash(e, category='warning')
159 except Exception:
159 except Exception:
160 log.error(traceback.format_exc())
160 log.error(traceback.format_exc())
161 h.flash(_('An error occurred during deletion of user'),
161 h.flash(_('An error occurred during deletion of user'),
162 category='error')
162 category='error')
163 return redirect(url('users'))
163 return redirect(url('users'))
164
164
165 def show(self, id, format='html'):
165 def show(self, id, format='html'):
166 """GET /users/id: Show a specific item"""
166 """GET /users/id: Show a specific item"""
167 # url('user', id=ID)
167 # url('user', id=ID)
168
168
169 def edit(self, id, format='html'):
169 def edit(self, id, format='html'):
170 """GET /users/id/edit: Form to edit an existing item"""
170 """GET /users/id/edit: Form to edit an existing item"""
171 # url('edit_user', id=ID)
171 # url('edit_user', id=ID)
172 c.user = User.get(id)
172 c.user = User.get(id)
173 if not c.user:
173 if not c.user:
174 return redirect(url('users'))
174 return redirect(url('users'))
175 if c.user.username == 'default':
175 if c.user.username == 'default':
176 h.flash(_("You can't edit this user"), category='warning')
176 h.flash(_("You can't edit this user"), category='warning')
177 return redirect(url('users'))
177 return redirect(url('users'))
178 c.perm_user = AuthUser(user_id=id)
178 c.perm_user = AuthUser(user_id=id)
179 c.user.permissions = {}
179 c.user.permissions = {}
180 c.granted_permissions = UserModel().fill_perms(c.user)\
180 c.granted_permissions = UserModel().fill_perms(c.user)\
181 .permissions['global']
181 .permissions['global']
182 c.user_email_map = UserEmailMap.query()\
182 c.user_email_map = UserEmailMap.query()\
183 .filter(UserEmailMap.user == c.user).all()
183 .filter(UserEmailMap.user == c.user).all()
184 defaults = c.user.get_dict()
184 defaults = c.user.get_dict()
185 perm = Permission.get_by_key('hg.create.repository')
185 perm = Permission.get_by_key('hg.create.repository')
186 defaults.update({'create_repo_perm': UserModel().has_perm(id, perm)})
186 defaults.update({'create_repo_perm': UserModel().has_perm(id, perm)})
187
187
188 return htmlfill.render(
188 return htmlfill.render(
189 render('admin/users/user_edit.html'),
189 render('admin/users/user_edit.html'),
190 defaults=defaults,
190 defaults=defaults,
191 encoding="UTF-8",
191 encoding="UTF-8",
192 force_defaults=False
192 force_defaults=False
193 )
193 )
194
194
195 def update_perm(self, id):
195 def update_perm(self, id):
196 """PUT /users_perm/id: Update an existing item"""
196 """PUT /users_perm/id: Update an existing item"""
197 # url('user_perm', id=ID, method='put')
197 # url('user_perm', id=ID, method='put')
198
198
199 grant_perm = request.POST.get('create_repo_perm', False)
199 grant_perm = request.POST.get('create_repo_perm', False)
200 user_model = UserModel()
200 user_model = UserModel()
201
201
202 if grant_perm:
202 if grant_perm:
203 perm = Permission.get_by_key('hg.create.none')
203 perm = Permission.get_by_key('hg.create.none')
204 user_model.revoke_perm(id, perm)
204 user_model.revoke_perm(id, perm)
205
205
206 perm = Permission.get_by_key('hg.create.repository')
206 perm = Permission.get_by_key('hg.create.repository')
207 user_model.grant_perm(id, perm)
207 user_model.grant_perm(id, perm)
208 h.flash(_("Granted 'repository create' permission to user"),
208 h.flash(_("Granted 'repository create' permission to user"),
209 category='success')
209 category='success')
210 Session.commit()
210 Session.commit()
211 else:
211 else:
212 perm = Permission.get_by_key('hg.create.repository')
212 perm = Permission.get_by_key('hg.create.repository')
213 user_model.revoke_perm(id, perm)
213 user_model.revoke_perm(id, perm)
214
214
215 perm = Permission.get_by_key('hg.create.none')
215 perm = Permission.get_by_key('hg.create.none')
216 user_model.grant_perm(id, perm)
216 user_model.grant_perm(id, perm)
217 h.flash(_("Revoked 'repository create' permission to user"),
217 h.flash(_("Revoked 'repository create' permission to user"),
218 category='success')
218 category='success')
219 Session.commit()
219 Session.commit()
220 return redirect(url('edit_user', id=id))
220 return redirect(url('edit_user', id=id))
221
221
222 def add_email(self, id):
222 def add_email(self, id):
223 """PUT /user_emails/id: Update an existing item"""
223 """POST /user_emails:Add an existing item"""
224 # url('user_emails', id=ID, method='put')
224 # url('user_emails', id=ID, method='put')
225
225
226 #TODO: validation and form !!!
226 #TODO: validation and form !!!
227 email = request.POST.get('new_email')
227 email = request.POST.get('new_email')
228 user_model = UserModel()
228 user_model = UserModel()
229
229
230 try:
230 try:
231 user_model.add_extra_email(id, email)
231 user_model.add_extra_email(id, email)
232 Session.commit()
232 Session.commit()
233 h.flash(_("Added email %s to user" % email), category='success')
233 h.flash(_("Added email %s to user" % email), category='success')
234 except Exception:
234 except Exception:
235 log.error(traceback.format_exc())
235 log.error(traceback.format_exc())
236 h.flash(_('An error occurred during email saving'),
236 h.flash(_('An error occurred during email saving'),
237 category='error')
237 category='error')
238 return redirect(url('edit_user', id=id))
238 return redirect(url('edit_user', id=id))
239
239
240 def delete_email(self, id):
240 def delete_email(self, id):
241 """DELETE /user_emails_delete/id: Delete an existing item"""
241 """DELETE /user_emails_delete/id: Delete an existing item"""
242 # url('user_emails_delete', id=ID, method='delete')
242 # url('user_emails_delete', id=ID, method='delete')
243 user_model = UserModel()
243 user_model = UserModel()
244 user_model.delete_extra_email(id, request.POST.get('del_email'))
244 user_model.delete_extra_email(id, request.POST.get('del_email'))
245 Session.commit()
245 Session.commit()
246 h.flash(_("Removed email from user"), category='success')
246 h.flash(_("Removed email from user"), category='success')
247 return redirect(url('edit_user', id=id))
247 return redirect(url('edit_user', id=id))
This diff has been collapsed as it changes many lines, (753 lines changed) Show them Hide them
@@ -1,774 +1,301 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import os
23 import re
24 import logging
22 import logging
25 import traceback
26
23
27 import formencode
24 import formencode
28 from formencode import All
25 from formencode import All
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
30 Email, Bool, StringBoolean, Set
31
26
32 from pylons.i18n.translation import _
27 from pylons.i18n.translation import _
33 from webhelpers.pylonslib.secure_form import authentication_token
34
28
35 from rhodecode.config.routing import ADMIN_PREFIX
29 from rhodecode.model import validators as v
36 from rhodecode.lib.utils import repo_name_slug
37 from rhodecode.lib.auth import authenticate, get_crypt_password
38 from rhodecode.lib.exceptions import LdapImportError
39 from rhodecode.model.db import User, UsersGroup, RepoGroup, Repository
40 from rhodecode import BACKENDS
30 from rhodecode import BACKENDS
41
31
42 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
43
33
44
34
45 #this is needed to translate the messages using _() in validators
46 class State_obj(object):
47 _ = staticmethod(_)
48
49
50 #==============================================================================
51 # VALIDATORS
52 #==============================================================================
53 class ValidAuthToken(formencode.validators.FancyValidator):
54 messages = {'invalid_token': _('Token mismatch')}
55
56 def validate_python(self, value, state):
57
58 if value != authentication_token():
59 raise formencode.Invalid(
60 self.message('invalid_token',
61 state, search_number=value),
62 value,
63 state
64 )
65
66
67 def ValidUsername(edit, old_data):
68 class _ValidUsername(formencode.validators.FancyValidator):
69
70 def validate_python(self, value, state):
71 if value in ['default', 'new_user']:
72 raise formencode.Invalid(_('Invalid username'), value, state)
73 #check if user is unique
74 old_un = None
75 if edit:
76 old_un = User.get(old_data.get('user_id')).username
77
78 if old_un != value or not edit:
79 if User.get_by_username(value, case_insensitive=True):
80 raise formencode.Invalid(_('This username already '
81 'exists') , value, state)
82
83 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
84 raise formencode.Invalid(
85 _('Username may only contain alphanumeric characters '
86 'underscores, periods or dashes and must begin with '
87 'alphanumeric character'),
88 value,
89 state
90 )
91
92 return _ValidUsername
93
94
95 def ValidUsersGroup(edit, old_data):
96
97 class _ValidUsersGroup(formencode.validators.FancyValidator):
98
99 def validate_python(self, value, state):
100 if value in ['default']:
101 raise formencode.Invalid(_('Invalid group name'), value, state)
102 #check if group is unique
103 old_ugname = None
104 if edit:
105 old_ugname = UsersGroup.get(
106 old_data.get('users_group_id')).users_group_name
107
108 if old_ugname != value or not edit:
109 if UsersGroup.get_by_group_name(value, cache=False,
110 case_insensitive=True):
111 raise formencode.Invalid(_('This users group '
112 'already exists'), value,
113 state)
114
115 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
116 raise formencode.Invalid(
117 _('RepoGroup name may only contain alphanumeric characters '
118 'underscores, periods or dashes and must begin with '
119 'alphanumeric character'),
120 value,
121 state
122 )
123
124 return _ValidUsersGroup
125
126
127 def ValidReposGroup(edit, old_data):
128 class _ValidReposGroup(formencode.validators.FancyValidator):
129
130 def validate_python(self, value, state):
131 # TODO WRITE VALIDATIONS
132 group_name = value.get('group_name')
133 group_parent_id = value.get('group_parent_id')
134
135 # slugify repo group just in case :)
136 slug = repo_name_slug(group_name)
137
138 # check for parent of self
139 parent_of_self = lambda: (
140 old_data['group_id'] == int(group_parent_id)
141 if group_parent_id else False
142 )
143 if edit and parent_of_self():
144 e_dict = {
145 'group_parent_id': _('Cannot assign this group as parent')
146 }
147 raise formencode.Invalid('', value, state,
148 error_dict=e_dict)
149
150 old_gname = None
151 if edit:
152 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
153
154 if old_gname != group_name or not edit:
155
156 # check group
157 gr = RepoGroup.query()\
158 .filter(RepoGroup.group_name == slug)\
159 .filter(RepoGroup.group_parent_id == group_parent_id)\
160 .scalar()
161
162 if gr:
163 e_dict = {
164 'group_name': _('This group already exists')
165 }
166 raise formencode.Invalid('', value, state,
167 error_dict=e_dict)
168
169 # check for same repo
170 repo = Repository.query()\
171 .filter(Repository.repo_name == slug)\
172 .scalar()
173
174 if repo:
175 e_dict = {
176 'group_name': _('Repository with this name already exists')
177 }
178 raise formencode.Invalid('', value, state,
179 error_dict=e_dict)
180
181 return _ValidReposGroup
182
183
184 class ValidPassword(formencode.validators.FancyValidator):
185
186 def to_python(self, value, state):
187
188 if not value:
189 return
190
191 if value.get('password'):
192 try:
193 value['password'] = get_crypt_password(value['password'])
194 except UnicodeEncodeError:
195 e_dict = {'password': _('Invalid characters in password')}
196 raise formencode.Invalid('', value, state, error_dict=e_dict)
197
198 if value.get('password_confirmation'):
199 try:
200 value['password_confirmation'] = \
201 get_crypt_password(value['password_confirmation'])
202 except UnicodeEncodeError:
203 e_dict = {
204 'password_confirmation': _('Invalid characters in password')
205 }
206 raise formencode.Invalid('', value, state, error_dict=e_dict)
207
208 if value.get('new_password'):
209 try:
210 value['new_password'] = \
211 get_crypt_password(value['new_password'])
212 except UnicodeEncodeError:
213 e_dict = {'new_password': _('Invalid characters in password')}
214 raise formencode.Invalid('', value, state, error_dict=e_dict)
215
216 return value
217
218
219 class ValidPasswordsMatch(formencode.validators.FancyValidator):
220
221 def validate_python(self, value, state):
222
223 pass_val = value.get('password') or value.get('new_password')
224 if pass_val != value['password_confirmation']:
225 e_dict = {'password_confirmation':
226 _('Passwords do not match')}
227 raise formencode.Invalid('', value, state, error_dict=e_dict)
228
229
230 class ValidAuth(formencode.validators.FancyValidator):
231 messages = {
232 'invalid_password':_('invalid password'),
233 'invalid_login':_('invalid user name'),
234 'disabled_account':_('Your account is disabled')
235 }
236
237 # error mapping
238 e_dict = {'username': messages['invalid_login'],
239 'password': messages['invalid_password']}
240 e_dict_disable = {'username': messages['disabled_account']}
241
242 def validate_python(self, value, state):
243 password = value['password']
244 username = value['username']
245 user = User.get_by_username(username)
246
247 if authenticate(username, password):
248 return value
249 else:
250 if user and user.active is False:
251 log.warning('user %s is disabled' % username)
252 raise formencode.Invalid(
253 self.message('disabled_account',
254 state=State_obj),
255 value, state,
256 error_dict=self.e_dict_disable
257 )
258 else:
259 log.warning('user %s failed to authenticate' % username)
260 raise formencode.Invalid(
261 self.message('invalid_password',
262 state=State_obj), value, state,
263 error_dict=self.e_dict
264 )
265
266
267 class ValidRepoUser(formencode.validators.FancyValidator):
268
269 def to_python(self, value, state):
270 try:
271 User.query().filter(User.active == True)\
272 .filter(User.username == value).one()
273 except Exception:
274 raise formencode.Invalid(_('This username is not valid'),
275 value, state)
276 return value
277
278
279 def ValidRepoName(edit, old_data):
280 class _ValidRepoName(formencode.validators.FancyValidator):
281 def to_python(self, value, state):
282
283 repo_name = value.get('repo_name')
284
285 slug = repo_name_slug(repo_name)
286 if slug in [ADMIN_PREFIX, '']:
287 e_dict = {'repo_name': _('This repository name is disallowed')}
288 raise formencode.Invalid('', value, state, error_dict=e_dict)
289
290 if value.get('repo_group'):
291 gr = RepoGroup.get(value.get('repo_group'))
292 group_path = gr.full_path
293 # value needs to be aware of group name in order to check
294 # db key This is an actual just the name to store in the
295 # database
296 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
297
298 else:
299 group_path = ''
300 repo_name_full = repo_name
301
302 value['repo_name_full'] = repo_name_full
303 rename = old_data.get('repo_name') != repo_name_full
304 create = not edit
305 if rename or create:
306
307 if group_path != '':
308 if Repository.get_by_repo_name(repo_name_full):
309 e_dict = {
310 'repo_name': _('This repository already exists in '
311 'a group "%s"') % gr.group_name
312 }
313 raise formencode.Invalid('', value, state,
314 error_dict=e_dict)
315 elif RepoGroup.get_by_group_name(repo_name_full):
316 e_dict = {
317 'repo_name': _('There is a group with this name '
318 'already "%s"') % repo_name_full
319 }
320 raise formencode.Invalid('', value, state,
321 error_dict=e_dict)
322
323 elif Repository.get_by_repo_name(repo_name_full):
324 e_dict = {'repo_name': _('This repository '
325 'already exists')}
326 raise formencode.Invalid('', value, state,
327 error_dict=e_dict)
328
329 return value
330
331 return _ValidRepoName
332
333
334 def ValidForkName(*args, **kwargs):
335 return ValidRepoName(*args, **kwargs)
336
337
338 def SlugifyName():
339 class _SlugifyName(formencode.validators.FancyValidator):
340
341 def to_python(self, value, state):
342 return repo_name_slug(value)
343
344 return _SlugifyName
345
346
347 def ValidCloneUri():
348 from rhodecode.lib.utils import make_ui
349
350 def url_handler(repo_type, url, proto, ui=None):
351 if repo_type == 'hg':
352 from mercurial.httprepo import httprepository, httpsrepository
353 if proto == 'https':
354 httpsrepository(make_ui('db'), url).capabilities
355 elif proto == 'http':
356 httprepository(make_ui('db'), url).capabilities
357 elif repo_type == 'git':
358 #TODO: write a git url validator
359 pass
360
361 class _ValidCloneUri(formencode.validators.FancyValidator):
362
363 def to_python(self, value, state):
364
365 repo_type = value.get('repo_type')
366 url = value.get('clone_uri')
367 e_dict = {'clone_uri': _('invalid clone url')}
368
369 if not url:
370 pass
371 elif url.startswith('https'):
372 try:
373 url_handler(repo_type, url, 'https', make_ui('db'))
374 except Exception:
375 log.error(traceback.format_exc())
376 raise formencode.Invalid('', value, state, error_dict=e_dict)
377 elif url.startswith('http'):
378 try:
379 url_handler(repo_type, url, 'http', make_ui('db'))
380 except Exception:
381 log.error(traceback.format_exc())
382 raise formencode.Invalid('', value, state, error_dict=e_dict)
383 else:
384 e_dict = {'clone_uri': _('Invalid clone url, provide a '
385 'valid clone http\s url')}
386 raise formencode.Invalid('', value, state, error_dict=e_dict)
387
388 return value
389
390 return _ValidCloneUri
391
392
393 def ValidForkType(old_data):
394 class _ValidForkType(formencode.validators.FancyValidator):
395
396 def to_python(self, value, state):
397 if old_data['repo_type'] != value:
398 raise formencode.Invalid(_('Fork have to be the same '
399 'type as original'), value, state)
400
401 return value
402 return _ValidForkType
403
404
405 def ValidPerms(type_='repo'):
406 if type_ == 'group':
407 EMPTY_PERM = 'group.none'
408 elif type_ == 'repo':
409 EMPTY_PERM = 'repository.none'
410
411 class _ValidPerms(formencode.validators.FancyValidator):
412 messages = {
413 'perm_new_member_name':
414 _('This username or users group name is not valid')
415 }
416
417 def to_python(self, value, state):
418 perms_update = []
419 perms_new = []
420 # build a list of permission to update and new permission to create
421 for k, v in value.items():
422 # means new added member to permissions
423 if k.startswith('perm_new_member'):
424 new_perm = value.get('perm_new_member', False)
425 new_member = value.get('perm_new_member_name', False)
426 new_type = value.get('perm_new_member_type')
427
428 if new_member and new_perm:
429 if (new_member, new_perm, new_type) not in perms_new:
430 perms_new.append((new_member, new_perm, new_type))
431 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
432 member = k[7:]
433 t = {'u': 'user',
434 'g': 'users_group'
435 }[k[0]]
436 if member == 'default':
437 if value.get('private'):
438 # set none for default when updating to private repo
439 v = EMPTY_PERM
440 perms_update.append((member, v, t))
441
442 value['perms_updates'] = perms_update
443 value['perms_new'] = perms_new
444
445 # update permissions
446 for k, v, t in perms_new:
447 try:
448 if t is 'user':
449 self.user_db = User.query()\
450 .filter(User.active == True)\
451 .filter(User.username == k).one()
452 if t is 'users_group':
453 self.user_db = UsersGroup.query()\
454 .filter(UsersGroup.users_group_active == True)\
455 .filter(UsersGroup.users_group_name == k).one()
456
457 except Exception:
458 msg = self.message('perm_new_member_name',
459 state=State_obj)
460 raise formencode.Invalid(
461 msg, value, state, error_dict={'perm_new_member_name': msg}
462 )
463 return value
464 return _ValidPerms
465
466
467 class ValidSettings(formencode.validators.FancyValidator):
468
469 def to_python(self, value, state):
470 # settings form can't edit user
471 if 'user' in value:
472 del['value']['user']
473 return value
474
475
476 class ValidPath(formencode.validators.FancyValidator):
477 def to_python(self, value, state):
478
479 if not os.path.isdir(value):
480 msg = _('This is not a valid path')
481 raise formencode.Invalid(msg, value, state,
482 error_dict={'paths_root_path': msg})
483 return value
484
485
486 def UniqSystemEmail(old_data):
487 class _UniqSystemEmail(formencode.validators.FancyValidator):
488 def to_python(self, value, state):
489 value = value.lower()
490 if (old_data.get('email') or '').lower() != value:
491 user = User.get_by_email(value, case_insensitive=True)
492 if user:
493 raise formencode.Invalid(
494 _("This e-mail address is already taken"), value, state
495 )
496 return value
497
498 return _UniqSystemEmail
499
500
501 class ValidSystemEmail(formencode.validators.FancyValidator):
502 def to_python(self, value, state):
503 value = value.lower()
504 user = User.get_by_email(value, case_insensitive=True)
505 if user is None:
506 raise formencode.Invalid(
507 _("This e-mail address doesn't exist."), value, state
508 )
509
510 return value
511
512
513 class LdapLibValidator(formencode.validators.FancyValidator):
514
515 def to_python(self, value, state):
516
517 try:
518 import ldap
519 except ImportError:
520 raise LdapImportError
521 return value
522
523
524 class AttrLoginValidator(formencode.validators.FancyValidator):
525
526 def to_python(self, value, state):
527
528 if not value or not isinstance(value, (str, unicode)):
529 raise formencode.Invalid(
530 _("The LDAP Login attribute of the CN must be specified - "
531 "this is the name of the attribute that is equivalent "
532 "to 'username'"), value, state
533 )
534
535 return value
536
537
538 #==============================================================================
539 # FORMS
540 #==============================================================================
541 class LoginForm(formencode.Schema):
35 class LoginForm(formencode.Schema):
542 allow_extra_fields = True
36 allow_extra_fields = True
543 filter_extra_fields = True
37 filter_extra_fields = True
544 username = UnicodeString(
38 username = v.UnicodeString(
545 strip=True,
39 strip=True,
546 min=1,
40 min=1,
547 not_empty=True,
41 not_empty=True,
548 messages={
42 messages={
549 'empty': _('Please enter a login'),
43 'empty': _(u'Please enter a login'),
550 'tooShort': _('Enter a value %(min)i characters long or more')}
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
551 )
45 )
552
46
553 password = UnicodeString(
47 password = v.UnicodeString(
554 strip=False,
48 strip=False,
555 min=3,
49 min=3,
556 not_empty=True,
50 not_empty=True,
557 messages={
51 messages={
558 'empty': _('Please enter a password'),
52 'empty': _(u'Please enter a password'),
559 'tooShort': _('Enter %(min)i characters or more')}
53 'tooShort': _(u'Enter %(min)i characters or more')}
560 )
54 )
561
55
562 remember = StringBoolean(if_missing=False)
56 remember = v.StringBoolean(if_missing=False)
563
57
564 chained_validators = [ValidAuth]
58 chained_validators = [v.ValidAuth()]
565
59
566
60
567 def UserForm(edit=False, old_data={}):
61 def UserForm(edit=False, old_data={}):
568 class _UserForm(formencode.Schema):
62 class _UserForm(formencode.Schema):
569 allow_extra_fields = True
63 allow_extra_fields = True
570 filter_extra_fields = True
64 filter_extra_fields = True
571 username = All(UnicodeString(strip=True, min=1, not_empty=True),
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
572 ValidUsername(edit, old_data))
66 v.ValidUsername(edit, old_data))
573 if edit:
67 if edit:
574 new_password = All(UnicodeString(strip=False, min=6, not_empty=False))
68 new_password = All(
575 password_confirmation = All(UnicodeString(strip=False, min=6,
69 v.UnicodeString(strip=False, min=6, not_empty=False)
576 not_empty=False))
70 )
577 admin = StringBoolean(if_missing=False)
71 password_confirmation = All(
72 v.ValidPassword(),
73 v.UnicodeString(strip=False, min=6, not_empty=False),
74 )
75 admin = v.StringBoolean(if_missing=False)
578 else:
76 else:
579 password = All(UnicodeString(strip=False, min=6, not_empty=True))
77 password = All(
580 password_confirmation = All(UnicodeString(strip=False, min=6,
78 v.ValidPassword(),
581 not_empty=False))
79 v.UnicodeString(strip=False, min=6, not_empty=True)
80 )
81 password_confirmation = All(
82 v.ValidPassword(),
83 v.UnicodeString(strip=False, min=6, not_empty=False)
84 )
582
85
583 active = StringBoolean(if_missing=False)
86 active = v.StringBoolean(if_missing=False)
584 name = UnicodeString(strip=True, min=1, not_empty=False)
87 name = v.UnicodeString(strip=True, min=1, not_empty=False)
585 lastname = UnicodeString(strip=True, min=1, not_empty=False)
88 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
586 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
89 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
587
90
588 chained_validators = [ValidPasswordsMatch, ValidPassword]
91 chained_validators = [v.ValidPasswordsMatch()]
589
92
590 return _UserForm
93 return _UserForm
591
94
592
95
593 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
96 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
594 class _UsersGroupForm(formencode.Schema):
97 class _UsersGroupForm(formencode.Schema):
595 allow_extra_fields = True
98 allow_extra_fields = True
596 filter_extra_fields = True
99 filter_extra_fields = True
597
100
598 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
101 users_group_name = All(
599 ValidUsersGroup(edit, old_data))
102 v.UnicodeString(strip=True, min=1, not_empty=True),
103 v.ValidUsersGroup(edit, old_data)
104 )
600
105
601 users_group_active = StringBoolean(if_missing=False)
106 users_group_active = v.StringBoolean(if_missing=False)
602
107
603 if edit:
108 if edit:
604 users_group_members = OneOf(available_members, hideList=False,
109 users_group_members = v.OneOf(
605 testValueList=True,
110 available_members, hideList=False, testValueList=True,
606 if_missing=None, not_empty=False)
111 if_missing=None, not_empty=False
112 )
607
113
608 return _UsersGroupForm
114 return _UsersGroupForm
609
115
610
116
611 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
117 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
612 class _ReposGroupForm(formencode.Schema):
118 class _ReposGroupForm(formencode.Schema):
613 allow_extra_fields = True
119 allow_extra_fields = True
614 filter_extra_fields = False
120 filter_extra_fields = False
615
121
616 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
122 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
617 SlugifyName())
123 v.SlugifyName())
618 group_description = UnicodeString(strip=True, min=1,
124 group_description = v.UnicodeString(strip=True, min=1,
619 not_empty=True)
125 not_empty=True)
620 group_parent_id = OneOf(available_groups, hideList=False,
126 group_parent_id = v.OneOf(available_groups, hideList=False,
621 testValueList=True,
127 testValueList=True,
622 if_missing=None, not_empty=False)
128 if_missing=None, not_empty=False)
623
129
624 chained_validators = [ValidReposGroup(edit, old_data), ValidPerms('group')]
130 chained_validators = [v.ValidReposGroup(edit, old_data),
131 v.ValidPerms('group')]
625
132
626 return _ReposGroupForm
133 return _ReposGroupForm
627
134
628
135
629 def RegisterForm(edit=False, old_data={}):
136 def RegisterForm(edit=False, old_data={}):
630 class _RegisterForm(formencode.Schema):
137 class _RegisterForm(formencode.Schema):
631 allow_extra_fields = True
138 allow_extra_fields = True
632 filter_extra_fields = True
139 filter_extra_fields = True
633 username = All(ValidUsername(edit, old_data),
140 username = All(
634 UnicodeString(strip=True, min=1, not_empty=True))
141 v.ValidUsername(edit, old_data),
635 password = All(UnicodeString(strip=False, min=6, not_empty=True))
142 v.UnicodeString(strip=True, min=1, not_empty=True)
636 password_confirmation = All(UnicodeString(strip=False, min=6, not_empty=True))
143 )
637 active = StringBoolean(if_missing=False)
144 password = All(
638 name = UnicodeString(strip=True, min=1, not_empty=False)
145 v.ValidPassword(),
639 lastname = UnicodeString(strip=True, min=1, not_empty=False)
146 v.UnicodeString(strip=False, min=6, not_empty=True)
640 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
147 )
148 password_confirmation = All(
149 v.ValidPassword(),
150 v.UnicodeString(strip=False, min=6, not_empty=True)
151 )
152 active = v.StringBoolean(if_missing=False)
153 name = v.UnicodeString(strip=True, min=1, not_empty=False)
154 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
155 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
641
156
642 chained_validators = [ValidPasswordsMatch, ValidPassword]
157 chained_validators = [v.ValidPasswordsMatch()]
643
158
644 return _RegisterForm
159 return _RegisterForm
645
160
646
161
647 def PasswordResetForm():
162 def PasswordResetForm():
648 class _PasswordResetForm(formencode.Schema):
163 class _PasswordResetForm(formencode.Schema):
649 allow_extra_fields = True
164 allow_extra_fields = True
650 filter_extra_fields = True
165 filter_extra_fields = True
651 email = All(ValidSystemEmail(), Email(not_empty=True))
166 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
652 return _PasswordResetForm
167 return _PasswordResetForm
653
168
654
169
655 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
170 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
656 repo_groups=[], landing_revs=[]):
171 repo_groups=[], landing_revs=[]):
657 class _RepoForm(formencode.Schema):
172 class _RepoForm(formencode.Schema):
658 allow_extra_fields = True
173 allow_extra_fields = True
659 filter_extra_fields = False
174 filter_extra_fields = False
660 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
175 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
661 SlugifyName())
176 v.SlugifyName())
662 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False))
177 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
663 repo_group = OneOf(repo_groups, hideList=True)
178 repo_group = v.OneOf(repo_groups, hideList=True)
664 repo_type = OneOf(supported_backends)
179 repo_type = v.OneOf(supported_backends)
665 description = UnicodeString(strip=True, min=1, not_empty=False)
180 description = v.UnicodeString(strip=True, min=1, not_empty=False)
666 private = StringBoolean(if_missing=False)
181 private = v.StringBoolean(if_missing=False)
667 enable_statistics = StringBoolean(if_missing=False)
182 enable_statistics = v.StringBoolean(if_missing=False)
668 enable_downloads = StringBoolean(if_missing=False)
183 enable_downloads = v.StringBoolean(if_missing=False)
669 landing_rev = OneOf(landing_revs, hideList=True)
184 landing_rev = v.OneOf(landing_revs, hideList=True)
670
185
671 if edit:
186 if edit:
672 #this is repo owner
187 #this is repo owner
673 user = All(UnicodeString(not_empty=True), ValidRepoUser)
188 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
674
189
675 chained_validators = [ValidCloneUri()(),
190 chained_validators = [v.ValidCloneUri(),
676 ValidRepoName(edit, old_data),
191 v.ValidRepoName(edit, old_data),
677 ValidPerms()]
192 v.ValidPerms()]
678 return _RepoForm
193 return _RepoForm
679
194
680
195
681 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
196 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
682 repo_groups=[]):
197 repo_groups=[]):
683 class _RepoForkForm(formencode.Schema):
198 class _RepoForkForm(formencode.Schema):
684 allow_extra_fields = True
199 allow_extra_fields = True
685 filter_extra_fields = False
200 filter_extra_fields = False
686 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
201 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
687 SlugifyName())
202 v.SlugifyName())
688 repo_group = OneOf(repo_groups, hideList=True)
203 repo_group = v.OneOf(repo_groups, hideList=True)
689 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
204 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
690 description = UnicodeString(strip=True, min=1, not_empty=True)
205 description = v.UnicodeString(strip=True, min=1, not_empty=True)
691 private = StringBoolean(if_missing=False)
206 private = v.StringBoolean(if_missing=False)
692 copy_permissions = StringBoolean(if_missing=False)
207 copy_permissions = v.StringBoolean(if_missing=False)
693 update_after_clone = StringBoolean(if_missing=False)
208 update_after_clone = v.StringBoolean(if_missing=False)
694 fork_parent_id = UnicodeString()
209 fork_parent_id = v.UnicodeString()
695 chained_validators = [ValidForkName(edit, old_data)]
210 chained_validators = [v.ValidForkName(edit, old_data)]
696
211
697 return _RepoForkForm
212 return _RepoForkForm
698
213
699
214
700 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
215 def RepoSettingsForm(edit=False, old_data={},
701 repo_groups=[], landing_revs=[]):
216 supported_backends=BACKENDS.keys(), repo_groups=[],
217 landing_revs=[]):
702 class _RepoForm(formencode.Schema):
218 class _RepoForm(formencode.Schema):
703 allow_extra_fields = True
219 allow_extra_fields = True
704 filter_extra_fields = False
220 filter_extra_fields = False
705 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
221 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
706 SlugifyName())
222 v.SlugifyName())
707 description = UnicodeString(strip=True, min=1, not_empty=True)
223 description = v.UnicodeString(strip=True, min=1, not_empty=True)
708 repo_group = OneOf(repo_groups, hideList=True)
224 repo_group = v.OneOf(repo_groups, hideList=True)
709 private = StringBoolean(if_missing=False)
225 private = v.StringBoolean(if_missing=False)
710 landing_rev = OneOf(landing_revs, hideList=True)
226 landing_rev = v.OneOf(landing_revs, hideList=True)
711 chained_validators = [ValidRepoName(edit, old_data), ValidPerms(),
227 chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
712 ValidSettings]
228 v.ValidSettings()]
713 return _RepoForm
229 return _RepoForm
714
230
715
231
716 def ApplicationSettingsForm():
232 def ApplicationSettingsForm():
717 class _ApplicationSettingsForm(formencode.Schema):
233 class _ApplicationSettingsForm(formencode.Schema):
718 allow_extra_fields = True
234 allow_extra_fields = True
719 filter_extra_fields = False
235 filter_extra_fields = False
720 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
236 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
721 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
237 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
722 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
238 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
723
239
724 return _ApplicationSettingsForm
240 return _ApplicationSettingsForm
725
241
726
242
727 def ApplicationUiSettingsForm():
243 def ApplicationUiSettingsForm():
728 class _ApplicationUiSettingsForm(formencode.Schema):
244 class _ApplicationUiSettingsForm(formencode.Schema):
729 allow_extra_fields = True
245 allow_extra_fields = True
730 filter_extra_fields = False
246 filter_extra_fields = False
731 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
247 web_push_ssl = v.OneOf(['true', 'false'], if_missing='false')
732 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
248 paths_root_path = All(
733 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
249 v.ValidPath(),
734 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
250 v.UnicodeString(strip=True, min=1, not_empty=True)
735 hooks_changegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
251 )
736 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
252 hooks_changegroup_update = v.OneOf(['True', 'False'],
253 if_missing=False)
254 hooks_changegroup_repo_size = v.OneOf(['True', 'False'],
255 if_missing=False)
256 hooks_changegroup_push_logger = v.OneOf(['True', 'False'],
257 if_missing=False)
258 hooks_preoutgoing_pull_logger = v.OneOf(['True', 'False'],
259 if_missing=False)
737
260
738 return _ApplicationUiSettingsForm
261 return _ApplicationUiSettingsForm
739
262
740
263
741 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
264 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
742 class _DefaultPermissionsForm(formencode.Schema):
265 class _DefaultPermissionsForm(formencode.Schema):
743 allow_extra_fields = True
266 allow_extra_fields = True
744 filter_extra_fields = True
267 filter_extra_fields = True
745 overwrite_default = StringBoolean(if_missing=False)
268 overwrite_default = v.StringBoolean(if_missing=False)
746 anonymous = OneOf(['True', 'False'], if_missing=False)
269 anonymous = v.OneOf(['True', 'False'], if_missing=False)
747 default_perm = OneOf(perms_choices)
270 default_perm = v.OneOf(perms_choices)
748 default_register = OneOf(register_choices)
271 default_register = v.OneOf(register_choices)
749 default_create = OneOf(create_choices)
272 default_create = v.OneOf(create_choices)
750
273
751 return _DefaultPermissionsForm
274 return _DefaultPermissionsForm
752
275
753
276
754 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
277 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
278 tls_kind_choices):
755 class _LdapSettingsForm(formencode.Schema):
279 class _LdapSettingsForm(formencode.Schema):
756 allow_extra_fields = True
280 allow_extra_fields = True
757 filter_extra_fields = True
281 filter_extra_fields = True
758 #pre_validators = [LdapLibValidator]
282 #pre_validators = [LdapLibValidator]
759 ldap_active = StringBoolean(if_missing=False)
283 ldap_active = v.StringBoolean(if_missing=False)
760 ldap_host = UnicodeString(strip=True,)
284 ldap_host = v.UnicodeString(strip=True,)
761 ldap_port = Number(strip=True,)
285 ldap_port = v.Number(strip=True,)
762 ldap_tls_kind = OneOf(tls_kind_choices)
286 ldap_tls_kind = v.OneOf(tls_kind_choices)
763 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
287 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
764 ldap_dn_user = UnicodeString(strip=True,)
288 ldap_dn_user = v.UnicodeString(strip=True,)
765 ldap_dn_pass = UnicodeString(strip=True,)
289 ldap_dn_pass = v.UnicodeString(strip=True,)
766 ldap_base_dn = UnicodeString(strip=True,)
290 ldap_base_dn = v.UnicodeString(strip=True,)
767 ldap_filter = UnicodeString(strip=True,)
291 ldap_filter = v.UnicodeString(strip=True,)
768 ldap_search_scope = OneOf(search_scope_choices)
292 ldap_search_scope = v.OneOf(search_scope_choices)
769 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
293 ldap_attr_login = All(
770 ldap_attr_firstname = UnicodeString(strip=True,)
294 v.AttrLoginValidator(),
771 ldap_attr_lastname = UnicodeString(strip=True,)
295 v.UnicodeString(strip=True,)
772 ldap_attr_email = UnicodeString(strip=True,)
296 )
297 ldap_attr_firstname = v.UnicodeString(strip=True,)
298 ldap_attr_lastname = v.UnicodeString(strip=True,)
299 ldap_attr_email = v.UnicodeString(strip=True,)
773
300
774 return _LdapSettingsForm
301 return _LdapSettingsForm
@@ -1,303 +1,303 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user_group
3 rhodecode.model.user_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 users groups model for RhodeCode
6 users groups model for RhodeCode
7
7
8 :created_on: Jan 25, 2011
8 :created_on: Jan 25, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import shutil
29 import shutil
30
30
31 from rhodecode.lib.utils2 import LazyProperty
31 from rhodecode.lib.utils2 import LazyProperty
32
32
33 from rhodecode.model import BaseModel
33 from rhodecode.model import BaseModel
34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 class ReposGroupModel(BaseModel):
40 class ReposGroupModel(BaseModel):
41
41
42 def __get_users_group(self, users_group):
42 def __get_users_group(self, users_group):
43 return self._get_instance(UsersGroup, users_group,
43 return self._get_instance(UsersGroup, users_group,
44 callback=UsersGroup.get_by_group_name)
44 callback=UsersGroup.get_by_group_name)
45
45
46 def __get_repos_group(self, repos_group):
46 def __get_repos_group(self, repos_group):
47 return self._get_instance(RepoGroup, repos_group,
47 return self._get_instance(RepoGroup, repos_group,
48 callback=RepoGroup.get_by_group_name)
48 callback=RepoGroup.get_by_group_name)
49
49
50 @LazyProperty
50 @LazyProperty
51 def repos_path(self):
51 def repos_path(self):
52 """
52 """
53 Get's the repositories root path from database
53 Get's the repositories root path from database
54 """
54 """
55
55
56 q = RhodeCodeUi.get_by_key('/').one()
56 q = RhodeCodeUi.get_by_key('/').one()
57 return q.ui_value
57 return q.ui_value
58
58
59 def _create_default_perms(self, new_group):
59 def _create_default_perms(self, new_group):
60 # create default permission
60 # create default permission
61 repo_group_to_perm = UserRepoGroupToPerm()
61 repo_group_to_perm = UserRepoGroupToPerm()
62 default_perm = 'group.read'
62 default_perm = 'group.read'
63 for p in User.get_by_username('default').user_perms:
63 for p in User.get_by_username('default').user_perms:
64 if p.permission.permission_name.startswith('group.'):
64 if p.permission.permission_name.startswith('group.'):
65 default_perm = p.permission.permission_name
65 default_perm = p.permission.permission_name
66 break
66 break
67
67
68 repo_group_to_perm.permission_id = self.sa.query(Permission)\
68 repo_group_to_perm.permission_id = self.sa.query(Permission)\
69 .filter(Permission.permission_name == default_perm)\
69 .filter(Permission.permission_name == default_perm)\
70 .one().permission_id
70 .one().permission_id
71
71
72 repo_group_to_perm.group = new_group
72 repo_group_to_perm.group = new_group
73 repo_group_to_perm.user_id = User.get_by_username('default').user_id
73 repo_group_to_perm.user_id = User.get_by_username('default').user_id
74
74
75 self.sa.add(repo_group_to_perm)
75 self.sa.add(repo_group_to_perm)
76
76
77 def __create_group(self, group_name):
77 def __create_group(self, group_name):
78 """
78 """
79 makes repositories group on filesystem
79 makes repositories group on filesystem
80
80
81 :param repo_name:
81 :param repo_name:
82 :param parent_id:
82 :param parent_id:
83 """
83 """
84
84
85 create_path = os.path.join(self.repos_path, group_name)
85 create_path = os.path.join(self.repos_path, group_name)
86 log.debug('creating new group in %s' % create_path)
86 log.debug('creating new group in %s' % create_path)
87
87
88 if os.path.isdir(create_path):
88 if os.path.isdir(create_path):
89 raise Exception('That directory already exists !')
89 raise Exception('That directory already exists !')
90
90
91 os.makedirs(create_path)
91 os.makedirs(create_path)
92
92
93 def __rename_group(self, old, new):
93 def __rename_group(self, old, new):
94 """
94 """
95 Renames a group on filesystem
95 Renames a group on filesystem
96
96
97 :param group_name:
97 :param group_name:
98 """
98 """
99
99
100 if old == new:
100 if old == new:
101 log.debug('skipping group rename')
101 log.debug('skipping group rename')
102 return
102 return
103
103
104 log.debug('renaming repos group from %s to %s' % (old, new))
104 log.debug('renaming repos group from %s to %s' % (old, new))
105
105
106 old_path = os.path.join(self.repos_path, old)
106 old_path = os.path.join(self.repos_path, old)
107 new_path = os.path.join(self.repos_path, new)
107 new_path = os.path.join(self.repos_path, new)
108
108
109 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
109 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
110
110
111 if os.path.isdir(new_path):
111 if os.path.isdir(new_path):
112 raise Exception('Was trying to rename to already '
112 raise Exception('Was trying to rename to already '
113 'existing dir %s' % new_path)
113 'existing dir %s' % new_path)
114 shutil.move(old_path, new_path)
114 shutil.move(old_path, new_path)
115
115
116 def __delete_group(self, group):
116 def __delete_group(self, group):
117 """
117 """
118 Deletes a group from a filesystem
118 Deletes a group from a filesystem
119
119
120 :param group: instance of group from database
120 :param group: instance of group from database
121 """
121 """
122 paths = group.full_path.split(RepoGroup.url_sep())
122 paths = group.full_path.split(RepoGroup.url_sep())
123 paths = os.sep.join(paths)
123 paths = os.sep.join(paths)
124
124
125 rm_path = os.path.join(self.repos_path, paths)
125 rm_path = os.path.join(self.repos_path, paths)
126 if os.path.isdir(rm_path):
126 if os.path.isdir(rm_path):
127 # delete only if that path really exists
127 # delete only if that path really exists
128 os.rmdir(rm_path)
128 os.rmdir(rm_path)
129
129
130 def create(self, group_name, group_description, parent, just_db=False):
130 def create(self, group_name, group_description, parent, just_db=False):
131 try:
131 try:
132 new_repos_group = RepoGroup()
132 new_repos_group = RepoGroup()
133 new_repos_group.group_description = group_description
133 new_repos_group.group_description = group_description
134 new_repos_group.parent_group = self.__get_repos_group(parent)
134 new_repos_group.parent_group = self.__get_repos_group(parent)
135 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
135 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
136
136
137 self.sa.add(new_repos_group)
137 self.sa.add(new_repos_group)
138 self._create_default_perms(new_repos_group)
138 self._create_default_perms(new_repos_group)
139
139
140 if not just_db:
140 if not just_db:
141 # we need to flush here, in order to check if database won't
141 # we need to flush here, in order to check if database won't
142 # throw any exceptions, create filesystem dirs at the very end
142 # throw any exceptions, create filesystem dirs at the very end
143 self.sa.flush()
143 self.sa.flush()
144 self.__create_group(new_repos_group.group_name)
144 self.__create_group(new_repos_group.group_name)
145
145
146 return new_repos_group
146 return new_repos_group
147 except:
147 except:
148 log.error(traceback.format_exc())
148 log.error(traceback.format_exc())
149 raise
149 raise
150
150
151 def update(self, repos_group_id, form_data):
151 def update(self, repos_group_id, form_data):
152
152
153 try:
153 try:
154 repos_group = RepoGroup.get(repos_group_id)
154 repos_group = RepoGroup.get(repos_group_id)
155
155
156 # update permissions
156 # update permissions
157 for member, perm, member_type in form_data['perms_updates']:
157 for member, perm, member_type in form_data['perms_updates']:
158 if member_type == 'user':
158 if member_type == 'user':
159 # this updates also current one if found
159 # this updates also current one if found
160 ReposGroupModel().grant_user_permission(
160 ReposGroupModel().grant_user_permission(
161 repos_group=repos_group, user=member, perm=perm
161 repos_group=repos_group, user=member, perm=perm
162 )
162 )
163 else:
163 else:
164 ReposGroupModel().grant_users_group_permission(
164 ReposGroupModel().grant_users_group_permission(
165 repos_group=repos_group, group_name=member, perm=perm
165 repos_group=repos_group, group_name=member, perm=perm
166 )
166 )
167 # set new permissions
167 # set new permissions
168 for member, perm, member_type in form_data['perms_new']:
168 for member, perm, member_type in form_data['perms_new']:
169 if member_type == 'user':
169 if member_type == 'user':
170 ReposGroupModel().grant_user_permission(
170 ReposGroupModel().grant_user_permission(
171 repos_group=repos_group, user=member, perm=perm
171 repos_group=repos_group, user=member, perm=perm
172 )
172 )
173 else:
173 else:
174 ReposGroupModel().grant_users_group_permission(
174 ReposGroupModel().grant_users_group_permission(
175 repos_group=repos_group, group_name=member, perm=perm
175 repos_group=repos_group, group_name=member, perm=perm
176 )
176 )
177
177
178 old_path = repos_group.full_path
178 old_path = repos_group.full_path
179
179
180 # change properties
180 # change properties
181 repos_group.group_description = form_data['group_description']
181 repos_group.group_description = form_data['group_description']
182 repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
182 repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
183 repos_group.group_parent_id = form_data['group_parent_id']
183 repos_group.group_parent_id = form_data['group_parent_id']
184 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
184 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
185 new_path = repos_group.full_path
185 new_path = repos_group.full_path
186
186
187 self.sa.add(repos_group)
187 self.sa.add(repos_group)
188
188
189 # we need to get all repositories from this new group and
189 # we need to get all repositories from this new group and
190 # rename them accordingly to new group path
190 # rename them accordingly to new group path
191 for r in repos_group.repositories:
191 for r in repos_group.repositories:
192 r.repo_name = r.get_new_name(r.just_name)
192 r.repo_name = r.get_new_name(r.just_name)
193 self.sa.add(r)
193 self.sa.add(r)
194
194
195 self.__rename_group(old_path, new_path)
195 self.__rename_group(old_path, new_path)
196
196
197 return repos_group
197 return repos_group
198 except:
198 except:
199 log.error(traceback.format_exc())
199 log.error(traceback.format_exc())
200 raise
200 raise
201
201
202 def delete(self, users_group_id):
202 def delete(self, repos_group):
203 repos_group = self.__get_repos_group(repos_group)
203 try:
204 try:
204 users_group = RepoGroup.get(users_group_id)
205 self.sa.delete(repos_group)
205 self.sa.delete(users_group)
206 self.__delete_group(repos_group)
206 self.__delete_group(users_group)
207 except:
207 except:
208 log.error(traceback.format_exc())
208 log.exception('Error removing repos_group %s' % repos_group)
209 raise
209 raise
210
210
211 def grant_user_permission(self, repos_group, user, perm):
211 def grant_user_permission(self, repos_group, user, perm):
212 """
212 """
213 Grant permission for user on given repositories group, or update
213 Grant permission for user on given repositories group, or update
214 existing one if found
214 existing one if found
215
215
216 :param repos_group: Instance of ReposGroup, repositories_group_id,
216 :param repos_group: Instance of ReposGroup, repositories_group_id,
217 or repositories_group name
217 or repositories_group name
218 :param user: Instance of User, user_id or username
218 :param user: Instance of User, user_id or username
219 :param perm: Instance of Permission, or permission_name
219 :param perm: Instance of Permission, or permission_name
220 """
220 """
221
221
222 repos_group = self.__get_repos_group(repos_group)
222 repos_group = self.__get_repos_group(repos_group)
223 user = self._get_user(user)
223 user = self._get_user(user)
224 permission = self._get_perm(perm)
224 permission = self._get_perm(perm)
225
225
226 # check if we have that permission already
226 # check if we have that permission already
227 obj = self.sa.query(UserRepoGroupToPerm)\
227 obj = self.sa.query(UserRepoGroupToPerm)\
228 .filter(UserRepoGroupToPerm.user == user)\
228 .filter(UserRepoGroupToPerm.user == user)\
229 .filter(UserRepoGroupToPerm.group == repos_group)\
229 .filter(UserRepoGroupToPerm.group == repos_group)\
230 .scalar()
230 .scalar()
231 if obj is None:
231 if obj is None:
232 # create new !
232 # create new !
233 obj = UserRepoGroupToPerm()
233 obj = UserRepoGroupToPerm()
234 obj.group = repos_group
234 obj.group = repos_group
235 obj.user = user
235 obj.user = user
236 obj.permission = permission
236 obj.permission = permission
237 self.sa.add(obj)
237 self.sa.add(obj)
238
238
239 def revoke_user_permission(self, repos_group, user):
239 def revoke_user_permission(self, repos_group, user):
240 """
240 """
241 Revoke permission for user on given repositories group
241 Revoke permission for user on given repositories group
242
242
243 :param repos_group: Instance of ReposGroup, repositories_group_id,
243 :param repos_group: Instance of ReposGroup, repositories_group_id,
244 or repositories_group name
244 or repositories_group name
245 :param user: Instance of User, user_id or username
245 :param user: Instance of User, user_id or username
246 """
246 """
247
247
248 repos_group = self.__get_repos_group(repos_group)
248 repos_group = self.__get_repos_group(repos_group)
249 user = self._get_user(user)
249 user = self._get_user(user)
250
250
251 obj = self.sa.query(UserRepoGroupToPerm)\
251 obj = self.sa.query(UserRepoGroupToPerm)\
252 .filter(UserRepoGroupToPerm.user == user)\
252 .filter(UserRepoGroupToPerm.user == user)\
253 .filter(UserRepoGroupToPerm.group == repos_group)\
253 .filter(UserRepoGroupToPerm.group == repos_group)\
254 .one()
254 .one()
255 self.sa.delete(obj)
255 self.sa.delete(obj)
256
256
257 def grant_users_group_permission(self, repos_group, group_name, perm):
257 def grant_users_group_permission(self, repos_group, group_name, perm):
258 """
258 """
259 Grant permission for users group on given repositories group, or update
259 Grant permission for users group on given repositories group, or update
260 existing one if found
260 existing one if found
261
261
262 :param repos_group: Instance of ReposGroup, repositories_group_id,
262 :param repos_group: Instance of ReposGroup, repositories_group_id,
263 or repositories_group name
263 or repositories_group name
264 :param group_name: Instance of UserGroup, users_group_id,
264 :param group_name: Instance of UserGroup, users_group_id,
265 or users group name
265 or users group name
266 :param perm: Instance of Permission, or permission_name
266 :param perm: Instance of Permission, or permission_name
267 """
267 """
268 repos_group = self.__get_repos_group(repos_group)
268 repos_group = self.__get_repos_group(repos_group)
269 group_name = self.__get_users_group(group_name)
269 group_name = self.__get_users_group(group_name)
270 permission = self._get_perm(perm)
270 permission = self._get_perm(perm)
271
271
272 # check if we have that permission already
272 # check if we have that permission already
273 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
273 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
274 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
274 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
275 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
275 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
276 .scalar()
276 .scalar()
277
277
278 if obj is None:
278 if obj is None:
279 # create new
279 # create new
280 obj = UsersGroupRepoGroupToPerm()
280 obj = UsersGroupRepoGroupToPerm()
281
281
282 obj.group = repos_group
282 obj.group = repos_group
283 obj.users_group = group_name
283 obj.users_group = group_name
284 obj.permission = permission
284 obj.permission = permission
285 self.sa.add(obj)
285 self.sa.add(obj)
286
286
287 def revoke_users_group_permission(self, repos_group, group_name):
287 def revoke_users_group_permission(self, repos_group, group_name):
288 """
288 """
289 Revoke permission for users group on given repositories group
289 Revoke permission for users group on given repositories group
290
290
291 :param repos_group: Instance of ReposGroup, repositories_group_id,
291 :param repos_group: Instance of ReposGroup, repositories_group_id,
292 or repositories_group name
292 or repositories_group name
293 :param group_name: Instance of UserGroup, users_group_id,
293 :param group_name: Instance of UserGroup, users_group_id,
294 or users group name
294 or users group name
295 """
295 """
296 repos_group = self.__get_repos_group(repos_group)
296 repos_group = self.__get_repos_group(repos_group)
297 group_name = self.__get_users_group(group_name)
297 group_name = self.__get_users_group(group_name)
298
298
299 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
299 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
300 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
300 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
301 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
301 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
302 .one()
302 .one()
303 self.sa.delete(obj)
303 self.sa.delete(obj)
@@ -1,608 +1,613 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user
3 rhodecode.model.user
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 users model for RhodeCode
6 users model for RhodeCode
7
7
8 :created_on: Apr 9, 2010
8 :created_on: Apr 9, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from pylons import url
29 from pylons import url
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31
31
32 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
32 from rhodecode.lib.utils2 import safe_unicode, generate_api_key
33 from rhodecode.lib.caching_query import FromCache
33 from rhodecode.lib.caching_query import FromCache
34
34
35 from rhodecode.model import BaseModel
35 from rhodecode.model import BaseModel
36 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
36 from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
37 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
37 UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
38 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
38 Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \
39 UserEmailMap
39 UserEmailMap
40 from rhodecode.lib.exceptions import DefaultUserException, \
40 from rhodecode.lib.exceptions import DefaultUserException, \
41 UserOwnsReposException
41 UserOwnsReposException
42
42
43 from sqlalchemy.exc import DatabaseError
43 from sqlalchemy.exc import DatabaseError
44
44
45 from sqlalchemy.orm import joinedload
45 from sqlalchemy.orm import joinedload
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 PERM_WEIGHTS = {
50 PERM_WEIGHTS = {
51 'repository.none': 0,
51 'repository.none': 0,
52 'repository.read': 1,
52 'repository.read': 1,
53 'repository.write': 3,
53 'repository.write': 3,
54 'repository.admin': 4,
54 'repository.admin': 4,
55 'group.none': 0,
55 'group.none': 0,
56 'group.read': 1,
56 'group.read': 1,
57 'group.write': 3,
57 'group.write': 3,
58 'group.admin': 4,
58 'group.admin': 4,
59 }
59 }
60
60
61
61
62 class UserModel(BaseModel):
62 class UserModel(BaseModel):
63
63
64 def get(self, user_id, cache=False):
64 def get(self, user_id, cache=False):
65 user = self.sa.query(User)
65 user = self.sa.query(User)
66 if cache:
66 if cache:
67 user = user.options(FromCache("sql_cache_short",
67 user = user.options(FromCache("sql_cache_short",
68 "get_user_%s" % user_id))
68 "get_user_%s" % user_id))
69 return user.get(user_id)
69 return user.get(user_id)
70
70
71 def get_user(self, user):
71 def get_user(self, user):
72 return self._get_user(user)
72 return self._get_user(user)
73
73
74 def get_by_username(self, username, cache=False, case_insensitive=False):
74 def get_by_username(self, username, cache=False, case_insensitive=False):
75
75
76 if case_insensitive:
76 if case_insensitive:
77 user = self.sa.query(User).filter(User.username.ilike(username))
77 user = self.sa.query(User).filter(User.username.ilike(username))
78 else:
78 else:
79 user = self.sa.query(User)\
79 user = self.sa.query(User)\
80 .filter(User.username == username)
80 .filter(User.username == username)
81 if cache:
81 if cache:
82 user = user.options(FromCache("sql_cache_short",
82 user = user.options(FromCache("sql_cache_short",
83 "get_user_%s" % username))
83 "get_user_%s" % username))
84 return user.scalar()
84 return user.scalar()
85
85
86 def get_by_api_key(self, api_key, cache=False):
86 def get_by_api_key(self, api_key, cache=False):
87 return User.get_by_api_key(api_key, cache)
87 return User.get_by_api_key(api_key, cache)
88
88
89 def create(self, form_data):
89 def create(self, form_data):
90 from rhodecode.lib.auth import get_crypt_password
90 try:
91 try:
91 new_user = User()
92 new_user = User()
92 for k, v in form_data.items():
93 for k, v in form_data.items():
94 if k == 'password':
95 v = get_crypt_password(v)
93 setattr(new_user, k, v)
96 setattr(new_user, k, v)
94
97
95 new_user.api_key = generate_api_key(form_data['username'])
98 new_user.api_key = generate_api_key(form_data['username'])
96 self.sa.add(new_user)
99 self.sa.add(new_user)
97 return new_user
100 return new_user
98 except:
101 except:
99 log.error(traceback.format_exc())
102 log.error(traceback.format_exc())
100 raise
103 raise
101
104
102 def create_or_update(self, username, password, email, name, lastname,
105 def create_or_update(self, username, password, email, name, lastname,
103 active=True, admin=False, ldap_dn=None):
106 active=True, admin=False, ldap_dn=None):
104 """
107 """
105 Creates a new instance if not found, or updates current one
108 Creates a new instance if not found, or updates current one
106
109
107 :param username:
110 :param username:
108 :param password:
111 :param password:
109 :param email:
112 :param email:
110 :param active:
113 :param active:
111 :param name:
114 :param name:
112 :param lastname:
115 :param lastname:
113 :param active:
116 :param active:
114 :param admin:
117 :param admin:
115 :param ldap_dn:
118 :param ldap_dn:
116 """
119 """
117
120
118 from rhodecode.lib.auth import get_crypt_password
121 from rhodecode.lib.auth import get_crypt_password
119
122
120 log.debug('Checking for %s account in RhodeCode database' % username)
123 log.debug('Checking for %s account in RhodeCode database' % username)
121 user = User.get_by_username(username, case_insensitive=True)
124 user = User.get_by_username(username, case_insensitive=True)
122 if user is None:
125 if user is None:
123 log.debug('creating new user %s' % username)
126 log.debug('creating new user %s' % username)
124 new_user = User()
127 new_user = User()
125 else:
128 else:
126 log.debug('updating user %s' % username)
129 log.debug('updating user %s' % username)
127 new_user = user
130 new_user = user
128
131
129 try:
132 try:
130 new_user.username = username
133 new_user.username = username
131 new_user.admin = admin
134 new_user.admin = admin
132 new_user.password = get_crypt_password(password)
135 new_user.password = get_crypt_password(password)
133 new_user.api_key = generate_api_key(username)
136 new_user.api_key = generate_api_key(username)
134 new_user.email = email
137 new_user.email = email
135 new_user.active = active
138 new_user.active = active
136 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
139 new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None
137 new_user.name = name
140 new_user.name = name
138 new_user.lastname = lastname
141 new_user.lastname = lastname
139 self.sa.add(new_user)
142 self.sa.add(new_user)
140 return new_user
143 return new_user
141 except (DatabaseError,):
144 except (DatabaseError,):
142 log.error(traceback.format_exc())
145 log.error(traceback.format_exc())
143 raise
146 raise
144
147
145 def create_for_container_auth(self, username, attrs):
148 def create_for_container_auth(self, username, attrs):
146 """
149 """
147 Creates the given user if it's not already in the database
150 Creates the given user if it's not already in the database
148
151
149 :param username:
152 :param username:
150 :param attrs:
153 :param attrs:
151 """
154 """
152 if self.get_by_username(username, case_insensitive=True) is None:
155 if self.get_by_username(username, case_insensitive=True) is None:
153
156
154 # autogenerate email for container account without one
157 # autogenerate email for container account without one
155 generate_email = lambda usr: '%s@container_auth.account' % usr
158 generate_email = lambda usr: '%s@container_auth.account' % usr
156
159
157 try:
160 try:
158 new_user = User()
161 new_user = User()
159 new_user.username = username
162 new_user.username = username
160 new_user.password = None
163 new_user.password = None
161 new_user.api_key = generate_api_key(username)
164 new_user.api_key = generate_api_key(username)
162 new_user.email = attrs['email']
165 new_user.email = attrs['email']
163 new_user.active = attrs.get('active', True)
166 new_user.active = attrs.get('active', True)
164 new_user.name = attrs['name'] or generate_email(username)
167 new_user.name = attrs['name'] or generate_email(username)
165 new_user.lastname = attrs['lastname']
168 new_user.lastname = attrs['lastname']
166
169
167 self.sa.add(new_user)
170 self.sa.add(new_user)
168 return new_user
171 return new_user
169 except (DatabaseError,):
172 except (DatabaseError,):
170 log.error(traceback.format_exc())
173 log.error(traceback.format_exc())
171 self.sa.rollback()
174 self.sa.rollback()
172 raise
175 raise
173 log.debug('User %s already exists. Skipping creation of account'
176 log.debug('User %s already exists. Skipping creation of account'
174 ' for container auth.', username)
177 ' for container auth.', username)
175 return None
178 return None
176
179
177 def create_ldap(self, username, password, user_dn, attrs):
180 def create_ldap(self, username, password, user_dn, attrs):
178 """
181 """
179 Checks if user is in database, if not creates this user marked
182 Checks if user is in database, if not creates this user marked
180 as ldap user
183 as ldap user
181
184
182 :param username:
185 :param username:
183 :param password:
186 :param password:
184 :param user_dn:
187 :param user_dn:
185 :param attrs:
188 :param attrs:
186 """
189 """
187 from rhodecode.lib.auth import get_crypt_password
190 from rhodecode.lib.auth import get_crypt_password
188 log.debug('Checking for such ldap account in RhodeCode database')
191 log.debug('Checking for such ldap account in RhodeCode database')
189 if self.get_by_username(username, case_insensitive=True) is None:
192 if self.get_by_username(username, case_insensitive=True) is None:
190
193
191 # autogenerate email for ldap account without one
194 # autogenerate email for ldap account without one
192 generate_email = lambda usr: '%s@ldap.account' % usr
195 generate_email = lambda usr: '%s@ldap.account' % usr
193
196
194 try:
197 try:
195 new_user = User()
198 new_user = User()
196 username = username.lower()
199 username = username.lower()
197 # add ldap account always lowercase
200 # add ldap account always lowercase
198 new_user.username = username
201 new_user.username = username
199 new_user.password = get_crypt_password(password)
202 new_user.password = get_crypt_password(password)
200 new_user.api_key = generate_api_key(username)
203 new_user.api_key = generate_api_key(username)
201 new_user.email = attrs['email'] or generate_email(username)
204 new_user.email = attrs['email'] or generate_email(username)
202 new_user.active = attrs.get('active', True)
205 new_user.active = attrs.get('active', True)
203 new_user.ldap_dn = safe_unicode(user_dn)
206 new_user.ldap_dn = safe_unicode(user_dn)
204 new_user.name = attrs['name']
207 new_user.name = attrs['name']
205 new_user.lastname = attrs['lastname']
208 new_user.lastname = attrs['lastname']
206
209
207 self.sa.add(new_user)
210 self.sa.add(new_user)
208 return new_user
211 return new_user
209 except (DatabaseError,):
212 except (DatabaseError,):
210 log.error(traceback.format_exc())
213 log.error(traceback.format_exc())
211 self.sa.rollback()
214 self.sa.rollback()
212 raise
215 raise
213 log.debug('this %s user exists skipping creation of ldap account',
216 log.debug('this %s user exists skipping creation of ldap account',
214 username)
217 username)
215 return None
218 return None
216
219
217 def create_registration(self, form_data):
220 def create_registration(self, form_data):
218 from rhodecode.model.notification import NotificationModel
221 from rhodecode.model.notification import NotificationModel
219
222
220 try:
223 try:
221 form_data['admin'] = False
224 form_data['admin'] = False
222 new_user = self.create(form_data)
225 new_user = self.create(form_data)
223
226
224 self.sa.add(new_user)
227 self.sa.add(new_user)
225 self.sa.flush()
228 self.sa.flush()
226
229
227 # notification to admins
230 # notification to admins
228 subject = _('new user registration')
231 subject = _('new user registration')
229 body = ('New user registration\n'
232 body = ('New user registration\n'
230 '---------------------\n'
233 '---------------------\n'
231 '- Username: %s\n'
234 '- Username: %s\n'
232 '- Full Name: %s\n'
235 '- Full Name: %s\n'
233 '- Email: %s\n')
236 '- Email: %s\n')
234 body = body % (new_user.username, new_user.full_name,
237 body = body % (new_user.username, new_user.full_name,
235 new_user.email)
238 new_user.email)
236 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
239 edit_url = url('edit_user', id=new_user.user_id, qualified=True)
237 kw = {'registered_user_url': edit_url}
240 kw = {'registered_user_url': edit_url}
238 NotificationModel().create(created_by=new_user, subject=subject,
241 NotificationModel().create(created_by=new_user, subject=subject,
239 body=body, recipients=None,
242 body=body, recipients=None,
240 type_=Notification.TYPE_REGISTRATION,
243 type_=Notification.TYPE_REGISTRATION,
241 email_kwargs=kw)
244 email_kwargs=kw)
242
245
243 except:
246 except:
244 log.error(traceback.format_exc())
247 log.error(traceback.format_exc())
245 raise
248 raise
246
249
247 def update(self, user_id, form_data):
250 def update(self, user_id, form_data):
248 try:
251 try:
249 user = self.get(user_id, cache=False)
252 user = self.get(user_id, cache=False)
250 if user.username == 'default':
253 if user.username == 'default':
251 raise DefaultUserException(
254 raise DefaultUserException(
252 _("You can't Edit this user since it's"
255 _("You can't Edit this user since it's"
253 " crucial for entire application"))
256 " crucial for entire application"))
254
257
255 for k, v in form_data.items():
258 for k, v in form_data.items():
256 if k == 'new_password' and v != '':
259 if k == 'new_password' and v != '':
257 user.password = v
260 user.password = v
258 user.api_key = generate_api_key(user.username)
261 user.api_key = generate_api_key(user.username)
259 else:
262 else:
260 setattr(user, k, v)
263 setattr(user, k, v)
261
264
262 self.sa.add(user)
265 self.sa.add(user)
263 except:
266 except:
264 log.error(traceback.format_exc())
267 log.error(traceback.format_exc())
265 raise
268 raise
266
269
267 def update_my_account(self, user_id, form_data):
270 def update_my_account(self, user_id, form_data):
271 from rhodecode.lib.auth import get_crypt_password
268 try:
272 try:
269 user = self.get(user_id, cache=False)
273 user = self.get(user_id, cache=False)
270 if user.username == 'default':
274 if user.username == 'default':
271 raise DefaultUserException(
275 raise DefaultUserException(
272 _("You can't Edit this user since it's"
276 _("You can't Edit this user since it's"
273 " crucial for entire application"))
277 " crucial for entire application")
278 )
274 for k, v in form_data.items():
279 for k, v in form_data.items():
275 if k == 'new_password' and v != '':
280 if k == 'new_password' and v != '':
276 user.password = v
281 user.password = get_crypt_password(v)
277 user.api_key = generate_api_key(user.username)
282 user.api_key = generate_api_key(user.username)
278 else:
283 else:
279 if k not in ['admin', 'active']:
284 if k not in ['admin', 'active']:
280 setattr(user, k, v)
285 setattr(user, k, v)
281
286
282 self.sa.add(user)
287 self.sa.add(user)
283 except:
288 except:
284 log.error(traceback.format_exc())
289 log.error(traceback.format_exc())
285 raise
290 raise
286
291
287 def delete(self, user):
292 def delete(self, user):
288 user = self._get_user(user)
293 user = self._get_user(user)
289
294
290 try:
295 try:
291 if user.username == 'default':
296 if user.username == 'default':
292 raise DefaultUserException(
297 raise DefaultUserException(
293 _(u"You can't remove this user since it's"
298 _(u"You can't remove this user since it's"
294 " crucial for entire application")
299 " crucial for entire application")
295 )
300 )
296 if user.repositories:
301 if user.repositories:
297 repos = [x.repo_name for x in user.repositories]
302 repos = [x.repo_name for x in user.repositories]
298 raise UserOwnsReposException(
303 raise UserOwnsReposException(
299 _(u'user "%s" still owns %s repositories and cannot be '
304 _(u'user "%s" still owns %s repositories and cannot be '
300 'removed. Switch owners or remove those repositories. %s')
305 'removed. Switch owners or remove those repositories. %s')
301 % (user.username, len(repos), ', '.join(repos))
306 % (user.username, len(repos), ', '.join(repos))
302 )
307 )
303 self.sa.delete(user)
308 self.sa.delete(user)
304 except:
309 except:
305 log.error(traceback.format_exc())
310 log.error(traceback.format_exc())
306 raise
311 raise
307
312
308 def reset_password_link(self, data):
313 def reset_password_link(self, data):
309 from rhodecode.lib.celerylib import tasks, run_task
314 from rhodecode.lib.celerylib import tasks, run_task
310 run_task(tasks.send_password_link, data['email'])
315 run_task(tasks.send_password_link, data['email'])
311
316
312 def reset_password(self, data):
317 def reset_password(self, data):
313 from rhodecode.lib.celerylib import tasks, run_task
318 from rhodecode.lib.celerylib import tasks, run_task
314 run_task(tasks.reset_user_password, data['email'])
319 run_task(tasks.reset_user_password, data['email'])
315
320
316 def fill_data(self, auth_user, user_id=None, api_key=None):
321 def fill_data(self, auth_user, user_id=None, api_key=None):
317 """
322 """
318 Fetches auth_user by user_id,or api_key if present.
323 Fetches auth_user by user_id,or api_key if present.
319 Fills auth_user attributes with those taken from database.
324 Fills auth_user attributes with those taken from database.
320 Additionally set's is_authenitated if lookup fails
325 Additionally set's is_authenitated if lookup fails
321 present in database
326 present in database
322
327
323 :param auth_user: instance of user to set attributes
328 :param auth_user: instance of user to set attributes
324 :param user_id: user id to fetch by
329 :param user_id: user id to fetch by
325 :param api_key: api key to fetch by
330 :param api_key: api key to fetch by
326 """
331 """
327 if user_id is None and api_key is None:
332 if user_id is None and api_key is None:
328 raise Exception('You need to pass user_id or api_key')
333 raise Exception('You need to pass user_id or api_key')
329
334
330 try:
335 try:
331 if api_key:
336 if api_key:
332 dbuser = self.get_by_api_key(api_key)
337 dbuser = self.get_by_api_key(api_key)
333 else:
338 else:
334 dbuser = self.get(user_id)
339 dbuser = self.get(user_id)
335
340
336 if dbuser is not None and dbuser.active:
341 if dbuser is not None and dbuser.active:
337 log.debug('filling %s data' % dbuser)
342 log.debug('filling %s data' % dbuser)
338 for k, v in dbuser.get_dict().items():
343 for k, v in dbuser.get_dict().items():
339 setattr(auth_user, k, v)
344 setattr(auth_user, k, v)
340 else:
345 else:
341 return False
346 return False
342
347
343 except:
348 except:
344 log.error(traceback.format_exc())
349 log.error(traceback.format_exc())
345 auth_user.is_authenticated = False
350 auth_user.is_authenticated = False
346 return False
351 return False
347
352
348 return True
353 return True
349
354
350 def fill_perms(self, user):
355 def fill_perms(self, user):
351 """
356 """
352 Fills user permission attribute with permissions taken from database
357 Fills user permission attribute with permissions taken from database
353 works for permissions given for repositories, and for permissions that
358 works for permissions given for repositories, and for permissions that
354 are granted to groups
359 are granted to groups
355
360
356 :param user: user instance to fill his perms
361 :param user: user instance to fill his perms
357 """
362 """
358 RK = 'repositories'
363 RK = 'repositories'
359 GK = 'repositories_groups'
364 GK = 'repositories_groups'
360 GLOBAL = 'global'
365 GLOBAL = 'global'
361 user.permissions[RK] = {}
366 user.permissions[RK] = {}
362 user.permissions[GK] = {}
367 user.permissions[GK] = {}
363 user.permissions[GLOBAL] = set()
368 user.permissions[GLOBAL] = set()
364
369
365 #======================================================================
370 #======================================================================
366 # fetch default permissions
371 # fetch default permissions
367 #======================================================================
372 #======================================================================
368 default_user = User.get_by_username('default', cache=True)
373 default_user = User.get_by_username('default', cache=True)
369 default_user_id = default_user.user_id
374 default_user_id = default_user.user_id
370
375
371 default_repo_perms = Permission.get_default_perms(default_user_id)
376 default_repo_perms = Permission.get_default_perms(default_user_id)
372 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
377 default_repo_groups_perms = Permission.get_default_group_perms(default_user_id)
373
378
374 if user.is_admin:
379 if user.is_admin:
375 #==================================================================
380 #==================================================================
376 # admin user have all default rights for repositories
381 # admin user have all default rights for repositories
377 # and groups set to admin
382 # and groups set to admin
378 #==================================================================
383 #==================================================================
379 user.permissions[GLOBAL].add('hg.admin')
384 user.permissions[GLOBAL].add('hg.admin')
380
385
381 # repositories
386 # repositories
382 for perm in default_repo_perms:
387 for perm in default_repo_perms:
383 r_k = perm.UserRepoToPerm.repository.repo_name
388 r_k = perm.UserRepoToPerm.repository.repo_name
384 p = 'repository.admin'
389 p = 'repository.admin'
385 user.permissions[RK][r_k] = p
390 user.permissions[RK][r_k] = p
386
391
387 # repositories groups
392 # repositories groups
388 for perm in default_repo_groups_perms:
393 for perm in default_repo_groups_perms:
389 rg_k = perm.UserRepoGroupToPerm.group.group_name
394 rg_k = perm.UserRepoGroupToPerm.group.group_name
390 p = 'group.admin'
395 p = 'group.admin'
391 user.permissions[GK][rg_k] = p
396 user.permissions[GK][rg_k] = p
392 return user
397 return user
393
398
394 #==================================================================
399 #==================================================================
395 # set default permissions first for repositories and groups
400 # set default permissions first for repositories and groups
396 #==================================================================
401 #==================================================================
397 uid = user.user_id
402 uid = user.user_id
398
403
399 # default global permissions
404 # default global permissions
400 default_global_perms = self.sa.query(UserToPerm)\
405 default_global_perms = self.sa.query(UserToPerm)\
401 .filter(UserToPerm.user_id == default_user_id)
406 .filter(UserToPerm.user_id == default_user_id)
402
407
403 for perm in default_global_perms:
408 for perm in default_global_perms:
404 user.permissions[GLOBAL].add(perm.permission.permission_name)
409 user.permissions[GLOBAL].add(perm.permission.permission_name)
405
410
406 # defaults for repositories, taken from default user
411 # defaults for repositories, taken from default user
407 for perm in default_repo_perms:
412 for perm in default_repo_perms:
408 r_k = perm.UserRepoToPerm.repository.repo_name
413 r_k = perm.UserRepoToPerm.repository.repo_name
409 if perm.Repository.private and not (perm.Repository.user_id == uid):
414 if perm.Repository.private and not (perm.Repository.user_id == uid):
410 # disable defaults for private repos,
415 # disable defaults for private repos,
411 p = 'repository.none'
416 p = 'repository.none'
412 elif perm.Repository.user_id == uid:
417 elif perm.Repository.user_id == uid:
413 # set admin if owner
418 # set admin if owner
414 p = 'repository.admin'
419 p = 'repository.admin'
415 else:
420 else:
416 p = perm.Permission.permission_name
421 p = perm.Permission.permission_name
417
422
418 user.permissions[RK][r_k] = p
423 user.permissions[RK][r_k] = p
419
424
420 # defaults for repositories groups taken from default user permission
425 # defaults for repositories groups taken from default user permission
421 # on given group
426 # on given group
422 for perm in default_repo_groups_perms:
427 for perm in default_repo_groups_perms:
423 rg_k = perm.UserRepoGroupToPerm.group.group_name
428 rg_k = perm.UserRepoGroupToPerm.group.group_name
424 p = perm.Permission.permission_name
429 p = perm.Permission.permission_name
425 user.permissions[GK][rg_k] = p
430 user.permissions[GK][rg_k] = p
426
431
427 #==================================================================
432 #==================================================================
428 # overwrite defaults with user permissions if any found
433 # overwrite defaults with user permissions if any found
429 #==================================================================
434 #==================================================================
430
435
431 # user global permissions
436 # user global permissions
432 user_perms = self.sa.query(UserToPerm)\
437 user_perms = self.sa.query(UserToPerm)\
433 .options(joinedload(UserToPerm.permission))\
438 .options(joinedload(UserToPerm.permission))\
434 .filter(UserToPerm.user_id == uid).all()
439 .filter(UserToPerm.user_id == uid).all()
435
440
436 for perm in user_perms:
441 for perm in user_perms:
437 user.permissions[GLOBAL].add(perm.permission.permission_name)
442 user.permissions[GLOBAL].add(perm.permission.permission_name)
438
443
439 # user explicit permissions for repositories
444 # user explicit permissions for repositories
440 user_repo_perms = \
445 user_repo_perms = \
441 self.sa.query(UserRepoToPerm, Permission, Repository)\
446 self.sa.query(UserRepoToPerm, Permission, Repository)\
442 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
447 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
443 .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
448 .join((Permission, UserRepoToPerm.permission_id == Permission.permission_id))\
444 .filter(UserRepoToPerm.user_id == uid)\
449 .filter(UserRepoToPerm.user_id == uid)\
445 .all()
450 .all()
446
451
447 for perm in user_repo_perms:
452 for perm in user_repo_perms:
448 # set admin if owner
453 # set admin if owner
449 r_k = perm.UserRepoToPerm.repository.repo_name
454 r_k = perm.UserRepoToPerm.repository.repo_name
450 if perm.Repository.user_id == uid:
455 if perm.Repository.user_id == uid:
451 p = 'repository.admin'
456 p = 'repository.admin'
452 else:
457 else:
453 p = perm.Permission.permission_name
458 p = perm.Permission.permission_name
454 user.permissions[RK][r_k] = p
459 user.permissions[RK][r_k] = p
455
460
456 # USER GROUP
461 # USER GROUP
457 #==================================================================
462 #==================================================================
458 # check if user is part of user groups for this repository and
463 # check if user is part of user groups for this repository and
459 # fill in (or replace with higher) permissions
464 # fill in (or replace with higher) permissions
460 #==================================================================
465 #==================================================================
461
466
462 # users group global
467 # users group global
463 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
468 user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\
464 .options(joinedload(UsersGroupToPerm.permission))\
469 .options(joinedload(UsersGroupToPerm.permission))\
465 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
470 .join((UsersGroupMember, UsersGroupToPerm.users_group_id ==
466 UsersGroupMember.users_group_id))\
471 UsersGroupMember.users_group_id))\
467 .filter(UsersGroupMember.user_id == uid).all()
472 .filter(UsersGroupMember.user_id == uid).all()
468
473
469 for perm in user_perms_from_users_groups:
474 for perm in user_perms_from_users_groups:
470 user.permissions[GLOBAL].add(perm.permission.permission_name)
475 user.permissions[GLOBAL].add(perm.permission.permission_name)
471
476
472 # users group for repositories permissions
477 # users group for repositories permissions
473 user_repo_perms_from_users_groups = \
478 user_repo_perms_from_users_groups = \
474 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
479 self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\
475 .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\
480 .join((Repository, UsersGroupRepoToPerm.repository_id == Repository.repo_id))\
476 .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\
481 .join((Permission, UsersGroupRepoToPerm.permission_id == Permission.permission_id))\
477 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\
482 .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == UsersGroupMember.users_group_id))\
478 .filter(UsersGroupMember.user_id == uid)\
483 .filter(UsersGroupMember.user_id == uid)\
479 .all()
484 .all()
480
485
481 for perm in user_repo_perms_from_users_groups:
486 for perm in user_repo_perms_from_users_groups:
482 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
487 r_k = perm.UsersGroupRepoToPerm.repository.repo_name
483 p = perm.Permission.permission_name
488 p = perm.Permission.permission_name
484 cur_perm = user.permissions[RK][r_k]
489 cur_perm = user.permissions[RK][r_k]
485 # overwrite permission only if it's greater than permission
490 # overwrite permission only if it's greater than permission
486 # given from other sources
491 # given from other sources
487 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
492 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
488 user.permissions[RK][r_k] = p
493 user.permissions[RK][r_k] = p
489
494
490 # REPO GROUP
495 # REPO GROUP
491 #==================================================================
496 #==================================================================
492 # get access for this user for repos group and override defaults
497 # get access for this user for repos group and override defaults
493 #==================================================================
498 #==================================================================
494
499
495 # user explicit permissions for repository
500 # user explicit permissions for repository
496 user_repo_groups_perms = \
501 user_repo_groups_perms = \
497 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
502 self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\
498 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
503 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
499 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
504 .join((Permission, UserRepoGroupToPerm.permission_id == Permission.permission_id))\
500 .filter(UserRepoGroupToPerm.user_id == uid)\
505 .filter(UserRepoGroupToPerm.user_id == uid)\
501 .all()
506 .all()
502
507
503 for perm in user_repo_groups_perms:
508 for perm in user_repo_groups_perms:
504 rg_k = perm.UserRepoGroupToPerm.group.group_name
509 rg_k = perm.UserRepoGroupToPerm.group.group_name
505 p = perm.Permission.permission_name
510 p = perm.Permission.permission_name
506 cur_perm = user.permissions[GK][rg_k]
511 cur_perm = user.permissions[GK][rg_k]
507 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
512 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
508 user.permissions[GK][rg_k] = p
513 user.permissions[GK][rg_k] = p
509
514
510 # REPO GROUP + USER GROUP
515 # REPO GROUP + USER GROUP
511 #==================================================================
516 #==================================================================
512 # check if user is part of user groups for this repo group and
517 # check if user is part of user groups for this repo group and
513 # fill in (or replace with higher) permissions
518 # fill in (or replace with higher) permissions
514 #==================================================================
519 #==================================================================
515
520
516 # users group for repositories permissions
521 # users group for repositories permissions
517 user_repo_group_perms_from_users_groups = \
522 user_repo_group_perms_from_users_groups = \
518 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
523 self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\
519 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
524 .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\
520 .join((Permission, UsersGroupRepoGroupToPerm.permission_id == Permission.permission_id))\
525 .join((Permission, UsersGroupRepoGroupToPerm.permission_id == Permission.permission_id))\
521 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
526 .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
522 .filter(UsersGroupMember.user_id == uid)\
527 .filter(UsersGroupMember.user_id == uid)\
523 .all()
528 .all()
524
529
525 for perm in user_repo_group_perms_from_users_groups:
530 for perm in user_repo_group_perms_from_users_groups:
526 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
531 g_k = perm.UsersGroupRepoGroupToPerm.group.group_name
527 p = perm.Permission.permission_name
532 p = perm.Permission.permission_name
528 cur_perm = user.permissions[GK][g_k]
533 cur_perm = user.permissions[GK][g_k]
529 # overwrite permission only if it's greater than permission
534 # overwrite permission only if it's greater than permission
530 # given from other sources
535 # given from other sources
531 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
536 if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
532 user.permissions[GK][g_k] = p
537 user.permissions[GK][g_k] = p
533
538
534 return user
539 return user
535
540
536 def has_perm(self, user, perm):
541 def has_perm(self, user, perm):
537 if not isinstance(perm, Permission):
542 if not isinstance(perm, Permission):
538 raise Exception('perm needs to be an instance of Permission class '
543 raise Exception('perm needs to be an instance of Permission class '
539 'got %s instead' % type(perm))
544 'got %s instead' % type(perm))
540
545
541 user = self._get_user(user)
546 user = self._get_user(user)
542
547
543 return UserToPerm.query().filter(UserToPerm.user == user)\
548 return UserToPerm.query().filter(UserToPerm.user == user)\
544 .filter(UserToPerm.permission == perm).scalar() is not None
549 .filter(UserToPerm.permission == perm).scalar() is not None
545
550
546 def grant_perm(self, user, perm):
551 def grant_perm(self, user, perm):
547 """
552 """
548 Grant user global permissions
553 Grant user global permissions
549
554
550 :param user:
555 :param user:
551 :param perm:
556 :param perm:
552 """
557 """
553 user = self._get_user(user)
558 user = self._get_user(user)
554 perm = self._get_perm(perm)
559 perm = self._get_perm(perm)
555 # if this permission is already granted skip it
560 # if this permission is already granted skip it
556 _perm = UserToPerm.query()\
561 _perm = UserToPerm.query()\
557 .filter(UserToPerm.user == user)\
562 .filter(UserToPerm.user == user)\
558 .filter(UserToPerm.permission == perm)\
563 .filter(UserToPerm.permission == perm)\
559 .scalar()
564 .scalar()
560 if _perm:
565 if _perm:
561 return
566 return
562 new = UserToPerm()
567 new = UserToPerm()
563 new.user = user
568 new.user = user
564 new.permission = perm
569 new.permission = perm
565 self.sa.add(new)
570 self.sa.add(new)
566
571
567 def revoke_perm(self, user, perm):
572 def revoke_perm(self, user, perm):
568 """
573 """
569 Revoke users global permissions
574 Revoke users global permissions
570
575
571 :param user:
576 :param user:
572 :param perm:
577 :param perm:
573 """
578 """
574 user = self._get_user(user)
579 user = self._get_user(user)
575 perm = self._get_perm(perm)
580 perm = self._get_perm(perm)
576
581
577 obj = UserToPerm.query()\
582 obj = UserToPerm.query()\
578 .filter(UserToPerm.user == user)\
583 .filter(UserToPerm.user == user)\
579 .filter(UserToPerm.permission == perm)\
584 .filter(UserToPerm.permission == perm)\
580 .scalar()
585 .scalar()
581 if obj:
586 if obj:
582 self.sa.delete(obj)
587 self.sa.delete(obj)
583
588
584 def add_extra_email(self, user, email):
589 def add_extra_email(self, user, email):
585 """
590 """
586 Adds email address to UserEmailMap
591 Adds email address to UserEmailMap
587
592
588 :param user:
593 :param user:
589 :param email:
594 :param email:
590 """
595 """
591 user = self._get_user(user)
596 user = self._get_user(user)
592 obj = UserEmailMap()
597 obj = UserEmailMap()
593 obj.user = user
598 obj.user = user
594 obj.email = email
599 obj.email = email
595 self.sa.add(obj)
600 self.sa.add(obj)
596 return obj
601 return obj
597
602
598 def delete_extra_email(self, user, email_id):
603 def delete_extra_email(self, user, email_id):
599 """
604 """
600 Removes email address from UserEmailMap
605 Removes email address from UserEmailMap
601
606
602 :param user:
607 :param user:
603 :param email_id:
608 :param email_id:
604 """
609 """
605 user = self._get_user(user)
610 user = self._get_user(user)
606 obj = UserEmailMap.query().get(email_id)
611 obj = UserEmailMap.query().get(email_id)
607 if obj:
612 if obj:
608 self.sa.delete(obj) No newline at end of file
613 self.sa.delete(obj)
@@ -1,212 +1,215 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 from rhodecode.lib.auth import get_crypt_password, check_password
3 from rhodecode.lib.auth import get_crypt_password, check_password
4 from rhodecode.model.db import User, RhodeCodeSetting
4 from rhodecode.model.db import User, RhodeCodeSetting
5 from rhodecode.tests import *
5 from rhodecode.tests import *
6 from rhodecode.lib import helpers as h
7
6
8
7 class TestAdminSettingsController(TestController):
9 class TestAdminSettingsController(TestController):
8
10
9 def test_index(self):
11 def test_index(self):
10 response = self.app.get(url('admin_settings'))
12 response = self.app.get(url('admin_settings'))
11 # Test response...
13 # Test response...
12
14
13 def test_index_as_xml(self):
15 def test_index_as_xml(self):
14 response = self.app.get(url('formatted_admin_settings', format='xml'))
16 response = self.app.get(url('formatted_admin_settings', format='xml'))
15
17
16 def test_create(self):
18 def test_create(self):
17 response = self.app.post(url('admin_settings'))
19 response = self.app.post(url('admin_settings'))
18
20
19 def test_new(self):
21 def test_new(self):
20 response = self.app.get(url('admin_new_setting'))
22 response = self.app.get(url('admin_new_setting'))
21
23
22 def test_new_as_xml(self):
24 def test_new_as_xml(self):
23 response = self.app.get(url('formatted_admin_new_setting', format='xml'))
25 response = self.app.get(url('formatted_admin_new_setting', format='xml'))
24
26
25 def test_update(self):
27 def test_update(self):
26 response = self.app.put(url('admin_setting', setting_id=1))
28 response = self.app.put(url('admin_setting', setting_id=1))
27
29
28 def test_update_browser_fakeout(self):
30 def test_update_browser_fakeout(self):
29 response = self.app.post(url('admin_setting', setting_id=1), params=dict(_method='put'))
31 response = self.app.post(url('admin_setting', setting_id=1), params=dict(_method='put'))
30
32
31 def test_delete(self):
33 def test_delete(self):
32 response = self.app.delete(url('admin_setting', setting_id=1))
34 response = self.app.delete(url('admin_setting', setting_id=1))
33
35
34 def test_delete_browser_fakeout(self):
36 def test_delete_browser_fakeout(self):
35 response = self.app.post(url('admin_setting', setting_id=1), params=dict(_method='delete'))
37 response = self.app.post(url('admin_setting', setting_id=1), params=dict(_method='delete'))
36
38
37 def test_show(self):
39 def test_show(self):
38 response = self.app.get(url('admin_setting', setting_id=1))
40 response = self.app.get(url('admin_setting', setting_id=1))
39
41
40 def test_show_as_xml(self):
42 def test_show_as_xml(self):
41 response = self.app.get(url('formatted_admin_setting', setting_id=1, format='xml'))
43 response = self.app.get(url('formatted_admin_setting', setting_id=1, format='xml'))
42
44
43 def test_edit(self):
45 def test_edit(self):
44 response = self.app.get(url('admin_edit_setting', setting_id=1))
46 response = self.app.get(url('admin_edit_setting', setting_id=1))
45
47
46 def test_edit_as_xml(self):
48 def test_edit_as_xml(self):
47 response = self.app.get(url('formatted_admin_edit_setting',
49 response = self.app.get(url('formatted_admin_edit_setting',
48 setting_id=1, format='xml'))
50 setting_id=1, format='xml'))
49
51
50
51 def test_ga_code_active(self):
52 def test_ga_code_active(self):
52 self.log_user()
53 self.log_user()
53 old_title = 'RhodeCode'
54 old_title = 'RhodeCode'
54 old_realm = 'RhodeCode authentication'
55 old_realm = 'RhodeCode authentication'
55 new_ga_code = 'ga-test-123456789'
56 new_ga_code = 'ga-test-123456789'
56 response = self.app.post(url('admin_setting', setting_id='global'),
57 response = self.app.post(url('admin_setting', setting_id='global'),
57 params=dict(
58 params=dict(
58 _method='put',
59 _method='put',
59 rhodecode_title=old_title,
60 rhodecode_title=old_title,
60 rhodecode_realm=old_realm,
61 rhodecode_realm=old_realm,
61 rhodecode_ga_code=new_ga_code
62 rhodecode_ga_code=new_ga_code
62 ))
63 ))
63
64
64 self.checkSessionFlash(response, 'Updated application settings')
65 self.checkSessionFlash(response, 'Updated application settings')
65
66
66 self.assertEqual(RhodeCodeSetting
67 self.assertEqual(RhodeCodeSetting
67 .get_app_settings()['rhodecode_ga_code'], new_ga_code)
68 .get_app_settings()['rhodecode_ga_code'], new_ga_code)
68
69
69 response = response.follow()
70 response = response.follow()
70 self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
71 self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
71 in response.body)
72 in response.body)
72
73
73 def test_ga_code_inactive(self):
74 def test_ga_code_inactive(self):
74 self.log_user()
75 self.log_user()
75 old_title = 'RhodeCode'
76 old_title = 'RhodeCode'
76 old_realm = 'RhodeCode authentication'
77 old_realm = 'RhodeCode authentication'
77 new_ga_code = ''
78 new_ga_code = ''
78 response = self.app.post(url('admin_setting', setting_id='global'),
79 response = self.app.post(url('admin_setting', setting_id='global'),
79 params=dict(
80 params=dict(
80 _method='put',
81 _method='put',
81 rhodecode_title=old_title,
82 rhodecode_title=old_title,
82 rhodecode_realm=old_realm,
83 rhodecode_realm=old_realm,
83 rhodecode_ga_code=new_ga_code
84 rhodecode_ga_code=new_ga_code
84 ))
85 ))
85
86
86 self.assertTrue('Updated application settings' in
87 self.assertTrue('Updated application settings' in
87 response.session['flash'][0][1])
88 response.session['flash'][0][1])
88 self.assertEqual(RhodeCodeSetting
89 self.assertEqual(RhodeCodeSetting
89 .get_app_settings()['rhodecode_ga_code'], new_ga_code)
90 .get_app_settings()['rhodecode_ga_code'], new_ga_code)
90
91
91 response = response.follow()
92 response = response.follow()
92 self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
93 self.assertTrue("""_gaq.push(['_setAccount', '%s']);""" % new_ga_code
93 not in response.body)
94 not in response.body)
94
95
95
96 def test_title_change(self):
96 def test_title_change(self):
97 self.log_user()
97 self.log_user()
98 old_title = 'RhodeCode'
98 old_title = 'RhodeCode'
99 new_title = old_title + '_changed'
99 new_title = old_title + '_changed'
100 old_realm = 'RhodeCode authentication'
100 old_realm = 'RhodeCode authentication'
101
101
102 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
102 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
103 response = self.app.post(url('admin_setting', setting_id='global'),
103 response = self.app.post(url('admin_setting', setting_id='global'),
104 params=dict(
104 params=dict(
105 _method='put',
105 _method='put',
106 rhodecode_title=new_title,
106 rhodecode_title=new_title,
107 rhodecode_realm=old_realm,
107 rhodecode_realm=old_realm,
108 rhodecode_ga_code=''
108 rhodecode_ga_code=''
109 ))
109 ))
110
110
111 self.checkSessionFlash(response, 'Updated application settings')
111 self.checkSessionFlash(response, 'Updated application settings')
112 self.assertEqual(RhodeCodeSetting
112 self.assertEqual(RhodeCodeSetting
113 .get_app_settings()['rhodecode_title'],
113 .get_app_settings()['rhodecode_title'],
114 new_title.decode('utf-8'))
114 new_title.decode('utf-8'))
115
115
116 response = response.follow()
116 response = response.follow()
117 self.assertTrue("""<h1><a href="/">%s</a></h1>""" % new_title
117 self.assertTrue("""<h1><a href="/">%s</a></h1>""" % new_title
118 in response.body)
118 in response.body)
119
119
120
121 def test_my_account(self):
120 def test_my_account(self):
122 self.log_user()
121 self.log_user()
123 response = self.app.get(url('admin_settings_my_account'))
122 response = self.app.get(url('admin_settings_my_account'))
124
123
125 self.assertTrue('value="test_admin' in response.body)
124 self.assertTrue('value="test_admin' in response.body)
126
125
127 def test_my_account_update(self):
126 def test_my_account_update(self):
128 self.log_user()
127 self.log_user()
129
128
130 new_email = 'new@mail.pl'
129 new_email = 'new@mail.pl'
131 new_name = 'NewName'
130 new_name = 'NewName'
132 new_lastname = 'NewLastname'
131 new_lastname = 'NewLastname'
133 new_password = 'test123'
132 new_password = 'test123'
134
133
135
136 response = self.app.post(url('admin_settings_my_account_update'),
134 response = self.app.post(url('admin_settings_my_account_update'),
137 params=dict(_method='put',
135 params=dict(_method='put',
138 username='test_admin',
136 username='test_admin',
139 new_password=new_password,
137 new_password=new_password,
140 password_confirmation = new_password,
138 password_confirmation=new_password,
141 password='',
139 password='',
142 name=new_name,
140 name=new_name,
143 lastname=new_lastname,
141 lastname=new_lastname,
144 email=new_email,))
142 email=new_email,))
145 response.follow()
143 response.follow()
146
144
147 assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change'
145 assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change'
148 user = self.Session.query(User).filter(User.username == 'test_admin').one()
146 user = self.Session.query(User).filter(User.username == 'test_admin').one()
149 assert user.email == new_email , 'incorrect user email after update got %s vs %s' % (user.email, new_email)
147 assert user.email == new_email, 'incorrect user email after update got %s vs %s' % (user.email, new_email)
150 assert user.name == new_name, 'updated field mismatch %s vs %s' % (user.name, new_name)
148 assert user.name == new_name, 'updated field mismatch %s vs %s' % (user.name, new_name)
151 assert user.lastname == new_lastname, 'updated field mismatch %s vs %s' % (user.lastname, new_lastname)
149 assert user.lastname == new_lastname, 'updated field mismatch %s vs %s' % (user.lastname, new_lastname)
152 assert check_password(new_password, user.password) is True, 'password field mismatch %s vs %s' % (user.password, new_password)
150 assert check_password(new_password, user.password) is True, 'password field mismatch %s vs %s' % (user.password, new_password)
153
151
154 #bring back the admin settings
152 #bring back the admin settings
155 old_email = 'test_admin@mail.com'
153 old_email = 'test_admin@mail.com'
156 old_name = 'RhodeCode'
154 old_name = 'RhodeCode'
157 old_lastname = 'Admin'
155 old_lastname = 'Admin'
158 old_password = 'test12'
156 old_password = 'test12'
159
157
160 response = self.app.post(url('admin_settings_my_account_update'), params=dict(
158 response = self.app.post(url('admin_settings_my_account_update'), params=dict(
161 _method='put',
159 _method='put',
162 username='test_admin',
160 username='test_admin',
163 new_password=old_password,
161 new_password=old_password,
164 password_confirmation = old_password,
162 password_confirmation=old_password,
165 password='',
163 password='',
166 name=old_name,
164 name=old_name,
167 lastname=old_lastname,
165 lastname=old_lastname,
168 email=old_email,))
166 email=old_email,))
169
167
170 response.follow()
168 response.follow()
171 self.checkSessionFlash(response,
169 self.checkSessionFlash(response,
172 'Your account was updated successfully')
170 'Your account was updated successfully')
173
171
174 user = self.Session.query(User).filter(User.username == 'test_admin').one()
172 user = self.Session.query(User).filter(User.username == 'test_admin').one()
175 assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
173 assert user.email == old_email, 'incorrect user email after update got %s vs %s' % (user.email, old_email)
176
174
177 assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
175 assert user.email == old_email, 'incorrect user email after update got %s vs %s' % (user.email, old_email)
178 assert user.name == old_name, 'updated field mismatch %s vs %s' % (user.name, old_name)
176 assert user.name == old_name, 'updated field mismatch %s vs %s' % (user.name, old_name)
179 assert user.lastname == old_lastname, 'updated field mismatch %s vs %s' % (user.lastname, old_lastname)
177 assert user.lastname == old_lastname, 'updated field mismatch %s vs %s' % (user.lastname, old_lastname)
180 assert check_password(old_password, user.password) is True , 'password updated field mismatch %s vs %s' % (user.password, old_password)
178 assert check_password(old_password, user.password) is True, 'password updated field mismatch %s vs %s' % (user.password, old_password)
181
179
182
183 def test_my_account_update_err_email_exists(self):
180 def test_my_account_update_err_email_exists(self):
184 self.log_user()
181 self.log_user()
185
182
186 new_email = 'test_regular@mail.com'#already exisitn email
183 new_email = 'test_regular@mail.com' # already exisitn email
187 response = self.app.post(url('admin_settings_my_account_update'), params=dict(
184 response = self.app.post(url('admin_settings_my_account_update'), params=dict(
188 _method='put',
185 _method='put',
189 username='test_admin',
186 username='test_admin',
190 new_password='test12',
187 new_password='test12',
191 password_confirmation = 'test122',
188 password_confirmation='test122',
192 name='NewName',
189 name='NewName',
193 lastname='NewLastname',
190 lastname='NewLastname',
194 email=new_email,))
191 email=new_email,))
195
192
196 assert 'This e-mail address is already taken' in response.body, 'Missing error message about existing email'
193 assert 'This e-mail address is already taken' in response.body, 'Missing error message about existing email'
197
194
198
199 def test_my_account_update_err(self):
195 def test_my_account_update_err(self):
200 self.log_user('test_regular2', 'test12')
196 self.log_user('test_regular2', 'test12')
201
197
202 new_email = 'newmail.pl'
198 new_email = 'newmail.pl'
203 response = self.app.post(url('admin_settings_my_account_update'), params=dict(
199 response = self.app.post(url('admin_settings_my_account_update'),
200 params=dict(
204 _method='put',
201 _method='put',
205 username='test_admin',
202 username='test_admin',
206 new_password='test12',
203 new_password='test12',
207 password_confirmation = 'test122',
204 password_confirmation='test122',
208 name='NewName',
205 name='NewName',
209 lastname='NewLastname',
206 lastname='NewLastname',
210 email=new_email,))
207 email=new_email,)
211 assert 'An email address must contain a single @' in response.body, 'Missing error message about wrong email'
208 )
212 assert 'This username already exists' in response.body, 'Missing error message about existing user'
209
210 response.mustcontain('An email address must contain a single @')
211 from rhodecode.model import validators
212 msg = validators.ValidUsername(edit=False,
213 old_data={})._messages['username_exists']
214 msg = h.html_escape(msg % {'username': 'test_admin'})
215 response.mustcontain(u"%s" % msg)
@@ -1,179 +1,180 b''
1 from sqlalchemy.orm.exc import NoResultFound
2
1 from rhodecode.tests import *
3 from rhodecode.tests import *
2 from rhodecode.model.db import User, Permission
4 from rhodecode.model.db import User, Permission
3 from rhodecode.lib.auth import check_password
5 from rhodecode.lib.auth import check_password
4 from sqlalchemy.orm.exc import NoResultFound
5 from rhodecode.model.user import UserModel
6 from rhodecode.model.user import UserModel
7 from rhodecode.model import validators
8 from rhodecode.lib import helpers as h
9
6
10
7 class TestAdminUsersController(TestController):
11 class TestAdminUsersController(TestController):
8
12
9 def test_index(self):
13 def test_index(self):
10 self.log_user()
14 self.log_user()
11 response = self.app.get(url('users'))
15 response = self.app.get(url('users'))
12 # Test response...
16 # Test response...
13
17
14 def test_index_as_xml(self):
18 def test_index_as_xml(self):
15 response = self.app.get(url('formatted_users', format='xml'))
19 response = self.app.get(url('formatted_users', format='xml'))
16
20
17 def test_create(self):
21 def test_create(self):
18 self.log_user()
22 self.log_user()
19 username = 'newtestuser'
23 username = 'newtestuser'
20 password = 'test12'
24 password = 'test12'
21 password_confirmation = password
25 password_confirmation = password
22 name = 'name'
26 name = 'name'
23 lastname = 'lastname'
27 lastname = 'lastname'
24 email = 'mail@mail.com'
28 email = 'mail@mail.com'
25
29
26 response = self.app.post(url('users'),
30 response = self.app.post(url('users'),
27 {'username':username,
31 {'username': username,
28 'password':password,
32 'password': password,
29 'password_confirmation':password_confirmation,
33 'password_confirmation': password_confirmation,
30 'name':name,
34 'name': name,
31 'active':True,
35 'active': True,
32 'lastname':lastname,
36 'lastname': lastname,
33 'email':email})
37 'email': email})
34
38
39 self.checkSessionFlash(response, '''created user %s''' % (username))
35
40
36 self.assertTrue('''created user %s''' % (username) in
37 response.session['flash'][0])
38
41
39 new_user = self.Session.query(User).\
42 new_user = self.Session.query(User).\
40 filter(User.username == username).one()
43 filter(User.username == username).one()
41
44
42 self.assertEqual(new_user.username,username)
45 self.assertEqual(new_user.username, username)
43 self.assertEqual(check_password(password, new_user.password),True)
46 self.assertEqual(check_password(password, new_user.password), True)
44 self.assertEqual(new_user.name,name)
47 self.assertEqual(new_user.name, name)
45 self.assertEqual(new_user.lastname,lastname)
48 self.assertEqual(new_user.lastname, lastname)
46 self.assertEqual(new_user.email,email)
49 self.assertEqual(new_user.email, email)
47
50
48 response.follow()
51 response.follow()
49 response = response.follow()
52 response = response.follow()
50 self.assertTrue("""edit">newtestuser</a>""" in response.body)
53 self.assertTrue("""edit">newtestuser</a>""" in response.body)
51
54
52 def test_create_err(self):
55 def test_create_err(self):
53 self.log_user()
56 self.log_user()
54 username = 'new_user'
57 username = 'new_user'
55 password = ''
58 password = ''
56 name = 'name'
59 name = 'name'
57 lastname = 'lastname'
60 lastname = 'lastname'
58 email = 'errmail.com'
61 email = 'errmail.com'
59
62
60 response = self.app.post(url('users'), {'username':username,
63 response = self.app.post(url('users'), {'username': username,
61 'password':password,
64 'password': password,
62 'name':name,
65 'name': name,
63 'active':False,
66 'active': False,
64 'lastname':lastname,
67 'lastname': lastname,
65 'email':email})
68 'email': email})
66
69
67 self.assertTrue("""<span class="error-message">Invalid username</span>""" in response.body)
70 msg = validators.ValidUsername(False, {})._messages['system_invalid_username']
68 self.assertTrue("""<span class="error-message">Please enter a value</span>""" in response.body)
71 msg = h.html_escape(msg % {'username': 'new_user'})
69 self.assertTrue("""<span class="error-message">An email address must contain a single @</span>""" in response.body)
72 response.mustcontain("""<span class="error-message">%s</span>""" % msg)
73 response.mustcontain("""<span class="error-message">Please enter a value</span>""")
74 response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""")
70
75
71 def get_user():
76 def get_user():
72 self.Session.query(User).filter(User.username == username).one()
77 self.Session.query(User).filter(User.username == username).one()
73
78
74 self.assertRaises(NoResultFound, get_user), 'found user in database'
79 self.assertRaises(NoResultFound, get_user), 'found user in database'
75
80
76 def test_new(self):
81 def test_new(self):
77 self.log_user()
82 self.log_user()
78 response = self.app.get(url('new_user'))
83 response = self.app.get(url('new_user'))
79
84
80 def test_new_as_xml(self):
85 def test_new_as_xml(self):
81 response = self.app.get(url('formatted_new_user', format='xml'))
86 response = self.app.get(url('formatted_new_user', format='xml'))
82
87
83 def test_update(self):
88 def test_update(self):
84 response = self.app.put(url('user', id=1))
89 response = self.app.put(url('user', id=1))
85
90
86 def test_update_browser_fakeout(self):
91 def test_update_browser_fakeout(self):
87 response = self.app.post(url('user', id=1), params=dict(_method='put'))
92 response = self.app.post(url('user', id=1), params=dict(_method='put'))
88
93
89 def test_delete(self):
94 def test_delete(self):
90 self.log_user()
95 self.log_user()
91 username = 'newtestuserdeleteme'
96 username = 'newtestuserdeleteme'
92 password = 'test12'
97 password = 'test12'
93 name = 'name'
98 name = 'name'
94 lastname = 'lastname'
99 lastname = 'lastname'
95 email = 'todeletemail@mail.com'
100 email = 'todeletemail@mail.com'
96
101
97 response = self.app.post(url('users'), {'username':username,
102 response = self.app.post(url('users'), {'username': username,
98 'password':password,
103 'password': password,
99 'password_confirmation':password,
104 'password_confirmation': password,
100 'name':name,
105 'name': name,
101 'active':True,
106 'active': True,
102 'lastname':lastname,
107 'lastname': lastname,
103 'email':email})
108 'email': email})
104
109
105 response = response.follow()
110 response = response.follow()
106
111
107 new_user = self.Session.query(User)\
112 new_user = self.Session.query(User)\
108 .filter(User.username == username).one()
113 .filter(User.username == username).one()
109 response = self.app.delete(url('user', id=new_user.user_id))
114 response = self.app.delete(url('user', id=new_user.user_id))
110
115
111 self.assertTrue("""successfully deleted user""" in
116 self.assertTrue("""successfully deleted user""" in
112 response.session['flash'][0])
117 response.session['flash'][0])
113
118
114
115 def test_delete_browser_fakeout(self):
119 def test_delete_browser_fakeout(self):
116 response = self.app.post(url('user', id=1),
120 response = self.app.post(url('user', id=1),
117 params=dict(_method='delete'))
121 params=dict(_method='delete'))
118
122
119 def test_show(self):
123 def test_show(self):
120 response = self.app.get(url('user', id=1))
124 response = self.app.get(url('user', id=1))
121
125
122 def test_show_as_xml(self):
126 def test_show_as_xml(self):
123 response = self.app.get(url('formatted_user', id=1, format='xml'))
127 response = self.app.get(url('formatted_user', id=1, format='xml'))
124
128
125 def test_edit(self):
129 def test_edit(self):
126 self.log_user()
130 self.log_user()
127 user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
131 user = User.get_by_username(TEST_USER_ADMIN_LOGIN)
128 response = self.app.get(url('edit_user', id=user.user_id))
132 response = self.app.get(url('edit_user', id=user.user_id))
129
133
130
131 def test_add_perm_create_repo(self):
134 def test_add_perm_create_repo(self):
132 self.log_user()
135 self.log_user()
133 perm_none = Permission.get_by_key('hg.create.none')
136 perm_none = Permission.get_by_key('hg.create.none')
134 perm_create = Permission.get_by_key('hg.create.repository')
137 perm_create = Permission.get_by_key('hg.create.repository')
135
138
136 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
139 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
137
140
138
139 #User should have None permission on creation repository
141 #User should have None permission on creation repository
140 self.assertEqual(UserModel().has_perm(user, perm_none), False)
142 self.assertEqual(UserModel().has_perm(user, perm_none), False)
141 self.assertEqual(UserModel().has_perm(user, perm_create), False)
143 self.assertEqual(UserModel().has_perm(user, perm_create), False)
142
144
143 response = self.app.post(url('user_perm', id=user.user_id),
145 response = self.app.post(url('user_perm', id=user.user_id),
144 params=dict(_method='put',
146 params=dict(_method='put',
145 create_repo_perm=True))
147 create_repo_perm=True))
146
148
147 perm_none = Permission.get_by_key('hg.create.none')
149 perm_none = Permission.get_by_key('hg.create.none')
148 perm_create = Permission.get_by_key('hg.create.repository')
150 perm_create = Permission.get_by_key('hg.create.repository')
149
151
150 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
152 user = User.get_by_username(TEST_USER_REGULAR_LOGIN)
151 #User should have None permission on creation repository
153 #User should have None permission on creation repository
152 self.assertEqual(UserModel().has_perm(user, perm_none), False)
154 self.assertEqual(UserModel().has_perm(user, perm_none), False)
153 self.assertEqual(UserModel().has_perm(user, perm_create), True)
155 self.assertEqual(UserModel().has_perm(user, perm_create), True)
154
156
155 def test_revoke_perm_create_repo(self):
157 def test_revoke_perm_create_repo(self):
156 self.log_user()
158 self.log_user()
157 perm_none = Permission.get_by_key('hg.create.none')
159 perm_none = Permission.get_by_key('hg.create.none')
158 perm_create = Permission.get_by_key('hg.create.repository')
160 perm_create = Permission.get_by_key('hg.create.repository')
159
161
160 user = User.get_by_username(TEST_USER_REGULAR2_LOGIN)
162 user = User.get_by_username(TEST_USER_REGULAR2_LOGIN)
161
163
162
163 #User should have None permission on creation repository
164 #User should have None permission on creation repository
164 self.assertEqual(UserModel().has_perm(user, perm_none), False)
165 self.assertEqual(UserModel().has_perm(user, perm_none), False)
165 self.assertEqual(UserModel().has_perm(user, perm_create), False)
166 self.assertEqual(UserModel().has_perm(user, perm_create), False)
166
167
167 response = self.app.post(url('user_perm', id=user.user_id),
168 response = self.app.post(url('user_perm', id=user.user_id),
168 params=dict(_method='put'))
169 params=dict(_method='put'))
169
170
170 perm_none = Permission.get_by_key('hg.create.none')
171 perm_none = Permission.get_by_key('hg.create.none')
171 perm_create = Permission.get_by_key('hg.create.repository')
172 perm_create = Permission.get_by_key('hg.create.repository')
172
173
173 user = User.get_by_username(TEST_USER_REGULAR2_LOGIN)
174 user = User.get_by_username(TEST_USER_REGULAR2_LOGIN)
174 #User should have None permission on creation repository
175 #User should have None permission on creation repository
175 self.assertEqual(UserModel().has_perm(user, perm_none), True)
176 self.assertEqual(UserModel().has_perm(user, perm_none), True)
176 self.assertEqual(UserModel().has_perm(user, perm_create), False)
177 self.assertEqual(UserModel().has_perm(user, perm_create), False)
177
178
178 def test_edit_as_xml(self):
179 def test_edit_as_xml(self):
179 response = self.app.get(url('formatted_edit_user', id=1, format='xml'))
180 response = self.app.get(url('formatted_edit_user', id=1, format='xml'))
@@ -1,267 +1,273 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 from rhodecode.tests import *
2 from rhodecode.tests import *
3 from rhodecode.model.db import User, Notification
3 from rhodecode.model.db import User, Notification
4 from rhodecode.lib.utils2 import generate_api_key
4 from rhodecode.lib.utils2 import generate_api_key
5 from rhodecode.lib.auth import check_password
5 from rhodecode.lib.auth import check_password
6 from rhodecode.model.meta import Session
6 from rhodecode.model.meta import Session
7 from rhodecode.lib import helpers as h
8 from rhodecode.model import validators
7
9
8
10
9 class TestLoginController(TestController):
11 class TestLoginController(TestController):
10
12
11 def tearDown(self):
13 def tearDown(self):
12 for n in Notification.query().all():
14 for n in Notification.query().all():
13 Session.delete(n)
15 Session.delete(n)
14
16
15 Session.commit()
17 Session.commit()
16 self.assertEqual(Notification.query().all(), [])
18 self.assertEqual(Notification.query().all(), [])
17
19
18 def test_index(self):
20 def test_index(self):
19 response = self.app.get(url(controller='login', action='index'))
21 response = self.app.get(url(controller='login', action='index'))
20 self.assertEqual(response.status, '200 OK')
22 self.assertEqual(response.status, '200 OK')
21 # Test response...
23 # Test response...
22
24
23 def test_login_admin_ok(self):
25 def test_login_admin_ok(self):
24 response = self.app.post(url(controller='login', action='index'),
26 response = self.app.post(url(controller='login', action='index'),
25 {'username':'test_admin',
27 {'username': 'test_admin',
26 'password':'test12'})
28 'password': 'test12'})
27 self.assertEqual(response.status, '302 Found')
29 self.assertEqual(response.status, '302 Found')
28 self.assertEqual(response.session['rhodecode_user'].get('username') ,
30 self.assertEqual(response.session['rhodecode_user'].get('username'),
29 'test_admin')
31 'test_admin')
30 response = response.follow()
32 response = response.follow()
31 self.assertTrue('%s repository' % HG_REPO in response.body)
33 self.assertTrue('%s repository' % HG_REPO in response.body)
32
34
33 def test_login_regular_ok(self):
35 def test_login_regular_ok(self):
34 response = self.app.post(url(controller='login', action='index'),
36 response = self.app.post(url(controller='login', action='index'),
35 {'username':'test_regular',
37 {'username': 'test_regular',
36 'password':'test12'})
38 'password': 'test12'})
37
39
38 self.assertEqual(response.status, '302 Found')
40 self.assertEqual(response.status, '302 Found')
39 self.assertEqual(response.session['rhodecode_user'].get('username') ,
41 self.assertEqual(response.session['rhodecode_user'].get('username'),
40 'test_regular')
42 'test_regular')
41 response = response.follow()
43 response = response.follow()
42 self.assertTrue('%s repository' % HG_REPO in response.body)
44 self.assertTrue('%s repository' % HG_REPO in response.body)
43 self.assertTrue('<a title="Admin" href="/_admin">' not in response.body)
45 self.assertTrue('<a title="Admin" href="/_admin">' not in response.body)
44
46
45 def test_login_ok_came_from(self):
47 def test_login_ok_came_from(self):
46 test_came_from = '/_admin/users'
48 test_came_from = '/_admin/users'
47 response = self.app.post(url(controller='login', action='index',
49 response = self.app.post(url(controller='login', action='index',
48 came_from=test_came_from),
50 came_from=test_came_from),
49 {'username':'test_admin',
51 {'username': 'test_admin',
50 'password':'test12'})
52 'password': 'test12'})
51 self.assertEqual(response.status, '302 Found')
53 self.assertEqual(response.status, '302 Found')
52 response = response.follow()
54 response = response.follow()
53
55
54 self.assertEqual(response.status, '200 OK')
56 self.assertEqual(response.status, '200 OK')
55 self.assertTrue('Users administration' in response.body)
57 self.assertTrue('Users administration' in response.body)
56
58
57 def test_login_short_password(self):
59 def test_login_short_password(self):
58 response = self.app.post(url(controller='login', action='index'),
60 response = self.app.post(url(controller='login', action='index'),
59 {'username':'test_admin',
61 {'username': 'test_admin',
60 'password':'as'})
62 'password': 'as'})
61 self.assertEqual(response.status, '200 OK')
63 self.assertEqual(response.status, '200 OK')
62
64
63 self.assertTrue('Enter 3 characters or more' in response.body)
65 self.assertTrue('Enter 3 characters or more' in response.body)
64
66
65 def test_login_wrong_username_password(self):
67 def test_login_wrong_username_password(self):
66 response = self.app.post(url(controller='login', action='index'),
68 response = self.app.post(url(controller='login', action='index'),
67 {'username':'error',
69 {'username': 'error',
68 'password':'test12'})
70 'password': 'test12'})
69 self.assertEqual(response.status , '200 OK')
70
71
71 self.assertTrue('invalid user name' in response.body)
72 self.assertTrue('invalid user name' in response.body)
72 self.assertTrue('invalid password' in response.body)
73 self.assertTrue('invalid password' in response.body)
73
74
74 #==========================================================================
75 #==========================================================================
75 # REGISTRATIONS
76 # REGISTRATIONS
76 #==========================================================================
77 #==========================================================================
77 def test_register(self):
78 def test_register(self):
78 response = self.app.get(url(controller='login', action='register'))
79 response = self.app.get(url(controller='login', action='register'))
79 self.assertTrue('Sign Up to RhodeCode' in response.body)
80 self.assertTrue('Sign Up to RhodeCode' in response.body)
80
81
81 def test_register_err_same_username(self):
82 def test_register_err_same_username(self):
83 uname = 'test_admin'
82 response = self.app.post(url(controller='login', action='register'),
84 response = self.app.post(url(controller='login', action='register'),
83 {'username':'test_admin',
85 {'username': uname,
84 'password':'test12',
86 'password': 'test12',
85 'password_confirmation':'test12',
87 'password_confirmation': 'test12',
86 'email':'goodmail@domain.com',
88 'email': 'goodmail@domain.com',
87 'name':'test',
89 'name': 'test',
88 'lastname':'test'})
90 'lastname': 'test'})
89
91
90 self.assertEqual(response.status , '200 OK')
92 msg = validators.ValidUsername()._messages['username_exists']
91 self.assertTrue('This username already exists' in response.body)
93 msg = h.html_escape(msg % {'username': uname})
94 response.mustcontain(msg)
92
95
93 def test_register_err_same_email(self):
96 def test_register_err_same_email(self):
94 response = self.app.post(url(controller='login', action='register'),
97 response = self.app.post(url(controller='login', action='register'),
95 {'username':'test_admin_0',
98 {'username': 'test_admin_0',
96 'password':'test12',
99 'password': 'test12',
97 'password_confirmation':'test12',
100 'password_confirmation': 'test12',
98 'email':'test_admin@mail.com',
101 'email': 'test_admin@mail.com',
99 'name':'test',
102 'name': 'test',
100 'lastname':'test'})
103 'lastname': 'test'})
101
104
102 self.assertEqual(response.status , '200 OK')
105 msg = validators.UniqSystemEmail()()._messages['email_taken']
103 response.mustcontain('This e-mail address is already taken')
106 response.mustcontain(msg)
104
107
105 def test_register_err_same_email_case_sensitive(self):
108 def test_register_err_same_email_case_sensitive(self):
106 response = self.app.post(url(controller='login', action='register'),
109 response = self.app.post(url(controller='login', action='register'),
107 {'username':'test_admin_1',
110 {'username': 'test_admin_1',
108 'password':'test12',
111 'password': 'test12',
109 'password_confirmation':'test12',
112 'password_confirmation': 'test12',
110 'email':'TesT_Admin@mail.COM',
113 'email': 'TesT_Admin@mail.COM',
111 'name':'test',
114 'name': 'test',
112 'lastname':'test'})
115 'lastname': 'test'})
113 self.assertEqual(response.status , '200 OK')
116 msg = validators.UniqSystemEmail()()._messages['email_taken']
114 response.mustcontain('This e-mail address is already taken')
117 response.mustcontain(msg)
115
118
116 def test_register_err_wrong_data(self):
119 def test_register_err_wrong_data(self):
117 response = self.app.post(url(controller='login', action='register'),
120 response = self.app.post(url(controller='login', action='register'),
118 {'username':'xs',
121 {'username': 'xs',
119 'password':'test',
122 'password': 'test',
120 'password_confirmation':'test',
123 'password_confirmation': 'test',
121 'email':'goodmailm',
124 'email': 'goodmailm',
122 'name':'test',
125 'name': 'test',
123 'lastname':'test'})
126 'lastname': 'test'})
124 self.assertEqual(response.status , '200 OK')
127 self.assertEqual(response.status, '200 OK')
125 response.mustcontain('An email address must contain a single @')
128 response.mustcontain('An email address must contain a single @')
126 response.mustcontain('Enter a value 6 characters long or more')
129 response.mustcontain('Enter a value 6 characters long or more')
127
130
128 def test_register_err_username(self):
131 def test_register_err_username(self):
129 response = self.app.post(url(controller='login', action='register'),
132 response = self.app.post(url(controller='login', action='register'),
130 {'username':'error user',
133 {'username': 'error user',
131 'password':'test12',
134 'password': 'test12',
132 'password_confirmation':'test12',
135 'password_confirmation': 'test12',
133 'email':'goodmailm',
136 'email': 'goodmailm',
134 'name':'test',
137 'name': 'test',
135 'lastname':'test'})
138 'lastname': 'test'})
136
139
137 self.assertEqual(response.status , '200 OK')
138 response.mustcontain('An email address must contain a single @')
140 response.mustcontain('An email address must contain a single @')
139 response.mustcontain('Username may only contain '
141 response.mustcontain('Username may only contain '
140 'alphanumeric characters underscores, '
142 'alphanumeric characters underscores, '
141 'periods or dashes and must begin with '
143 'periods or dashes and must begin with '
142 'alphanumeric character')
144 'alphanumeric character')
143
145
144 def test_register_err_case_sensitive(self):
146 def test_register_err_case_sensitive(self):
147 usr = 'Test_Admin'
145 response = self.app.post(url(controller='login', action='register'),
148 response = self.app.post(url(controller='login', action='register'),
146 {'username':'Test_Admin',
149 {'username': usr,
147 'password':'test12',
150 'password': 'test12',
148 'password_confirmation':'test12',
151 'password_confirmation': 'test12',
149 'email':'goodmailm',
152 'email': 'goodmailm',
150 'name':'test',
153 'name': 'test',
151 'lastname':'test'})
154 'lastname': 'test'})
152
155
153 self.assertEqual(response.status , '200 OK')
156 response.mustcontain('An email address must contain a single @')
154 self.assertTrue('An email address must contain a single @' in response.body)
157 msg = validators.ValidUsername()._messages['username_exists']
155 self.assertTrue('This username already exists' in response.body)
158 msg = h.html_escape(msg % {'username': usr})
159 response.mustcontain(msg)
156
160
157 def test_register_special_chars(self):
161 def test_register_special_chars(self):
158 response = self.app.post(url(controller='login', action='register'),
162 response = self.app.post(url(controller='login', action='register'),
159 {'username':'xxxaxn',
163 {'username': 'xxxaxn',
160 'password':'Δ…Δ‡ΕΊΕΌΔ…Ε›Ε›Ε›Ε›',
164 'password': 'Δ…Δ‡ΕΊΕΌΔ…Ε›Ε›Ε›Ε›',
161 'password_confirmation':'Δ…Δ‡ΕΊΕΌΔ…Ε›Ε›Ε›Ε›',
165 'password_confirmation': 'Δ…Δ‡ΕΊΕΌΔ…Ε›Ε›Ε›Ε›',
162 'email':'goodmailm@test.plx',
166 'email': 'goodmailm@test.plx',
163 'name':'test',
167 'name': 'test',
164 'lastname':'test'})
168 'lastname': 'test'})
165
169
166 self.assertEqual(response.status , '200 OK')
170 msg = validators.ValidPassword()._messages['invalid_password']
167 self.assertTrue('Invalid characters in password' in response.body)
171 response.mustcontain(msg)
168
172
169 def test_register_password_mismatch(self):
173 def test_register_password_mismatch(self):
170 response = self.app.post(url(controller='login', action='register'),
174 response = self.app.post(url(controller='login', action='register'),
171 {'username':'xs',
175 {'username': 'xs',
172 'password':'123qwe',
176 'password': '123qwe',
173 'password_confirmation':'qwe123',
177 'password_confirmation': 'qwe123',
174 'email':'goodmailm@test.plxa',
178 'email': 'goodmailm@test.plxa',
175 'name':'test',
179 'name': 'test',
176 'lastname':'test'})
180 'lastname': 'test'})
177
181 msg = validators.ValidPasswordsMatch()._messages['password_mismatch']
178 self.assertEqual(response.status, '200 OK')
182 response.mustcontain(msg)
179 response.mustcontain('Passwords do not match')
180
183
181 def test_register_ok(self):
184 def test_register_ok(self):
182 username = 'test_regular4'
185 username = 'test_regular4'
183 password = 'qweqwe'
186 password = 'qweqwe'
184 email = 'marcin@test.com'
187 email = 'marcin@test.com'
185 name = 'testname'
188 name = 'testname'
186 lastname = 'testlastname'
189 lastname = 'testlastname'
187
190
188 response = self.app.post(url(controller='login', action='register'),
191 response = self.app.post(url(controller='login', action='register'),
189 {'username':username,
192 {'username': username,
190 'password':password,
193 'password': password,
191 'password_confirmation':password,
194 'password_confirmation': password,
192 'email':email,
195 'email': email,
193 'name':name,
196 'name': name,
194 'lastname':lastname,
197 'lastname': lastname,
195 'admin':True}) # This should be overriden
198 'admin': True}) # This should be overriden
196 self.assertEqual(response.status, '302 Found')
199 self.assertEqual(response.status, '302 Found')
197 self.checkSessionFlash(response, 'You have successfully registered into rhodecode')
200 self.checkSessionFlash(response, 'You have successfully registered into rhodecode')
198
201
199 ret = self.Session.query(User).filter(User.username == 'test_regular4').one()
202 ret = self.Session.query(User).filter(User.username == 'test_regular4').one()
200 self.assertEqual(ret.username, username)
203 self.assertEqual(ret.username, username)
201 self.assertEqual(check_password(password, ret.password), True)
204 self.assertEqual(check_password(password, ret.password), True)
202 self.assertEqual(ret.email, email)
205 self.assertEqual(ret.email, email)
203 self.assertEqual(ret.name, name)
206 self.assertEqual(ret.name, name)
204 self.assertEqual(ret.lastname, lastname)
207 self.assertEqual(ret.lastname, lastname)
205 self.assertNotEqual(ret.api_key, None)
208 self.assertNotEqual(ret.api_key, None)
206 self.assertEqual(ret.admin, False)
209 self.assertEqual(ret.admin, False)
207
210
208 def test_forgot_password_wrong_mail(self):
211 def test_forgot_password_wrong_mail(self):
212 bad_email = 'marcin@wrongmail.org'
209 response = self.app.post(
213 response = self.app.post(
210 url(controller='login', action='password_reset'),
214 url(controller='login', action='password_reset'),
211 {'email': 'marcin@wrongmail.org',}
215 {'email': bad_email, }
212 )
216 )
213
217
214 response.mustcontain("This e-mail address doesn't exist")
218 msg = validators.ValidSystemEmail()._messages['non_existing_email']
219 msg = h.html_escape(msg % {'email': bad_email})
220 response.mustcontain()
215
221
216 def test_forgot_password(self):
222 def test_forgot_password(self):
217 response = self.app.get(url(controller='login',
223 response = self.app.get(url(controller='login',
218 action='password_reset'))
224 action='password_reset'))
219 self.assertEqual(response.status, '200 OK')
225 self.assertEqual(response.status, '200 OK')
220
226
221 username = 'test_password_reset_1'
227 username = 'test_password_reset_1'
222 password = 'qweqwe'
228 password = 'qweqwe'
223 email = 'marcin@python-works.com'
229 email = 'marcin@python-works.com'
224 name = 'passwd'
230 name = 'passwd'
225 lastname = 'reset'
231 lastname = 'reset'
226
232
227 new = User()
233 new = User()
228 new.username = username
234 new.username = username
229 new.password = password
235 new.password = password
230 new.email = email
236 new.email = email
231 new.name = name
237 new.name = name
232 new.lastname = lastname
238 new.lastname = lastname
233 new.api_key = generate_api_key(username)
239 new.api_key = generate_api_key(username)
234 self.Session.add(new)
240 self.Session.add(new)
235 self.Session.commit()
241 self.Session.commit()
236
242
237 response = self.app.post(url(controller='login',
243 response = self.app.post(url(controller='login',
238 action='password_reset'),
244 action='password_reset'),
239 {'email':email, })
245 {'email': email, })
240
246
241 self.checkSessionFlash(response, 'Your password reset link was sent')
247 self.checkSessionFlash(response, 'Your password reset link was sent')
242
248
243 response = response.follow()
249 response = response.follow()
244
250
245 # BAD KEY
251 # BAD KEY
246
252
247 key = "bad"
253 key = "bad"
248 response = self.app.get(url(controller='login',
254 response = self.app.get(url(controller='login',
249 action='password_reset_confirmation',
255 action='password_reset_confirmation',
250 key=key))
256 key=key))
251 self.assertEqual(response.status, '302 Found')
257 self.assertEqual(response.status, '302 Found')
252 self.assertTrue(response.location.endswith(url('reset_password')))
258 self.assertTrue(response.location.endswith(url('reset_password')))
253
259
254 # GOOD KEY
260 # GOOD KEY
255
261
256 key = User.get_by_username(username).api_key
262 key = User.get_by_username(username).api_key
257 response = self.app.get(url(controller='login',
263 response = self.app.get(url(controller='login',
258 action='password_reset_confirmation',
264 action='password_reset_confirmation',
259 key=key))
265 key=key))
260 self.assertEqual(response.status, '302 Found')
266 self.assertEqual(response.status, '302 Found')
261 self.assertTrue(response.location.endswith(url('login_home')))
267 self.assertTrue(response.location.endswith(url('login_home')))
262
268
263 self.checkSessionFlash(response,
269 self.checkSessionFlash(response,
264 ('Your password reset was successful, '
270 ('Your password reset was successful, '
265 'new password has been sent to your email'))
271 'new password has been sent to your email'))
266
272
267 response = response.follow()
273 response = response.follow()
General Comments 0
You need to be logged in to leave comments. Login now