##// END OF EJS Templates
Added user registration, changed login url schema, moved it into _admin/ for safety
marcink -
r363:98abf895 default
parent child Browse files
Show More
@@ -1,129 +1,131
1 """Routes configuration
1 """Routes configuration
2
2
3 The more specific and detailed routes should be defined first so they
3 The more specific and detailed routes should be defined first so they
4 may take precedent over the more generic routes. For more information
4 may take precedent over the more generic routes. For more information
5 refer to the routes manual at http://routes.groovie.org/docs/
5 refer to the routes manual at http://routes.groovie.org/docs/
6 """
6 """
7 from routes import Mapper
7 from routes import Mapper
8 from pylons_app.lib.utils import check_repo_fast as cr
8 from pylons_app.lib.utils import check_repo_fast as cr
9
9
10 def make_map(config):
10 def make_map(config):
11 """Create, configure and return the routes Mapper"""
11 """Create, configure and return the routes Mapper"""
12 map = Mapper(directory=config['pylons.paths']['controllers'],
12 map = Mapper(directory=config['pylons.paths']['controllers'],
13 always_scan=config['debug'])
13 always_scan=config['debug'])
14 map.minimization = False
14 map.minimization = False
15 map.explicit = False
15 map.explicit = False
16
16
17 # The ErrorController route (handles 404/500 error pages); it should
17 # The ErrorController route (handles 404/500 error pages); it should
18 # likely stay at the top, ensuring it can always be resolved
18 # likely stay at the top, ensuring it can always be resolved
19 map.connect('/error/{action}', controller='error')
19 map.connect('/error/{action}', controller='error')
20 map.connect('/error/{action}/{id}', controller='error')
20 map.connect('/error/{action}/{id}', controller='error')
21
21
22 # CUSTOM ROUTES HERE
22 # CUSTOM ROUTES HERE
23 map.connect('hg_home', '/', controller='hg', action='index')
23 map.connect('hg_home', '/', controller='hg', action='index')
24
24
25 def check_repo(environ, match_dict):
25 def check_repo(environ, match_dict):
26 """
26 """
27 check for valid repository for proper 404 handling
27 check for valid repository for proper 404 handling
28 @param environ:
28 @param environ:
29 @param match_dict:
29 @param match_dict:
30 """
30 """
31 repo_name = match_dict.get('repo_name')
31 repo_name = match_dict.get('repo_name')
32 return not cr(repo_name, config['base_path'])
32 return not cr(repo_name, config['base_path'])
33
33
34 #REST routes
34 #REST routes
35 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
35 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
36 m.connect("repos", "/repos",
36 m.connect("repos", "/repos",
37 action="create", conditions=dict(method=["POST"]))
37 action="create", conditions=dict(method=["POST"]))
38 m.connect("repos", "/repos",
38 m.connect("repos", "/repos",
39 action="index", conditions=dict(method=["GET"]))
39 action="index", conditions=dict(method=["GET"]))
40 m.connect("formatted_repos", "/repos.{format}",
40 m.connect("formatted_repos", "/repos.{format}",
41 action="index",
41 action="index",
42 conditions=dict(method=["GET"]))
42 conditions=dict(method=["GET"]))
43 m.connect("new_repo", "/repos/new",
43 m.connect("new_repo", "/repos/new",
44 action="new", conditions=dict(method=["GET"]))
44 action="new", conditions=dict(method=["GET"]))
45 m.connect("formatted_new_repo", "/repos/new.{format}",
45 m.connect("formatted_new_repo", "/repos/new.{format}",
46 action="new", conditions=dict(method=["GET"]))
46 action="new", conditions=dict(method=["GET"]))
47 m.connect("/repos/{repo_name:.*}",
47 m.connect("/repos/{repo_name:.*}",
48 action="update", conditions=dict(method=["PUT"],
48 action="update", conditions=dict(method=["PUT"],
49 function=check_repo))
49 function=check_repo))
50 m.connect("/repos/{repo_name:.*}",
50 m.connect("/repos/{repo_name:.*}",
51 action="delete", conditions=dict(method=["DELETE"],
51 action="delete", conditions=dict(method=["DELETE"],
52 function=check_repo))
52 function=check_repo))
53 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
53 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
54 action="edit", conditions=dict(method=["GET"],
54 action="edit", conditions=dict(method=["GET"],
55 function=check_repo))
55 function=check_repo))
56 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
56 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
57 action="edit", conditions=dict(method=["GET"],
57 action="edit", conditions=dict(method=["GET"],
58 function=check_repo))
58 function=check_repo))
59 m.connect("repo", "/repos/{repo_name:.*}",
59 m.connect("repo", "/repos/{repo_name:.*}",
60 action="show", conditions=dict(method=["GET"],
60 action="show", conditions=dict(method=["GET"],
61 function=check_repo))
61 function=check_repo))
62 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
62 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
63 action="show", conditions=dict(method=["GET"],
63 action="show", conditions=dict(method=["GET"],
64 function=check_repo))
64 function=check_repo))
65 #ajax delete repo perm user
65 #ajax delete repo perm user
66 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
66 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
67 action="delete_perm_user", conditions=dict(method=["DELETE"],
67 action="delete_perm_user", conditions=dict(method=["DELETE"],
68 function=check_repo))
68 function=check_repo))
69
69
70 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
70 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
71 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
71 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
72 map.resource('setting', 'settings', controller='admin/settings', path_prefix='/_admin', name_prefix='admin_')
72 map.resource('setting', 'settings', controller='admin/settings', path_prefix='/_admin', name_prefix='admin_')
73
73
74 #ADMIN
74 #ADMIN
75 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
75 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
76 m.connect('admin_home', '', action='index')#main page
76 m.connect('admin_home', '', action='index')#main page
77 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
77 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
78 action='add_repo')
78 action='add_repo')
79
79
80 #LOGIN/LOGOUT
81 map.connect('login_home', '/_admin/login', controller='login')
82 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
83 map.connect('register', '/_admin/register', controller='login', action='register')
84
80 #FEEDS
85 #FEEDS
81 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
86 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
82 controller='feed', action='rss',
87 controller='feed', action='rss',
83 conditions=dict(function=check_repo))
88 conditions=dict(function=check_repo))
84 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
89 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
85 controller='feed', action='atom',
90 controller='feed', action='atom',
86 conditions=dict(function=check_repo))
91 conditions=dict(function=check_repo))
87
92
88 #LOGIN/LOGOUT
89 map.connect('login_home', '/login', controller='login')
90 map.connect('logout_home', '/logout', controller='login', action='logout')
91
93
92 #OTHERS
94 #OTHERS
93 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
95 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
94 controller='changeset', revision='tip',
96 controller='changeset', revision='tip',
95 conditions=dict(function=check_repo))
97 conditions=dict(function=check_repo))
96 map.connect('summary_home', '/{repo_name:.*}/summary',
98 map.connect('summary_home', '/{repo_name:.*}/summary',
97 controller='summary', conditions=dict(function=check_repo))
99 controller='summary', conditions=dict(function=check_repo))
98 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
100 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
99 controller='shortlog', conditions=dict(function=check_repo))
101 controller='shortlog', conditions=dict(function=check_repo))
100 map.connect('branches_home', '/{repo_name:.*}/branches',
102 map.connect('branches_home', '/{repo_name:.*}/branches',
101 controller='branches', conditions=dict(function=check_repo))
103 controller='branches', conditions=dict(function=check_repo))
102 map.connect('tags_home', '/{repo_name:.*}/tags',
104 map.connect('tags_home', '/{repo_name:.*}/tags',
103 controller='tags', conditions=dict(function=check_repo))
105 controller='tags', conditions=dict(function=check_repo))
104 map.connect('changelog_home', '/{repo_name:.*}/changelog',
106 map.connect('changelog_home', '/{repo_name:.*}/changelog',
105 controller='changelog', conditions=dict(function=check_repo))
107 controller='changelog', conditions=dict(function=check_repo))
106 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
108 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
107 controller='files', revision='tip', f_path='',
109 controller='files', revision='tip', f_path='',
108 conditions=dict(function=check_repo))
110 conditions=dict(function=check_repo))
109 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
111 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
110 controller='files', action='diff', revision='tip', f_path='',
112 controller='files', action='diff', revision='tip', f_path='',
111 conditions=dict(function=check_repo))
113 conditions=dict(function=check_repo))
112 map.connect('files_raw_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
114 map.connect('files_raw_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
113 controller='files', action='rawfile', revision='tip', f_path='',
115 controller='files', action='rawfile', revision='tip', f_path='',
114 conditions=dict(function=check_repo))
116 conditions=dict(function=check_repo))
115 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
117 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
116 controller='files', action='annotate', revision='tip', f_path='',
118 controller='files', action='annotate', revision='tip', f_path='',
117 conditions=dict(function=check_repo))
119 conditions=dict(function=check_repo))
118 map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}',
120 map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}',
119 controller='files', action='archivefile', revision='tip',
121 controller='files', action='archivefile', revision='tip',
120 conditions=dict(function=check_repo))
122 conditions=dict(function=check_repo))
121 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
123 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
122 controller='settings', action="update",
124 controller='settings', action="update",
123 conditions=dict(method=["PUT"], function=check_repo))
125 conditions=dict(method=["PUT"], function=check_repo))
124 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
126 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
125 controller='settings', action='index',
127 controller='settings', action='index',
126 conditions=dict(function=check_repo))
128 conditions=dict(function=check_repo))
127
129
128
130
129 return map
131 return map
@@ -1,67 +1,88
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # login controller for pylons
3 # login controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 from formencode import htmlfill
21 from pylons import request, response, session, tmpl_context as c, url
22 from pylons.controllers.util import abort, redirect
23 from pylons_app.lib.auth import AuthUser
24 from pylons_app.lib.base import BaseController, render
25 from pylons_app.model.forms import LoginForm, RegisterForm
26 from pylons_app.model.user_model import UserModel
27 import formencode
28 import logging
20 """
29 """
21 Created on April 22, 2010
30 Created on April 22, 2010
22 login controller for pylons
31 login controller for pylons
23 @author: marcink
32 @author: marcink
24 """
33 """
25 import logging
26 from formencode import htmlfill
27 from pylons import request, response, session, tmpl_context as c, url
28 from pylons.controllers.util import abort, redirect
29 from pylons_app.lib.base import BaseController, render
30 import formencode
31 from pylons_app.model.forms import LoginForm
32 from pylons_app.lib.auth import AuthUser
33
34
34 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
35
36
36 class LoginController(BaseController):
37 class LoginController(BaseController):
37
38
38 def __before__(self):
39 def __before__(self):
39 super(LoginController, self).__before__()
40 super(LoginController, self).__before__()
40
41
41 def index(self):
42 def index(self):
42 #redirect if already logged in
43 #redirect if already logged in
43 if c.hg_app_user.is_authenticated:
44 if c.hg_app_user.is_authenticated:
44 return redirect(url('hg_home'))
45 return redirect(url('hg_home'))
45
46
46 if request.POST:
47 if request.POST:
47 #import Login Form validator class
48 #import Login Form validator class
48 login_form = LoginForm()
49 login_form = LoginForm()
49 try:
50 try:
50 c.form_result = login_form.to_python(dict(request.POST))
51 c.form_result = login_form.to_python(dict(request.POST))
51 return redirect(url('hg_home'))
52 return redirect(url('hg_home'))
52
53
53 except formencode.Invalid as errors:
54 except formencode.Invalid as errors:
54 return htmlfill.render(
55 return htmlfill.render(
55 render('/login.html'),
56 render('/login.html'),
56 defaults=errors.value,
57 defaults=errors.value,
57 errors=errors.error_dict or {},
58 errors=errors.error_dict or {},
58 prefix_error=False,
59 prefix_error=False,
59 encoding="UTF-8")
60 encoding="UTF-8")
60
61
61 return render('/login.html')
62 return render('/login.html')
62
63
64
65 def register(self):
66 if request.POST:
67 user_model = UserModel()
68 register_form = RegisterForm()()
69 try:
70 form_result = register_form.to_python(dict(request.POST))
71 user_model.create_registration(form_result)
72 return redirect(url('login_home'))
73
74 except formencode.Invalid as errors:
75 return htmlfill.render(
76 render('/register.html'),
77 defaults=errors.value,
78 errors=errors.error_dict or {},
79 prefix_error=False,
80 encoding="UTF-8")
81
82 return render('/register.html')
83
63 def logout(self):
84 def logout(self):
64 session['hg_app_user'] = AuthUser()
85 session['hg_app_user'] = AuthUser()
65 session.save()
86 session.save()
66 log.info('Logging out and setting user as Empty')
87 log.info('Logging out and setting user as Empty')
67 redirect(url('hg_home'))
88 redirect(url('hg_home'))
@@ -1,304 +1,307
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 from formencode import All
22 from formencode import All
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
24 Email, Bool, StringBoolean
24 Email, Bool, StringBoolean
25 from pylons import session
25 from pylons import session
26 from pylons.i18n.translation import _
26 from pylons.i18n.translation import _
27 from pylons_app.lib.auth import get_crypt_password
27 from pylons_app.lib.auth import get_crypt_password
28 import pylons_app.lib.helpers as h
28 import pylons_app.lib.helpers as h
29 from pylons_app.model import meta
29 from pylons_app.model import meta
30 from pylons_app.model.db import User, Repository
30 from pylons_app.model.db import User, Repository
31 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.exc import OperationalError
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34 import datetime
34 import datetime
35 import formencode
35 import formencode
36 import logging
36 import logging
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 #this is needed to translate the messages using _() in validators
40 #this is needed to translate the messages using _() in validators
41 class State_obj(object):
41 class State_obj(object):
42 _ = staticmethod(_)
42 _ = staticmethod(_)
43
43
44 #===============================================================================
44 #===============================================================================
45 # VALIDATORS
45 # VALIDATORS
46 #===============================================================================
46 #===============================================================================
47 class ValidAuthToken(formencode.validators.FancyValidator):
47 class ValidAuthToken(formencode.validators.FancyValidator):
48 messages = {'invalid_token':_('Token mismatch')}
48 messages = {'invalid_token':_('Token mismatch')}
49
49
50 def validate_python(self, value, state):
50 def validate_python(self, value, state):
51
51
52 if value != authentication_token():
52 if value != authentication_token():
53 raise formencode.Invalid(self.message('invalid_token', state,
53 raise formencode.Invalid(self.message('invalid_token', state,
54 search_number=value), value, state)
54 search_number=value), value, state)
55
55
56 def ValidUsername(edit, old_data):
56 def ValidUsername(edit, old_data):
57 class _ValidUsername(formencode.validators.FancyValidator):
57 class _ValidUsername(formencode.validators.FancyValidator):
58
58
59 def validate_python(self, value, state):
59 def validate_python(self, value, state):
60 if value in ['default', 'new_user']:
60 if value in ['default', 'new_user']:
61 raise formencode.Invalid(_('Invalid username'), value, state)
61 raise formencode.Invalid(_('Invalid username'), value, state)
62 #check if user is uniq
62 #check if user is uniq
63 sa = meta.Session
63 sa = meta.Session
64 old_un = None
64 old_un = None
65 if edit:
65 if edit:
66 old_un = sa.query(User).get(old_data.get('user_id')).username
66 old_un = sa.query(User).get(old_data.get('user_id')).username
67
67
68 if old_un != value or not edit:
68 if old_un != value or not edit:
69 if sa.query(User).filter(User.username == value).scalar():
69 if sa.query(User).filter(User.username == value).scalar():
70 raise formencode.Invalid(_('This username already exists') ,
70 raise formencode.Invalid(_('This username already exists') ,
71 value, state)
71 value, state)
72 meta.Session.remove()
72 meta.Session.remove()
73
73
74 return _ValidUsername
74 return _ValidUsername
75
75
76 class ValidPassword(formencode.validators.FancyValidator):
76 class ValidPassword(formencode.validators.FancyValidator):
77
77
78 def to_python(self, value, state):
78 def to_python(self, value, state):
79 if value:
79 if value:
80 return get_crypt_password(value)
80 return get_crypt_password(value)
81
81
82 class ValidAuth(formencode.validators.FancyValidator):
82 class ValidAuth(formencode.validators.FancyValidator):
83 messages = {
83 messages = {
84 'invalid_password':_('invalid password'),
84 'invalid_password':_('invalid password'),
85 'invalid_login':_('invalid user name'),
85 'invalid_login':_('invalid user name'),
86 'disabled_account':_('Your acccount is disabled')
86 'disabled_account':_('Your acccount is disabled')
87
87
88 }
88 }
89 #error mapping
89 #error mapping
90 e_dict = {'username':messages['invalid_login'],
90 e_dict = {'username':messages['invalid_login'],
91 'password':messages['invalid_password']}
91 'password':messages['invalid_password']}
92 e_dict_disable = {'username':messages['disabled_account']}
92 e_dict_disable = {'username':messages['disabled_account']}
93
93
94 def validate_python(self, value, state):
94 def validate_python(self, value, state):
95 sa = meta.Session
95 sa = meta.Session
96 crypted_passwd = get_crypt_password(value['password'])
96 crypted_passwd = get_crypt_password(value['password'])
97 username = value['username']
97 username = value['username']
98 try:
98 try:
99 user = sa.query(User).filter(User.username == username).one()
99 user = sa.query(User).filter(User.username == username).one()
100 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
100 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
101 log.error(e)
101 log.error(e)
102 user = None
102 user = None
103 raise formencode.Invalid(self.message('invalid_password',
103 raise formencode.Invalid(self.message('invalid_password',
104 state=State_obj), value, state,
104 state=State_obj), value, state,
105 error_dict=self.e_dict)
105 error_dict=self.e_dict)
106 if user:
106 if user:
107 if user.active:
107 if user.active:
108 if user.username == username and user.password == crypted_passwd:
108 if user.username == username and user.password == crypted_passwd:
109 from pylons_app.lib.auth import AuthUser
109 from pylons_app.lib.auth import AuthUser
110 auth_user = AuthUser()
110 auth_user = AuthUser()
111 auth_user.username = username
111 auth_user.username = username
112 auth_user.is_authenticated = True
112 auth_user.is_authenticated = True
113 auth_user.is_admin = user.admin
113 auth_user.is_admin = user.admin
114 auth_user.user_id = user.user_id
114 auth_user.user_id = user.user_id
115 auth_user.name = user.name
115 auth_user.name = user.name
116 auth_user.lastname = user.lastname
116 auth_user.lastname = user.lastname
117 session['hg_app_user'] = auth_user
117 session['hg_app_user'] = auth_user
118 session.save()
118 session.save()
119 log.info('user %s is now authenticated', username)
119 log.info('user %s is now authenticated', username)
120
120
121 try:
121 try:
122 user.last_login = datetime.datetime.now()
122 user.last_login = datetime.datetime.now()
123 sa.add(user)
123 sa.add(user)
124 sa.commit()
124 sa.commit()
125 except (OperationalError) as e:
125 except (OperationalError) as e:
126 log.error(e)
126 log.error(e)
127 sa.rollback()
127 sa.rollback()
128
128
129 return value
129 return value
130 else:
130 else:
131 log.warning('user %s not authenticated', username)
131 log.warning('user %s not authenticated', username)
132 raise formencode.Invalid(self.message('invalid_password',
132 raise formencode.Invalid(self.message('invalid_password',
133 state=State_obj), value, state,
133 state=State_obj), value, state,
134 error_dict=self.e_dict)
134 error_dict=self.e_dict)
135 else:
135 else:
136 log.warning('user %s is disabled', username)
136 log.warning('user %s is disabled', username)
137 raise formencode.Invalid(self.message('disabled_account',
137 raise formencode.Invalid(self.message('disabled_account',
138 state=State_obj),
138 state=State_obj),
139 value, state,
139 value, state,
140 error_dict=self.e_dict_disable)
140 error_dict=self.e_dict_disable)
141
141
142 meta.Session.remove()
142 meta.Session.remove()
143
143
144
144
145 class ValidRepoUser(formencode.validators.FancyValidator):
145 class ValidRepoUser(formencode.validators.FancyValidator):
146
146
147 def to_python(self, value, state):
147 def to_python(self, value, state):
148 sa = meta.Session
148 sa = meta.Session
149 try:
149 try:
150 self.user_db = sa.query(User)\
150 self.user_db = sa.query(User)\
151 .filter(User.active == True)\
151 .filter(User.active == True)\
152 .filter(User.username == value).one()
152 .filter(User.username == value).one()
153 except Exception:
153 except Exception:
154 raise formencode.Invalid(_('This username is not valid'),
154 raise formencode.Invalid(_('This username is not valid'),
155 value, state)
155 value, state)
156 meta.Session.remove()
156 meta.Session.remove()
157 return self.user_db.user_id
157 return self.user_db.user_id
158
158
159 def ValidRepoName(edit, old_data):
159 def ValidRepoName(edit, old_data):
160 class _ValidRepoName(formencode.validators.FancyValidator):
160 class _ValidRepoName(formencode.validators.FancyValidator):
161
161
162 def to_python(self, value, state):
162 def to_python(self, value, state):
163 slug = h.repo_name_slug(value)
163 slug = h.repo_name_slug(value)
164 if slug in ['_admin']:
164 if slug in ['_admin']:
165 raise formencode.Invalid(_('This repository name is disallowed'),
165 raise formencode.Invalid(_('This repository name is disallowed'),
166 value, state)
166 value, state)
167
167
168 if old_data.get('repo_name') != value or not edit:
168 if old_data.get('repo_name') != value or not edit:
169 sa = meta.Session
169 sa = meta.Session
170 if sa.query(Repository).get(slug):
170 if sa.query(Repository).get(slug):
171 raise formencode.Invalid(_('This repository already exists') ,
171 raise formencode.Invalid(_('This repository already exists') ,
172 value, state)
172 value, state)
173 meta.Session.remove()
173 meta.Session.remove()
174 return slug
174 return slug
175
175
176
176
177 return _ValidRepoName
177 return _ValidRepoName
178
178
179 class ValidPerms(formencode.validators.FancyValidator):
179 class ValidPerms(formencode.validators.FancyValidator):
180 messages = {'perm_new_user_name':_('This username is not valid')}
180 messages = {'perm_new_user_name':_('This username is not valid')}
181
181
182 def to_python(self, value, state):
182 def to_python(self, value, state):
183 perms_update = []
183 perms_update = []
184 perms_new = []
184 perms_new = []
185 #build a list of permission to update and new permission to create
185 #build a list of permission to update and new permission to create
186 for k, v in value.items():
186 for k, v in value.items():
187 if k.startswith('perm_'):
187 if k.startswith('perm_'):
188 if k.startswith('perm_new_user'):
188 if k.startswith('perm_new_user'):
189 new_perm = value.get('perm_new_user', False)
189 new_perm = value.get('perm_new_user', False)
190 new_user = value.get('perm_new_user_name', False)
190 new_user = value.get('perm_new_user_name', False)
191 if new_user and new_perm:
191 if new_user and new_perm:
192 if (new_user, new_perm) not in perms_new:
192 if (new_user, new_perm) not in perms_new:
193 perms_new.append((new_user, new_perm))
193 perms_new.append((new_user, new_perm))
194 else:
194 else:
195 usr = k[5:]
195 usr = k[5:]
196 if usr == 'default':
196 if usr == 'default':
197 if value['private']:
197 if value['private']:
198 #set none for default when updating to private repo
198 #set none for default when updating to private repo
199 v = 'repository.none'
199 v = 'repository.none'
200 perms_update.append((usr, v))
200 perms_update.append((usr, v))
201 value['perms_updates'] = perms_update
201 value['perms_updates'] = perms_update
202 value['perms_new'] = perms_new
202 value['perms_new'] = perms_new
203 sa = meta.Session
203 sa = meta.Session
204 for k, v in perms_new:
204 for k, v in perms_new:
205 try:
205 try:
206 self.user_db = sa.query(User)\
206 self.user_db = sa.query(User)\
207 .filter(User.active == True)\
207 .filter(User.active == True)\
208 .filter(User.username == k).one()
208 .filter(User.username == k).one()
209 except Exception:
209 except Exception:
210 msg = self.message('perm_new_user_name',
210 msg = self.message('perm_new_user_name',
211 state=State_obj)
211 state=State_obj)
212 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
212 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
213 return value
213 return value
214
214
215 class ValidSettings(formencode.validators.FancyValidator):
215 class ValidSettings(formencode.validators.FancyValidator):
216
216
217 def to_python(self, value, state):
217 def to_python(self, value, state):
218 #settings form can't edit user
218 #settings form can't edit user
219 if value.has_key('user'):
219 if value.has_key('user'):
220 del['value']['user']
220 del['value']['user']
221
221
222 return value
222 return value
223 #===============================================================================
223 #===============================================================================
224 # FORMS
224 # FORMS
225 #===============================================================================
225 #===============================================================================
226 class LoginForm(formencode.Schema):
226 class LoginForm(formencode.Schema):
227 allow_extra_fields = True
227 allow_extra_fields = True
228 filter_extra_fields = True
228 filter_extra_fields = True
229 username = UnicodeString(
229 username = UnicodeString(
230 strip=True,
230 strip=True,
231 min=3,
231 min=3,
232 not_empty=True,
232 not_empty=True,
233 messages={
233 messages={
234 'empty':_('Please enter a login'),
234 'empty':_('Please enter a login'),
235 'tooShort':_('Enter a value %(min)i characters long or more')}
235 'tooShort':_('Enter a value %(min)i characters long or more')}
236 )
236 )
237
237
238 password = UnicodeString(
238 password = UnicodeString(
239 strip=True,
239 strip=True,
240 min=3,
240 min=3,
241 not_empty=True,
241 not_empty=True,
242 messages={
242 messages={
243 'empty':_('Please enter a password'),
243 'empty':_('Please enter a password'),
244 'tooShort':_('Enter a value %(min)i characters long or more')}
244 'tooShort':_('Enter a value %(min)i characters long or more')}
245 )
245 )
246
246
247
247
248 #chained validators have access to all data
248 #chained validators have access to all data
249 chained_validators = [ValidAuth]
249 chained_validators = [ValidAuth]
250
250
251 def UserForm(edit=False, old_data={}):
251 def UserForm(edit=False, old_data={}):
252 class _UserForm(formencode.Schema):
252 class _UserForm(formencode.Schema):
253 allow_extra_fields = True
253 allow_extra_fields = True
254 filter_extra_fields = True
254 filter_extra_fields = True
255 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
255 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
256 if edit:
256 if edit:
257 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
257 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
258 admin = StringBoolean(if_missing=False)
258 admin = StringBoolean(if_missing=False)
259 else:
259 else:
260 password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
260 password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
261 active = StringBoolean(if_missing=False)
261 active = StringBoolean(if_missing=False)
262 name = UnicodeString(strip=True, min=3, not_empty=True)
262 name = UnicodeString(strip=True, min=3, not_empty=True)
263 lastname = UnicodeString(strip=True, min=3, not_empty=True)
263 lastname = UnicodeString(strip=True, min=3, not_empty=True)
264 email = Email(not_empty=True)
264 email = Email(not_empty=True)
265
265
266 return _UserForm
266 return _UserForm
267
267
268 RegisterForm = UserForm
269
270
268 def RepoForm(edit=False, old_data={}):
271 def RepoForm(edit=False, old_data={}):
269 class _RepoForm(formencode.Schema):
272 class _RepoForm(formencode.Schema):
270 allow_extra_fields = True
273 allow_extra_fields = True
271 filter_extra_fields = False
274 filter_extra_fields = False
272 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
275 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
273 description = UnicodeString(strip=True, min=3, not_empty=True)
276 description = UnicodeString(strip=True, min=3, not_empty=True)
274 private = StringBoolean(if_missing=False)
277 private = StringBoolean(if_missing=False)
275
278
276 if edit:
279 if edit:
277 user = All(Int(not_empty=True), ValidRepoUser)
280 user = All(Int(not_empty=True), ValidRepoUser)
278
281
279 chained_validators = [ValidPerms]
282 chained_validators = [ValidPerms]
280 return _RepoForm
283 return _RepoForm
281
284
282 def RepoSettingsForm(edit=False, old_data={}):
285 def RepoSettingsForm(edit=False, old_data={}):
283 class _RepoForm(formencode.Schema):
286 class _RepoForm(formencode.Schema):
284 allow_extra_fields = True
287 allow_extra_fields = True
285 filter_extra_fields = False
288 filter_extra_fields = False
286 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
289 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
287 description = UnicodeString(strip=True, min=3, not_empty=True)
290 description = UnicodeString(strip=True, min=3, not_empty=True)
288 private = StringBoolean(if_missing=False)
291 private = StringBoolean(if_missing=False)
289
292
290 chained_validators = [ValidPerms, ValidSettings]
293 chained_validators = [ValidPerms, ValidSettings]
291 return _RepoForm
294 return _RepoForm
292
295
293
296
294 def ApplicationSettingsForm():
297 def ApplicationSettingsForm():
295 class _ApplicationSettingsForm(formencode.Schema):
298 class _ApplicationSettingsForm(formencode.Schema):
296 allow_extra_fields = True
299 allow_extra_fields = True
297 filter_extra_fields = False
300 filter_extra_fields = False
298 app_title = UnicodeString(strip=True, min=3, not_empty=True)
301 app_title = UnicodeString(strip=True, min=3, not_empty=True)
299 app_auth_realm = UnicodeString(strip=True, min=3, not_empty=True)
302 app_auth_realm = UnicodeString(strip=True, min=3, not_empty=True)
300
303
301 return _ApplicationSettingsForm
304 return _ApplicationSettingsForm
302
305
303
306
304
307
@@ -1,90 +1,105
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for users
3 # Model for users
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
5
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20
20
21 """
21 """
22 Created on April 9, 2010
22 Created on April 9, 2010
23 Model for users
23 Model for users
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26
27 from pylons_app.model.db import User
27 from pylons_app.model.db import User
28 from pylons_app.model.meta import Session
28 from pylons_app.model.meta import Session
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30 import logging
30 import logging
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33 class DefaultUserException(Exception):pass
33 class DefaultUserException(Exception):pass
34
34
35 class UserModel(object):
35 class UserModel(object):
36
36
37 def __init__(self):
37 def __init__(self):
38 self.sa = Session()
38 self.sa = Session()
39
39
40 def get_user(self, id):
40 def get_user(self, id):
41 return self.sa.query(User).get(id)
41 return self.sa.query(User).get(id)
42
42
43 def create(self, form_data):
43 def create(self, form_data):
44 try:
44 try:
45 new_user = User()
45 new_user = User()
46 for k, v in form_data.items():
46 for k, v in form_data.items():
47 setattr(new_user, k, v)
47 setattr(new_user, k, v)
48
48
49 self.sa.add(new_user)
49 self.sa.add(new_user)
50 self.sa.commit()
50 self.sa.commit()
51 except Exception as e:
51 except Exception as e:
52 log.error(e)
52 log.error(e)
53 self.sa.rollback()
53 self.sa.rollback()
54 raise
54 raise
55
55
56 def create_registration(self, form_data):
57 try:
58 new_user = User()
59 for k, v in form_data.items():
60 if k != 'admin' or k != 'active':
61 setattr(new_user, k, v)
62 setattr(new_user, 'active', True)
63
64 self.sa.add(new_user)
65 self.sa.commit()
66 except Exception as e:
67 log.error(e)
68 self.sa.rollback()
69 raise
70
56 def update(self, id, form_data):
71 def update(self, id, form_data):
57 try:
72 try:
58 new_user = self.sa.query(User).get(id)
73 new_user = self.sa.query(User).get(id)
59 if new_user.username == 'default':
74 if new_user.username == 'default':
60 raise DefaultUserException(
75 raise DefaultUserException(
61 _("You can't Edit this user since it's"
76 _("You can't Edit this user since it's"
62 " crucial for entire application"))
77 " crucial for entire application"))
63 for k, v in form_data.items():
78 for k, v in form_data.items():
64 if k == 'new_password' and v != '':
79 if k == 'new_password' and v != '':
65 new_user.password = v
80 new_user.password = v
66 else:
81 else:
67 setattr(new_user, k, v)
82 setattr(new_user, k, v)
68
83
69 self.sa.add(new_user)
84 self.sa.add(new_user)
70 self.sa.commit()
85 self.sa.commit()
71 except Exception as e:
86 except Exception as e:
72 log.error(e)
87 log.error(e)
73 self.sa.rollback()
88 self.sa.rollback()
74 raise
89 raise
75
90
76 def delete(self, id):
91 def delete(self, id):
77
92
78 try:
93 try:
79
94
80 user = self.sa.query(User).get(id)
95 user = self.sa.query(User).get(id)
81 if user.username == 'default':
96 if user.username == 'default':
82 raise DefaultUserException(
97 raise DefaultUserException(
83 _("You can't remove this user since it's"
98 _("You can't remove this user since it's"
84 " crucial for entire application"))
99 " crucial for entire application"))
85 self.sa.delete(user)
100 self.sa.delete(user)
86 self.sa.commit()
101 self.sa.commit()
87 except Exception as e:
102 except Exception as e:
88 log.error(e)
103 log.error(e)
89 self.sa.rollback()
104 self.sa.rollback()
90 raise
105 raise
General Comments 0
You need to be logged in to leave comments. Login now