##// END OF EJS Templates
moved loged in user propagation out of forms,...
marcink -
r442:d66a7fa7 default
parent child Browse files
Show More
@@ -1,155 +1,155 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # pylons_app - Pylons environment configuration #
3 # pylons_app - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 ############################################
10 ############################################
11 ## Uncomment and replace with the address ##
11 ## Uncomment and replace with the address ##
12 ## which should receive any error reports ##
12 ## which should receive any error reports ##
13 ############################################
13 ############################################
14 #email_to = admin@localhost
14 #email_to = admin@localhost
15 #smtp_server = mail.server.com
15 #smtp_server = mail.server.com
16 #error_email_from = paste_error@localhost
16 #error_email_from = paste_error@localhost
17 #smtp_username =
17 #smtp_username =
18 #smtp_password =
18 #smtp_password =
19 #error_message = 'mercurial crash !'
19 #error_message = 'mercurial crash !'
20
20
21 [server:main]
21 [server:main]
22 ##nr of threads to spawn
22 ##nr of threads to spawn
23 threadpool_workers = 5
23 threadpool_workers = 5
24
24
25 ##max request before
25 ##max request before
26 threadpool_max_requests = 2
26 threadpool_max_requests = 2
27
27
28 ##option to use threads of process
28 ##option to use threads of process
29 use_threadpool = true
29 use_threadpool = true
30
30
31 use = egg:Paste#http
31 use = egg:Paste#http
32 host = 127.0.0.1
32 host = 127.0.0.1
33 port = 8001
33 port = 8001
34
34
35 [app:main]
35 [app:main]
36 use = egg:pylons_app
36 use = egg:pylons_app
37 full_stack = true
37 full_stack = true
38 static_files = false
38 static_files = false
39 lang=en
39 lang=en
40 cache_dir = %(here)s/data
40 cache_dir = %(here)s/data
41
41
42 ####################################
42 ####################################
43 ### BEAKER CACHE ####
43 ### BEAKER CACHE ####
44 ####################################
44 ####################################
45 beaker.cache.data_dir=/%(here)s/data/cache/data
45 beaker.cache.data_dir=/%(here)s/data/cache/data
46 beaker.cache.lock_dir=/%(here)s/data/cache/lock
46 beaker.cache.lock_dir=/%(here)s/data/cache/lock
47 beaker.cache.regions=super_short_term,short_term,long_term
47 beaker.cache.regions=super_short_term,short_term,long_term
48 beaker.cache.long_term.type=memory
48 beaker.cache.long_term.type=memory
49 beaker.cache.long_term.expire=36000
49 beaker.cache.long_term.expire=36000
50 beaker.cache.short_term.type=memory
50 beaker.cache.short_term.type=memory
51 beaker.cache.short_term.expire=60
51 beaker.cache.short_term.expire=60
52 beaker.cache.super_short_term.type=memory
52 beaker.cache.super_short_term.type=memory
53 beaker.cache.super_short_term.expire=10
53 beaker.cache.super_short_term.expire=10
54
54
55 ####################################
55 ####################################
56 ### BEAKER SESSION ####
56 ### BEAKER SESSION ####
57 ####################################
57 ####################################
58 ## Type of storage used for the session, current types are
58 ## Type of storage used for the session, current types are
59 ## β€œdbm”, β€œfile”, β€œmemcached”, β€œdatabase”, and β€œmemory”.
59 ## dbm, file, memcached, database, and memory.
60 ## The storage uses the Container API
60 ## The storage uses the Container API
61 ##that is also used by the cache system.
61 ##that is also used by the cache system.
62 beaker.session.type = file
62 beaker.session.type = file
63
63
64 beaker.session.key = hg-app
64 beaker.session.key = hg-app
65 beaker.session.secret = g654dcno0-9873jhgfreyu
65 beaker.session.secret = g654dcno0-9873jhgfreyu
66 beaker.session.timeout = 36000
66 beaker.session.timeout = 36000
67
67
68 ##auto save the session to not to use .save()
68 ##auto save the session to not to use .save()
69 beaker.session.auto = False
69 beaker.session.auto = False
70
70
71 ##true exire at browser close
71 ##true exire at browser close
72 #beaker.session.cookie_expires = 3600
72 #beaker.session.cookie_expires = 3600
73
73
74
74
75 ################################################################################
75 ################################################################################
76 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
76 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
77 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
77 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
78 ## execute malicious code after an exception is raised. ##
78 ## execute malicious code after an exception is raised. ##
79 ################################################################################
79 ################################################################################
80 set debug = false
80 set debug = false
81
81
82 ##################################
82 ##################################
83 ### LOGVIEW CONFIG ###
83 ### LOGVIEW CONFIG ###
84 ##################################
84 ##################################
85 logview.sqlalchemy = #faa
85 logview.sqlalchemy = #faa
86 logview.pylons.templating = #bfb
86 logview.pylons.templating = #bfb
87 logview.pylons.util = #eee
87 logview.pylons.util = #eee
88
88
89 #########################################################
89 #########################################################
90 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
90 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
91 #########################################################
91 #########################################################
92 sqlalchemy.db1.url = sqlite:///%(here)s/hg_app.db
92 sqlalchemy.db1.url = sqlite:///%(here)s/hg_app.db
93 #sqlalchemy.db1.echo = False
93 #sqlalchemy.db1.echo = False
94 #sqlalchemy.db1.pool_recycle = 3600
94 #sqlalchemy.db1.pool_recycle = 3600
95 sqlalchemy.convert_unicode = true
95 sqlalchemy.convert_unicode = true
96
96
97 ################################
97 ################################
98 ### LOGGING CONFIGURATION ####
98 ### LOGGING CONFIGURATION ####
99 ################################
99 ################################
100 [loggers]
100 [loggers]
101 keys = root, routes, pylons_app, sqlalchemy
101 keys = root, routes, pylons_app, sqlalchemy
102
102
103 [handlers]
103 [handlers]
104 keys = console
104 keys = console
105
105
106 [formatters]
106 [formatters]
107 keys = generic,color_formatter
107 keys = generic,color_formatter
108
108
109 #############
109 #############
110 ## LOGGERS ##
110 ## LOGGERS ##
111 #############
111 #############
112 [logger_root]
112 [logger_root]
113 level = INFO
113 level = INFO
114 handlers = console
114 handlers = console
115
115
116 [logger_routes]
116 [logger_routes]
117 level = INFO
117 level = INFO
118 handlers = console
118 handlers = console
119 qualname = routes.middleware
119 qualname = routes.middleware
120 # "level = DEBUG" logs the route matched and routing variables.
120 # "level = DEBUG" logs the route matched and routing variables.
121
121
122 [logger_pylons_app]
122 [logger_pylons_app]
123 level = DEBUG
123 level = DEBUG
124 handlers = console
124 handlers = console
125 qualname = pylons_app
125 qualname = pylons_app
126 propagate = 0
126 propagate = 0
127
127
128 [logger_sqlalchemy]
128 [logger_sqlalchemy]
129 level = ERROR
129 level = ERROR
130 handlers = console
130 handlers = console
131 qualname = sqlalchemy.engine
131 qualname = sqlalchemy.engine
132 propagate = 0
132 propagate = 0
133
133
134 ##############
134 ##############
135 ## HANDLERS ##
135 ## HANDLERS ##
136 ##############
136 ##############
137
137
138 [handler_console]
138 [handler_console]
139 class = StreamHandler
139 class = StreamHandler
140 args = (sys.stderr,)
140 args = (sys.stderr,)
141 level = NOTSET
141 level = NOTSET
142 formatter = color_formatter
142 formatter = color_formatter
143
143
144 ################
144 ################
145 ## FORMATTERS ##
145 ## FORMATTERS ##
146 ################
146 ################
147
147
148 [formatter_generic]
148 [formatter_generic]
149 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
149 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
150 datefmt = %Y-%m-%d %H:%M:%S
150 datefmt = %Y-%m-%d %H:%M:%S
151
151
152 [formatter_color_formatter]
152 [formatter_color_formatter]
153 class=pylons_app.lib.colored_formatter.ColorFormatter
153 class=pylons_app.lib.colored_formatter.ColorFormatter
154 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
154 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
155 datefmt = %Y-%m-%d %H:%M:%S No newline at end of file
155 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,102 +1,120 b''
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
20
21 """
21 """
22 Created on April 22, 2010
22 Created on April 22, 2010
23 login controller for pylons
23 login controller for pylons
24 @author: marcink
24 @author: marcink
25 """
25 """
26 from formencode import htmlfill
26 from formencode import htmlfill
27 from pylons import request, response, session, tmpl_context as c, url
27 from pylons import request, response, session, tmpl_context as c, url
28 from pylons.controllers.util import abort, redirect
28 from pylons.controllers.util import abort, redirect
29 from pylons_app.lib.auth import AuthUser, HasPermissionAnyDecorator
29 from pylons_app.lib.auth import AuthUser, HasPermissionAnyDecorator
30 from pylons_app.lib.base import BaseController, render
30 from pylons_app.lib.base import BaseController, render
31 from pylons_app.model.forms import LoginForm, RegisterForm
31 from pylons_app.model.forms import LoginForm, RegisterForm
32 from pylons_app.model.user_model import UserModel
32 from pylons_app.model.user_model import UserModel
33 from sqlalchemy.exc import OperationalError
33 import formencode
34 import formencode
35 import datetime
34 import logging
36 import logging
35
37
36 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
37
39
38 class LoginController(BaseController):
40 class LoginController(BaseController):
39
41
40 def __before__(self):
42 def __before__(self):
41 super(LoginController, self).__before__()
43 super(LoginController, self).__before__()
42
44
43 def index(self):
45 def index(self):
44 #redirect if already logged in
46 #redirect if already logged in
45 c.came_from = request.GET.get('came_from',None)
47 c.came_from = request.GET.get('came_from',None)
46
48
47 if c.hg_app_user.is_authenticated:
49 if c.hg_app_user.is_authenticated:
48 return redirect(url('hg_home'))
50 return redirect(url('hg_home'))
49
51
50 if request.POST:
52 if request.POST:
51 #import Login Form validator class
53 #import Login Form validator class
52 login_form = LoginForm()
54 login_form = LoginForm()
53 try:
55 try:
54 c.form_result = login_form.to_python(dict(request.POST))
56 c.form_result = login_form.to_python(dict(request.POST))
57 username = c.form_result['username']
58 user = UserModel().get_user_by_name(username)
59 auth_user = AuthUser()
60 auth_user.username = user.username
61 auth_user.is_authenticated = True
62 auth_user.is_admin = user.admin
63 auth_user.user_id = user.user_id
64 auth_user.name = user.name
65 auth_user.lastname = user.lastname
66 session['hg_app_user'] = auth_user
67 session.save()
68 log.info('user %s is now authenticated', username)
69
70 user.update_lastlogin()
71
55 if c.came_from:
72 if c.came_from:
56 return redirect(c.came_from)
73 return redirect(c.came_from)
57 else:
74 else:
58 return redirect(url('hg_home'))
75 return redirect(url('hg_home'))
59
76
60 except formencode.Invalid as errors:
77 except formencode.Invalid as errors:
61 return htmlfill.render(
78 return htmlfill.render(
62 render('/login.html'),
79 render('/login.html'),
63 defaults=errors.value,
80 defaults=errors.value,
64 errors=errors.error_dict or {},
81 errors=errors.error_dict or {},
65 prefix_error=False,
82 prefix_error=False,
66 encoding="UTF-8")
83 encoding="UTF-8")
67
84
68 return render('/login.html')
85 return render('/login.html')
69
86
70 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
87 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
88 'hg.register.manual_activate')
71 def register(self):
89 def register(self):
72 user_model = UserModel()
90 user_model = UserModel()
73 c.auto_active = False
91 c.auto_active = False
74 for perm in user_model.get_default().user_perms:
92 for perm in user_model.get_default().user_perms:
75 if perm.permission.permission_name == 'hg.register.auto_activate':
93 if perm.permission.permission_name == 'hg.register.auto_activate':
76 c.auto_active = True
94 c.auto_active = True
77 break
95 break
78
96
79 if request.POST:
97 if request.POST:
80
98
81 register_form = RegisterForm()()
99 register_form = RegisterForm()()
82 try:
100 try:
83 form_result = register_form.to_python(dict(request.POST))
101 form_result = register_form.to_python(dict(request.POST))
84 form_result['active'] = c.auto_active
102 form_result['active'] = c.auto_active
85 user_model.create_registration(form_result)
103 user_model.create_registration(form_result)
86 return redirect(url('login_home'))
104 return redirect(url('login_home'))
87
105
88 except formencode.Invalid as errors:
106 except formencode.Invalid as errors:
89 return htmlfill.render(
107 return htmlfill.render(
90 render('/register.html'),
108 render('/register.html'),
91 defaults=errors.value,
109 defaults=errors.value,
92 errors=errors.error_dict or {},
110 errors=errors.error_dict or {},
93 prefix_error=False,
111 prefix_error=False,
94 encoding="UTF-8")
112 encoding="UTF-8")
95
113
96 return render('/register.html')
114 return render('/register.html')
97
115
98 def logout(self):
116 def logout(self):
99 session['hg_app_user'] = AuthUser()
117 session['hg_app_user'] = AuthUser()
100 session.save()
118 session.save()
101 log.info('Logging out and setting user as Empty')
119 log.info('Logging out and setting user as Empty')
102 redirect(url('hg_home'))
120 redirect(url('hg_home'))
@@ -1,454 +1,454 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # authentication and permission libraries
3 # authentication and permission libraries
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 Created on April 4, 2010
21 Created on April 4, 2010
22
22
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from beaker.cache import cache_region
25 from beaker.cache import cache_region
26 from pylons import config, session, url, request
26 from pylons import config, session, url, request
27 from pylons.controllers.util import abort, redirect
27 from pylons.controllers.util import abort, redirect
28 from pylons_app.lib.utils import get_repo_slug
28 from pylons_app.lib.utils import get_repo_slug
29 from pylons_app.model import meta
29 from pylons_app.model import meta
30 from pylons_app.model.db import User, RepoToPerm, Repository, Permission, \
30 from pylons_app.model.db import User, RepoToPerm, Repository, Permission, \
31 UserToPerm
31 UserToPerm
32 from sqlalchemy.exc import OperationalError
32 from sqlalchemy.exc import OperationalError
33 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
34 import bcrypt
34 import bcrypt
35 from decorator import decorator
35 from decorator import decorator
36 import logging
36 import logging
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40 def get_crypt_password(password):
40 def get_crypt_password(password):
41 """Cryptographic function used for password hashing based on sha1
41 """Cryptographic function used for password hashing based on sha1
42 @param password: password to hash
42 @param password: password to hash
43 """
43 """
44 return bcrypt.hashpw(password, bcrypt.gensalt(10))
44 return bcrypt.hashpw(password, bcrypt.gensalt(10))
45
45
46 def check_password(password, hashed):
46 def check_password(password, hashed):
47 return bcrypt.hashpw(password, hashed) == hashed
47 return bcrypt.hashpw(password, hashed) == hashed
48
48
49 @cache_region('super_short_term', 'cached_user')
49 @cache_region('super_short_term', 'cached_user')
50 def get_user_cached(username):
50 def get_user_cached(username):
51 sa = meta.Session
51 sa = meta.Session
52 try:
52 try:
53 user = sa.query(User).filter(User.username == username).one()
53 user = sa.query(User).filter(User.username == username).one()
54 finally:
54 finally:
55 meta.Session.remove()
55 meta.Session.remove()
56 return user
56 return user
57
57
58 def authfunc(environ, username, password):
58 def authfunc(environ, username, password):
59 try:
59 try:
60 user = get_user_cached(username)
60 user = get_user_cached(username)
61 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
61 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
62 log.error(e)
62 log.error(e)
63 user = None
63 user = None
64
64
65 if user:
65 if user:
66 if user.active:
66 if user.active:
67 if user.username == username and check_password(password, user.password):
67 if user.username == username and check_password(password, user.password):
68 log.info('user %s authenticated correctly', username)
68 log.info('user %s authenticated correctly', username)
69 return True
69 return True
70 else:
70 else:
71 log.error('user %s is disabled', username)
71 log.error('user %s is disabled', username)
72
72
73 return False
73 return False
74
74
75 class AuthUser(object):
75 class AuthUser(object):
76 """
76 """
77 A simple object that handles a mercurial username for authentication
77 A simple object that handles a mercurial username for authentication
78 """
78 """
79 def __init__(self):
79 def __init__(self):
80 self.username = 'None'
80 self.username = 'None'
81 self.name = ''
81 self.name = ''
82 self.lastname = ''
82 self.lastname = ''
83 self.email = ''
83 self.email = ''
84 self.user_id = None
84 self.user_id = None
85 self.is_authenticated = False
85 self.is_authenticated = False
86 self.is_admin = False
86 self.is_admin = False
87 self.permissions = {}
87 self.permissions = {}
88
88
89
89
90 def set_available_permissions(config):
90 def set_available_permissions(config):
91 """
91 """
92 This function will propagate pylons globals with all available defined
92 This function will propagate pylons globals with all available defined
93 permission given in db. We don't wannt to check each time from db for new
93 permission given in db. We don't wannt to check each time from db for new
94 permissions since adding a new permission also requires application restart
94 permissions since adding a new permission also requires application restart
95 ie. to decorate new views with the newly created permission
95 ie. to decorate new views with the newly created permission
96 @param config:
96 @param config:
97 """
97 """
98 log.info('getting information about all available permissions')
98 log.info('getting information about all available permissions')
99 try:
99 try:
100 sa = meta.Session
100 sa = meta.Session
101 all_perms = sa.query(Permission).all()
101 all_perms = sa.query(Permission).all()
102 finally:
102 finally:
103 meta.Session.remove()
103 meta.Session.remove()
104
104
105 config['available_permissions'] = [x.permission_name for x in all_perms]
105 config['available_permissions'] = [x.permission_name for x in all_perms]
106
106
107 def set_base_path(config):
107 def set_base_path(config):
108 config['base_path'] = config['pylons.app_globals'].base_path
108 config['base_path'] = config['pylons.app_globals'].base_path
109
109
110 def fill_data(user):
110 def fill_data(user):
111 """
111 """
112 Fills user data with those from database and log out user if not present
112 Fills user data with those from database and log out user if not present
113 in database
113 in database
114 @param user:
114 @param user:
115 """
115 """
116 sa = meta.Session
116 sa = meta.Session
117 dbuser = sa.query(User).get(user.user_id)
117 dbuser = sa.query(User).get(user.user_id)
118 if dbuser:
118 if dbuser:
119 user.username = dbuser.username
119 user.username = dbuser.username
120 user.is_admin = dbuser.admin
120 user.is_admin = dbuser.admin
121 user.name = dbuser.name
121 user.name = dbuser.name
122 user.lastname = dbuser.lastname
122 user.lastname = dbuser.lastname
123 user.email = dbuser.email
123 user.email = dbuser.email
124 else:
124 else:
125 user.is_authenticated = False
125 user.is_authenticated = False
126 meta.Session.remove()
126 meta.Session.remove()
127 return user
127 return user
128
128
129 def fill_perms(user):
129 def fill_perms(user):
130 """
130 """
131 Fills user permission attribute with permissions taken from database
131 Fills user permission attribute with permissions taken from database
132 @param user:
132 @param user:
133 """
133 """
134
134
135 sa = meta.Session
135 sa = meta.Session
136 user.permissions['repositories'] = {}
136 user.permissions['repositories'] = {}
137 user.permissions['global'] = set()
137 user.permissions['global'] = set()
138
138
139 #===========================================================================
139 #===========================================================================
140 # fetch default permissions
140 # fetch default permissions
141 #===========================================================================
141 #===========================================================================
142 default_perms = sa.query(RepoToPerm, Repository, Permission)\
142 default_perms = sa.query(RepoToPerm, Repository, Permission)\
143 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
143 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
144 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
144 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
145 .filter(RepoToPerm.user == sa.query(User).filter(User.username ==
145 .filter(RepoToPerm.user == sa.query(User).filter(User.username ==
146 'default').scalar()).all()
146 'default').scalar()).all()
147
147
148 if user.is_admin:
148 if user.is_admin:
149 #=======================================================================
149 #=======================================================================
150 # #admin have all default rights set to admin
150 # #admin have all default rights set to admin
151 #=======================================================================
151 #=======================================================================
152 user.permissions['global'].add('hg.admin')
152 user.permissions['global'].add('hg.admin')
153
153
154 for perm in default_perms:
154 for perm in default_perms:
155 p = 'repository.admin'
155 p = 'repository.admin'
156 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
156 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
157
157
158 else:
158 else:
159 #=======================================================================
159 #=======================================================================
160 # set default permissions
160 # set default permissions
161 #=======================================================================
161 #=======================================================================
162
162
163 #default global
163 #default global
164 default_global_perms = sa.query(UserToPerm)\
164 default_global_perms = sa.query(UserToPerm)\
165 .filter(UserToPerm.user == sa.query(User).filter(User.username ==
165 .filter(UserToPerm.user == sa.query(User).filter(User.username ==
166 'default').one())
166 'default').one())
167
167
168 for perm in default_global_perms:
168 for perm in default_global_perms:
169 user.permissions['global'].add(perm.permission.permission_name)
169 user.permissions['global'].add(perm.permission.permission_name)
170
170
171 #default repositories
171 #default repositories
172 for perm in default_perms:
172 for perm in default_perms:
173 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
173 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
174 #disable defaults for private repos,
174 #disable defaults for private repos,
175 p = 'repository.none'
175 p = 'repository.none'
176 elif perm.Repository.user_id == user.user_id:
176 elif perm.Repository.user_id == user.user_id:
177 #set admin if owner
177 #set admin if owner
178 p = 'repository.admin'
178 p = 'repository.admin'
179 else:
179 else:
180 p = perm.Permission.permission_name
180 p = perm.Permission.permission_name
181
181
182 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
182 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
183
183
184 #=======================================================================
184 #=======================================================================
185 # #overwrite default with user permissions if any
185 # #overwrite default with user permissions if any
186 #=======================================================================
186 #=======================================================================
187 user_perms = sa.query(RepoToPerm, Permission, Repository)\
187 user_perms = sa.query(RepoToPerm, Permission, Repository)\
188 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
188 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
189 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
189 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
190 .filter(RepoToPerm.user_id == user.user_id).all()
190 .filter(RepoToPerm.user_id == user.user_id).all()
191
191
192 for perm in user_perms:
192 for perm in user_perms:
193 if perm.Repository.user_id == user.user_id:#set admin if owner
193 if perm.Repository.user_id == user.user_id:#set admin if owner
194 p = 'repository.admin'
194 p = 'repository.admin'
195 else:
195 else:
196 p = perm.Permission.permission_name
196 p = perm.Permission.permission_name
197 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
197 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
198 meta.Session.remove()
198 meta.Session.remove()
199 return user
199 return user
200
200
201 def get_user(session):
201 def get_user(session):
202 """
202 """
203 Gets user from session, and wraps permissions into user
203 Gets user from session, and wraps permissions into user
204 @param session:
204 @param session:
205 """
205 """
206 user = session.get('hg_app_user', AuthUser())
206 user = session.get('hg_app_user', AuthUser())
207 if user.is_authenticated:
207 if user.is_authenticated:
208 user = fill_data(user)
208 user = fill_data(user)
209 user = fill_perms(user)
209 user = fill_perms(user)
210 session['hg_app_user'] = user
210 session['hg_app_user'] = user
211 session.save()
211 session.save()
212 return user
212 return user
213
213
214 #===============================================================================
214 #===============================================================================
215 # CHECK DECORATORS
215 # CHECK DECORATORS
216 #===============================================================================
216 #===============================================================================
217 class LoginRequired(object):
217 class LoginRequired(object):
218 """Must be logged in to execute this function else redirect to login page"""
218 """Must be logged in to execute this function else redirect to login page"""
219
219
220 def __call__(self, func):
220 def __call__(self, func):
221 return decorator(self.__wrapper, func)
221 return decorator(self.__wrapper, func)
222
222
223 def __wrapper(self, func, *fargs, **fkwargs):
223 def __wrapper(self, func, *fargs, **fkwargs):
224 user = session.get('hg_app_user', AuthUser())
224 user = session.get('hg_app_user', AuthUser())
225 log.debug('Checking login required for user:%s', user.username)
225 log.debug('Checking login required for user:%s', user.username)
226 if user.is_authenticated:
226 if user.is_authenticated:
227 log.debug('user %s is authenticated', user.username)
227 log.debug('user %s is authenticated', user.username)
228 return func(*fargs, **fkwargs)
228 return func(*fargs, **fkwargs)
229 else:
229 else:
230 log.warn('user %s not authenticated', user.username)
230 log.warn('user %s not authenticated', user.username)
231
231
232 p = request.environ.get('PATH_INFO')
232 p = request.environ.get('PATH_INFO')
233 if request.environ.get('QUERY_STRING'):
233 if request.environ.get('QUERY_STRING'):
234 p+='?'+request.environ.get('QUERY_STRING')
234 p+='?'+request.environ.get('QUERY_STRING')
235 log.debug('redirecting to login page with %',p)
235 log.debug('redirecting to login page with %s',p)
236 return redirect(url('login_home',came_from=p))
236 return redirect(url('login_home',came_from=p))
237
237
238 class PermsDecorator(object):
238 class PermsDecorator(object):
239 """Base class for decorators"""
239 """Base class for decorators"""
240
240
241 def __init__(self, *required_perms):
241 def __init__(self, *required_perms):
242 available_perms = config['available_permissions']
242 available_perms = config['available_permissions']
243 for perm in required_perms:
243 for perm in required_perms:
244 if perm not in available_perms:
244 if perm not in available_perms:
245 raise Exception("'%s' permission is not defined" % perm)
245 raise Exception("'%s' permission is not defined" % perm)
246 self.required_perms = set(required_perms)
246 self.required_perms = set(required_perms)
247 self.user_perms = None
247 self.user_perms = None
248
248
249 def __call__(self, func):
249 def __call__(self, func):
250 return decorator(self.__wrapper, func)
250 return decorator(self.__wrapper, func)
251
251
252
252
253 def __wrapper(self, func, *fargs, **fkwargs):
253 def __wrapper(self, func, *fargs, **fkwargs):
254 # _wrapper.__name__ = func.__name__
254 # _wrapper.__name__ = func.__name__
255 # _wrapper.__dict__.update(func.__dict__)
255 # _wrapper.__dict__.update(func.__dict__)
256 # _wrapper.__doc__ = func.__doc__
256 # _wrapper.__doc__ = func.__doc__
257
257
258 self.user_perms = session.get('hg_app_user', AuthUser()).permissions
258 self.user_perms = session.get('hg_app_user', AuthUser()).permissions
259 log.debug('checking %s permissions %s for %s',
259 log.debug('checking %s permissions %s for %s',
260 self.__class__.__name__, self.required_perms, func.__name__)
260 self.__class__.__name__, self.required_perms, func.__name__)
261
261
262 if self.check_permissions():
262 if self.check_permissions():
263 log.debug('Permission granted for %s', func.__name__)
263 log.debug('Permission granted for %s', func.__name__)
264
264
265 return func(*fargs, **fkwargs)
265 return func(*fargs, **fkwargs)
266
266
267 else:
267 else:
268 log.warning('Permission denied for %s', func.__name__)
268 log.warning('Permission denied for %s', func.__name__)
269 #redirect with forbidden ret code
269 #redirect with forbidden ret code
270 return abort(403)
270 return abort(403)
271
271
272
272
273
273
274 def check_permissions(self):
274 def check_permissions(self):
275 """Dummy function for overriding"""
275 """Dummy function for overriding"""
276 raise Exception('You have to write this function in child class')
276 raise Exception('You have to write this function in child class')
277
277
278 class HasPermissionAllDecorator(PermsDecorator):
278 class HasPermissionAllDecorator(PermsDecorator):
279 """Checks for access permission for all given predicates. All of them
279 """Checks for access permission for all given predicates. All of them
280 have to be meet in order to fulfill the request
280 have to be meet in order to fulfill the request
281 """
281 """
282
282
283 def check_permissions(self):
283 def check_permissions(self):
284 if self.required_perms.issubset(self.user_perms.get('global')):
284 if self.required_perms.issubset(self.user_perms.get('global')):
285 return True
285 return True
286 return False
286 return False
287
287
288
288
289 class HasPermissionAnyDecorator(PermsDecorator):
289 class HasPermissionAnyDecorator(PermsDecorator):
290 """Checks for access permission for any of given predicates. In order to
290 """Checks for access permission for any of given predicates. In order to
291 fulfill the request any of predicates must be meet
291 fulfill the request any of predicates must be meet
292 """
292 """
293
293
294 def check_permissions(self):
294 def check_permissions(self):
295 if self.required_perms.intersection(self.user_perms.get('global')):
295 if self.required_perms.intersection(self.user_perms.get('global')):
296 return True
296 return True
297 return False
297 return False
298
298
299 class HasRepoPermissionAllDecorator(PermsDecorator):
299 class HasRepoPermissionAllDecorator(PermsDecorator):
300 """Checks for access permission for all given predicates for specific
300 """Checks for access permission for all given predicates for specific
301 repository. All of them have to be meet in order to fulfill the request
301 repository. All of them have to be meet in order to fulfill the request
302 """
302 """
303
303
304 def check_permissions(self):
304 def check_permissions(self):
305 repo_name = get_repo_slug(request)
305 repo_name = get_repo_slug(request)
306 try:
306 try:
307 user_perms = set([self.user_perms['repositories'][repo_name]])
307 user_perms = set([self.user_perms['repositories'][repo_name]])
308 except KeyError:
308 except KeyError:
309 return False
309 return False
310 if self.required_perms.issubset(user_perms):
310 if self.required_perms.issubset(user_perms):
311 return True
311 return True
312 return False
312 return False
313
313
314
314
315 class HasRepoPermissionAnyDecorator(PermsDecorator):
315 class HasRepoPermissionAnyDecorator(PermsDecorator):
316 """Checks for access permission for any of given predicates for specific
316 """Checks for access permission for any of given predicates for specific
317 repository. In order to fulfill the request any of predicates must be meet
317 repository. In order to fulfill the request any of predicates must be meet
318 """
318 """
319
319
320 def check_permissions(self):
320 def check_permissions(self):
321 repo_name = get_repo_slug(request)
321 repo_name = get_repo_slug(request)
322
322
323 try:
323 try:
324 user_perms = set([self.user_perms['repositories'][repo_name]])
324 user_perms = set([self.user_perms['repositories'][repo_name]])
325 except KeyError:
325 except KeyError:
326 return False
326 return False
327 if self.required_perms.intersection(user_perms):
327 if self.required_perms.intersection(user_perms):
328 return True
328 return True
329 return False
329 return False
330 #===============================================================================
330 #===============================================================================
331 # CHECK FUNCTIONS
331 # CHECK FUNCTIONS
332 #===============================================================================
332 #===============================================================================
333
333
334 class PermsFunction(object):
334 class PermsFunction(object):
335 """Base function for other check functions"""
335 """Base function for other check functions"""
336
336
337 def __init__(self, *perms):
337 def __init__(self, *perms):
338 available_perms = config['available_permissions']
338 available_perms = config['available_permissions']
339
339
340 for perm in perms:
340 for perm in perms:
341 if perm not in available_perms:
341 if perm not in available_perms:
342 raise Exception("'%s' permission in not defined" % perm)
342 raise Exception("'%s' permission in not defined" % perm)
343 self.required_perms = set(perms)
343 self.required_perms = set(perms)
344 self.user_perms = None
344 self.user_perms = None
345 self.granted_for = ''
345 self.granted_for = ''
346 self.repo_name = None
346 self.repo_name = None
347
347
348 def __call__(self, check_Location=''):
348 def __call__(self, check_Location=''):
349 user = session.get('hg_app_user', False)
349 user = session.get('hg_app_user', False)
350 if not user:
350 if not user:
351 return False
351 return False
352 self.user_perms = user.permissions
352 self.user_perms = user.permissions
353 self.granted_for = user.username
353 self.granted_for = user.username
354 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
354 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
355
355
356 if self.check_permissions():
356 if self.check_permissions():
357 log.debug('Permission granted for %s @%s', self.granted_for,
357 log.debug('Permission granted for %s @%s', self.granted_for,
358 check_Location)
358 check_Location)
359 return True
359 return True
360
360
361 else:
361 else:
362 log.warning('Permission denied for %s @%s', self.granted_for,
362 log.warning('Permission denied for %s @%s', self.granted_for,
363 check_Location)
363 check_Location)
364 return False
364 return False
365
365
366 def check_permissions(self):
366 def check_permissions(self):
367 """Dummy function for overriding"""
367 """Dummy function for overriding"""
368 raise Exception('You have to write this function in child class')
368 raise Exception('You have to write this function in child class')
369
369
370 class HasPermissionAll(PermsFunction):
370 class HasPermissionAll(PermsFunction):
371 def check_permissions(self):
371 def check_permissions(self):
372 if self.required_perms.issubset(self.user_perms.get('global')):
372 if self.required_perms.issubset(self.user_perms.get('global')):
373 return True
373 return True
374 return False
374 return False
375
375
376 class HasPermissionAny(PermsFunction):
376 class HasPermissionAny(PermsFunction):
377 def check_permissions(self):
377 def check_permissions(self):
378 if self.required_perms.intersection(self.user_perms.get('global')):
378 if self.required_perms.intersection(self.user_perms.get('global')):
379 return True
379 return True
380 return False
380 return False
381
381
382 class HasRepoPermissionAll(PermsFunction):
382 class HasRepoPermissionAll(PermsFunction):
383
383
384 def __call__(self, repo_name=None, check_Location=''):
384 def __call__(self, repo_name=None, check_Location=''):
385 self.repo_name = repo_name
385 self.repo_name = repo_name
386 return super(HasRepoPermissionAll, self).__call__(check_Location)
386 return super(HasRepoPermissionAll, self).__call__(check_Location)
387
387
388 def check_permissions(self):
388 def check_permissions(self):
389 if not self.repo_name:
389 if not self.repo_name:
390 self.repo_name = get_repo_slug(request)
390 self.repo_name = get_repo_slug(request)
391
391
392 try:
392 try:
393 self.user_perms = set([self.user_perms['repositories']\
393 self.user_perms = set([self.user_perms['repositories']\
394 [self.repo_name]])
394 [self.repo_name]])
395 except KeyError:
395 except KeyError:
396 return False
396 return False
397 self.granted_for = self.repo_name
397 self.granted_for = self.repo_name
398 if self.required_perms.issubset(self.user_perms):
398 if self.required_perms.issubset(self.user_perms):
399 return True
399 return True
400 return False
400 return False
401
401
402 class HasRepoPermissionAny(PermsFunction):
402 class HasRepoPermissionAny(PermsFunction):
403
403
404 def __call__(self, repo_name=None, check_Location=''):
404 def __call__(self, repo_name=None, check_Location=''):
405 self.repo_name = repo_name
405 self.repo_name = repo_name
406 return super(HasRepoPermissionAny, self).__call__(check_Location)
406 return super(HasRepoPermissionAny, self).__call__(check_Location)
407
407
408 def check_permissions(self):
408 def check_permissions(self):
409 if not self.repo_name:
409 if not self.repo_name:
410 self.repo_name = get_repo_slug(request)
410 self.repo_name = get_repo_slug(request)
411
411
412 try:
412 try:
413 self.user_perms = set([self.user_perms['repositories']\
413 self.user_perms = set([self.user_perms['repositories']\
414 [self.repo_name]])
414 [self.repo_name]])
415 except KeyError:
415 except KeyError:
416 return False
416 return False
417 self.granted_for = self.repo_name
417 self.granted_for = self.repo_name
418 if self.required_perms.intersection(self.user_perms):
418 if self.required_perms.intersection(self.user_perms):
419 return True
419 return True
420 return False
420 return False
421
421
422 #===============================================================================
422 #===============================================================================
423 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
423 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
424 #===============================================================================
424 #===============================================================================
425
425
426 class HasPermissionAnyMiddleware(object):
426 class HasPermissionAnyMiddleware(object):
427 def __init__(self, *perms):
427 def __init__(self, *perms):
428 self.required_perms = set(perms)
428 self.required_perms = set(perms)
429
429
430 def __call__(self, user, repo_name):
430 def __call__(self, user, repo_name):
431 usr = AuthUser()
431 usr = AuthUser()
432 usr.user_id = user.user_id
432 usr.user_id = user.user_id
433 usr.username = user.username
433 usr.username = user.username
434 usr.is_admin = user.admin
434 usr.is_admin = user.admin
435
435
436 try:
436 try:
437 self.user_perms = set([fill_perms(usr)\
437 self.user_perms = set([fill_perms(usr)\
438 .permissions['repositories'][repo_name]])
438 .permissions['repositories'][repo_name]])
439 except:
439 except:
440 self.user_perms = set()
440 self.user_perms = set()
441 self.granted_for = ''
441 self.granted_for = ''
442 self.username = user.username
442 self.username = user.username
443 self.repo_name = repo_name
443 self.repo_name = repo_name
444 return self.check_permissions()
444 return self.check_permissions()
445
445
446 def check_permissions(self):
446 def check_permissions(self):
447 log.debug('checking mercurial protocol '
447 log.debug('checking mercurial protocol '
448 'permissions for user:%s repository:%s',
448 'permissions for user:%s repository:%s',
449 self.username, self.repo_name)
449 self.username, self.repo_name)
450 if self.required_perms.intersection(self.user_perms):
450 if self.required_perms.intersection(self.user_perms):
451 log.debug('permission granted')
451 log.debug('permission granted')
452 return True
452 return True
453 log.debug('permission denied')
453 log.debug('permission denied')
454 return False
454 return False
@@ -1,107 +1,125 b''
1 from pylons_app.model.meta import Base
1 from pylons_app.model.meta import Base
2 from sqlalchemy import *
2 from sqlalchemy.orm import relation, backref
3 from sqlalchemy.orm import relation, backref
3 from sqlalchemy import *
4 from sqlalchemy.orm.session import Session
4 from vcs.utils.lazy import LazyProperty
5 from vcs.utils.lazy import LazyProperty
6 import logging
7
8 log = logging.getLogger(__name__)
5
9
6 class HgAppSettings(Base):
10 class HgAppSettings(Base):
7 __tablename__ = 'hg_app_settings'
11 __tablename__ = 'hg_app_settings'
8 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
12 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
9 app_settings_id = Column("app_settings_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
13 app_settings_id = Column("app_settings_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
10 app_settings_name = Column("app_settings_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
14 app_settings_name = Column("app_settings_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
11 app_settings_value = Column("app_settings_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
15 app_settings_value = Column("app_settings_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
12
16
13 class HgAppUi(Base):
17 class HgAppUi(Base):
14 __tablename__ = 'hg_app_ui'
18 __tablename__ = 'hg_app_ui'
15 __table_args__ = {'useexisting':True}
19 __table_args__ = {'useexisting':True}
16 ui_id = Column("ui_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
20 ui_id = Column("ui_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
17 ui_section = Column("ui_section", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
21 ui_section = Column("ui_section", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
18 ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
22 ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
19 ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
23 ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
20 ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
24 ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
21
25
22
26
23 class User(Base):
27 class User(Base):
24 __tablename__ = 'users'
28 __tablename__ = 'users'
25 __table_args__ = {'useexisting':True}
29 __table_args__ = {'useexisting':True}
26 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
30 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
27 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
31 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
28 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
32 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
29 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
33 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
30 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=False)
34 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=False)
31 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
35 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
32 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
36 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
33 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
37 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
34 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
38 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
35
39
36 user_log = relation('UserLog')
40 user_log = relation('UserLog')
37 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id")
41 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id")
38
42
39 @LazyProperty
43 @LazyProperty
40 def full_contact(self):
44 def full_contact(self):
41 return '%s %s <%s>' % (self.name, self.lastname, self.email)
45 return '%s %s <%s>' % (self.name, self.lastname, self.email)
42
46
43 def __repr__(self):
47 def __repr__(self):
44 return "<User('id:%s:%s')>" % (self.user_id, self.username)
48 return "<User('id:%s:%s')>" % (self.user_id, self.username)
49
50 def update_lastlogin(self):
51 """Update user lastlogin"""
52 import datetime
53
54 try:
55 session = Session.object_session(self)
56 self.last_login = datetime.datetime.now()
57 session.add(self)
58 session.commit()
59 log.debug('updated user %s lastlogin',self)
60 except Exception:
61 session.rollback()
62
45
63
46 class UserLog(Base):
64 class UserLog(Base):
47 __tablename__ = 'user_logs'
65 __tablename__ = 'user_logs'
48 __table_args__ = {'useexisting':True}
66 __table_args__ = {'useexisting':True}
49 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
67 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
50 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
68 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
51 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
69 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
52 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_name'), nullable=False, unique=None, default=None)
70 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_name'), nullable=False, unique=None, default=None)
53 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
71 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
54 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
72 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
55
73
56 user = relation('User')
74 user = relation('User')
57
75
58 class Repository(Base):
76 class Repository(Base):
59 __tablename__ = 'repositories'
77 __tablename__ = 'repositories'
60 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
78 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
61 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
79 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
62 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
80 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
63 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
81 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
64 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
82 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
65 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
83 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
66
84
67 user = relation('User')
85 user = relation('User')
68 repo_to_perm = relation('RepoToPerm', cascade='all')
86 repo_to_perm = relation('RepoToPerm', cascade='all')
69
87
70 def __repr__(self):
88 def __repr__(self):
71 return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name)
89 return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name)
72
90
73 class Permission(Base):
91 class Permission(Base):
74 __tablename__ = 'permissions'
92 __tablename__ = 'permissions'
75 __table_args__ = {'useexisting':True}
93 __table_args__ = {'useexisting':True}
76 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
94 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
77 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
95 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
78 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
96 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
79
97
80 def __repr__(self):
98 def __repr__(self):
81 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
99 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
82
100
83 class RepoToPerm(Base):
101 class RepoToPerm(Base):
84 __tablename__ = 'repo_to_perm'
102 __tablename__ = 'repo_to_perm'
85 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
103 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
86 repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
104 repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
87 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
105 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
88 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
106 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
89 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
107 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None)
90
108
91 user = relation('User')
109 user = relation('User')
92 permission = relation('Permission')
110 permission = relation('Permission')
93 repository = relation('Repository')
111 repository = relation('Repository')
94
112
95 class UserToPerm(Base):
113 class UserToPerm(Base):
96 __tablename__ = 'user_to_perm'
114 __tablename__ = 'user_to_perm'
97 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
115 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
98 user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
116 user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
99 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
117 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
100 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
118 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None)
101
119
102 user = relation('User')
120 user = relation('User')
103 permission = relation('Permission')
121 permission = relation('Permission')
104
122
105
123
106
124
107
125
@@ -1,340 +1,318 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 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 check_password, get_crypt_password
27 from pylons_app.lib.auth import check_password, get_crypt_password
28 from pylons_app.model import meta
28 from pylons_app.model import meta
29 from pylons_app.model.user_model import UserModel
29 from pylons_app.model.db import User, Repository
30 from pylons_app.model.db import User, Repository
30 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
33 import datetime
34 import formencode
34 import formencode
35 import logging
35 import logging
36 import os
36 import os
37 import pylons_app.lib.helpers as h
37 import pylons_app.lib.helpers as h
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40
40
41 #this is needed to translate the messages using _() in validators
41 #this is needed to translate the messages using _() in validators
42 class State_obj(object):
42 class State_obj(object):
43 _ = staticmethod(_)
43 _ = staticmethod(_)
44
44
45 #===============================================================================
45 #===============================================================================
46 # VALIDATORS
46 # VALIDATORS
47 #===============================================================================
47 #===============================================================================
48 class ValidAuthToken(formencode.validators.FancyValidator):
48 class ValidAuthToken(formencode.validators.FancyValidator):
49 messages = {'invalid_token':_('Token mismatch')}
49 messages = {'invalid_token':_('Token mismatch')}
50
50
51 def validate_python(self, value, state):
51 def validate_python(self, value, state):
52
52
53 if value != authentication_token():
53 if value != authentication_token():
54 raise formencode.Invalid(self.message('invalid_token', state,
54 raise formencode.Invalid(self.message('invalid_token', state,
55 search_number=value), value, state)
55 search_number=value), value, state)
56
56
57 def ValidUsername(edit, old_data):
57 def ValidUsername(edit, old_data):
58 class _ValidUsername(formencode.validators.FancyValidator):
58 class _ValidUsername(formencode.validators.FancyValidator):
59
59
60 def validate_python(self, value, state):
60 def validate_python(self, value, state):
61 if value in ['default', 'new_user']:
61 if value in ['default', 'new_user']:
62 raise formencode.Invalid(_('Invalid username'), value, state)
62 raise formencode.Invalid(_('Invalid username'), value, state)
63 #check if user is uniq
63 #check if user is uniq
64 sa = meta.Session
64 sa = meta.Session
65 old_un = None
65 old_un = None
66 if edit:
66 if edit:
67 old_un = sa.query(User).get(old_data.get('user_id')).username
67 old_un = sa.query(User).get(old_data.get('user_id')).username
68
68
69 if old_un != value or not edit:
69 if old_un != value or not edit:
70 if sa.query(User).filter(User.username == value).scalar():
70 if sa.query(User).filter(User.username == value).scalar():
71 raise formencode.Invalid(_('This username already exists') ,
71 raise formencode.Invalid(_('This username already exists') ,
72 value, state)
72 value, state)
73 meta.Session.remove()
73 meta.Session.remove()
74
74
75 return _ValidUsername
75 return _ValidUsername
76
76
77 class ValidPassword(formencode.validators.FancyValidator):
77 class ValidPassword(formencode.validators.FancyValidator):
78
78
79 def to_python(self, value, state):
79 def to_python(self, value, state):
80 if value:
80 if value:
81 return get_crypt_password(value)
81 return get_crypt_password(value)
82
82
83 class ValidAuth(formencode.validators.FancyValidator):
83 class ValidAuth(formencode.validators.FancyValidator):
84 messages = {
84 messages = {
85 'invalid_password':_('invalid password'),
85 'invalid_password':_('invalid password'),
86 'invalid_login':_('invalid user name'),
86 'invalid_login':_('invalid user name'),
87 'disabled_account':_('Your acccount is disabled')
87 'disabled_account':_('Your acccount is disabled')
88
88
89 }
89 }
90 #error mapping
90 #error mapping
91 e_dict = {'username':messages['invalid_login'],
91 e_dict = {'username':messages['invalid_login'],
92 'password':messages['invalid_password']}
92 'password':messages['invalid_password']}
93 e_dict_disable = {'username':messages['disabled_account']}
93 e_dict_disable = {'username':messages['disabled_account']}
94
94
95 def validate_python(self, value, state):
95 def validate_python(self, value, state):
96 sa = meta.Session
97 password = value['password']
96 password = value['password']
98 username = value['username']
97 username = value['username']
99 try:
98 try:
100 user = sa.query(User).filter(User.username == username).one()
99 user = UserModel().get_user_by_name(username)
101 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
100 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
102 log.error(e)
101 log.error(e)
103 user = None
102 user = None
104 raise formencode.Invalid(self.message('invalid_password',
103 raise formencode.Invalid(self.message('invalid_password',
105 state=State_obj), value, state,
104 state=State_obj), value, state,
106 error_dict=self.e_dict)
105 error_dict=self.e_dict)
107 if user:
106 if user:
108 if user.active:
107 if user.active:
109 if user.username == username and check_password(password, user.password):
108 if user.username == username and check_password(password,
110 from pylons_app.lib.auth import AuthUser
109 user.password):
111 auth_user = AuthUser()
112 auth_user.username = username
113 auth_user.is_authenticated = True
114 auth_user.is_admin = user.admin
115 auth_user.user_id = user.user_id
116 auth_user.name = user.name
117 auth_user.lastname = user.lastname
118 session['hg_app_user'] = auth_user
119 session.save()
120 log.info('user %s is now authenticated', username)
121
122 try:
123 user.last_login = datetime.datetime.now()
124 sa.add(user)
125 sa.commit()
126 except (OperationalError) as e:
127 log.error(e)
128 sa.rollback()
129
130 return value
110 return value
131 else:
111 else:
132 log.warning('user %s not authenticated', username)
112 log.warning('user %s not authenticated', username)
133 raise formencode.Invalid(self.message('invalid_password',
113 raise formencode.Invalid(self.message('invalid_password',
134 state=State_obj), value, state,
114 state=State_obj), value, state,
135 error_dict=self.e_dict)
115 error_dict=self.e_dict)
136 else:
116 else:
137 log.warning('user %s is disabled', username)
117 log.warning('user %s is disabled', username)
138 raise formencode.Invalid(self.message('disabled_account',
118 raise formencode.Invalid(self.message('disabled_account',
139 state=State_obj),
119 state=State_obj),
140 value, state,
120 value, state,
141 error_dict=self.e_dict_disable)
121 error_dict=self.e_dict_disable)
142
143 meta.Session.remove()
144
145
122
146 class ValidRepoUser(formencode.validators.FancyValidator):
123 class ValidRepoUser(formencode.validators.FancyValidator):
147
124
148 def to_python(self, value, state):
125 def to_python(self, value, state):
149 sa = meta.Session
150 try:
126 try:
151 self.user_db = sa.query(User)\
127 self.user_db = meta.Session.query(User)\
152 .filter(User.active == True)\
128 .filter(User.active == True)\
153 .filter(User.username == value).one()
129 .filter(User.username == value).one()
154 except Exception:
130 except Exception:
155 raise formencode.Invalid(_('This username is not valid'),
131 raise formencode.Invalid(_('This username is not valid'),
156 value, state)
132 value, state)
157 meta.Session.remove()
133 finally:
134 meta.Session.remove()
135
158 return self.user_db.user_id
136 return self.user_db.user_id
159
137
160 def ValidRepoName(edit, old_data):
138 def ValidRepoName(edit, old_data):
161 class _ValidRepoName(formencode.validators.FancyValidator):
139 class _ValidRepoName(formencode.validators.FancyValidator):
162
140
163 def to_python(self, value, state):
141 def to_python(self, value, state):
164 slug = h.repo_name_slug(value)
142 slug = h.repo_name_slug(value)
165 if slug in ['_admin']:
143 if slug in ['_admin']:
166 raise formencode.Invalid(_('This repository name is disallowed'),
144 raise formencode.Invalid(_('This repository name is disallowed'),
167 value, state)
145 value, state)
168 if old_data.get('repo_name') != value or not edit:
146 if old_data.get('repo_name') != value or not edit:
169 sa = meta.Session
147 sa = meta.Session
170 if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
148 if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
171 raise formencode.Invalid(_('This repository already exists') ,
149 raise formencode.Invalid(_('This repository already exists') ,
172 value, state)
150 value, state)
173 meta.Session.remove()
151 meta.Session.remove()
174 return slug
152 return slug
175
153
176
154
177 return _ValidRepoName
155 return _ValidRepoName
178
156
179 class ValidPerms(formencode.validators.FancyValidator):
157 class ValidPerms(formencode.validators.FancyValidator):
180 messages = {'perm_new_user_name':_('This username is not valid')}
158 messages = {'perm_new_user_name':_('This username is not valid')}
181
159
182 def to_python(self, value, state):
160 def to_python(self, value, state):
183 perms_update = []
161 perms_update = []
184 perms_new = []
162 perms_new = []
185 #build a list of permission to update and new permission to create
163 #build a list of permission to update and new permission to create
186 for k, v in value.items():
164 for k, v in value.items():
187 if k.startswith('perm_'):
165 if k.startswith('perm_'):
188 if k.startswith('perm_new_user'):
166 if k.startswith('perm_new_user'):
189 new_perm = value.get('perm_new_user', False)
167 new_perm = value.get('perm_new_user', False)
190 new_user = value.get('perm_new_user_name', False)
168 new_user = value.get('perm_new_user_name', False)
191 if new_user and new_perm:
169 if new_user and new_perm:
192 if (new_user, new_perm) not in perms_new:
170 if (new_user, new_perm) not in perms_new:
193 perms_new.append((new_user, new_perm))
171 perms_new.append((new_user, new_perm))
194 else:
172 else:
195 usr = k[5:]
173 usr = k[5:]
196 if usr == 'default':
174 if usr == 'default':
197 if value['private']:
175 if value['private']:
198 #set none for default when updating to private repo
176 #set none for default when updating to private repo
199 v = 'repository.none'
177 v = 'repository.none'
200 perms_update.append((usr, v))
178 perms_update.append((usr, v))
201 value['perms_updates'] = perms_update
179 value['perms_updates'] = perms_update
202 value['perms_new'] = perms_new
180 value['perms_new'] = perms_new
203 sa = meta.Session
181 sa = meta.Session
204 for k, v in perms_new:
182 for k, v in perms_new:
205 try:
183 try:
206 self.user_db = sa.query(User)\
184 self.user_db = sa.query(User)\
207 .filter(User.active == True)\
185 .filter(User.active == True)\
208 .filter(User.username == k).one()
186 .filter(User.username == k).one()
209 except Exception:
187 except Exception:
210 msg = self.message('perm_new_user_name',
188 msg = self.message('perm_new_user_name',
211 state=State_obj)
189 state=State_obj)
212 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
190 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
213 return value
191 return value
214
192
215 class ValidSettings(formencode.validators.FancyValidator):
193 class ValidSettings(formencode.validators.FancyValidator):
216
194
217 def to_python(self, value, state):
195 def to_python(self, value, state):
218 #settings form can't edit user
196 #settings form can't edit user
219 if value.has_key('user'):
197 if value.has_key('user'):
220 del['value']['user']
198 del['value']['user']
221
199
222 return value
200 return value
223
201
224 class ValidPath(formencode.validators.FancyValidator):
202 class ValidPath(formencode.validators.FancyValidator):
225 def to_python(self, value, state):
203 def to_python(self, value, state):
226 isdir = os.path.isdir(value.replace('*', ''))
204 isdir = os.path.isdir(value.replace('*', ''))
227 if (value.endswith('/*') or value.endswith('/**')) and isdir:
205 if (value.endswith('/*') or value.endswith('/**')) and isdir:
228 return value
206 return value
229 elif not isdir:
207 elif not isdir:
230 msg = _('This is not a valid path')
208 msg = _('This is not a valid path')
231 else:
209 else:
232 msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
210 msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
233
211
234 raise formencode.Invalid(msg, value, state,
212 raise formencode.Invalid(msg, value, state,
235 error_dict={'paths_root_path':msg})
213 error_dict={'paths_root_path':msg})
236
214
237 #===============================================================================
215 #===============================================================================
238 # FORMS
216 # FORMS
239 #===============================================================================
217 #===============================================================================
240 class LoginForm(formencode.Schema):
218 class LoginForm(formencode.Schema):
241 allow_extra_fields = True
219 allow_extra_fields = True
242 filter_extra_fields = True
220 filter_extra_fields = True
243 username = UnicodeString(
221 username = UnicodeString(
244 strip=True,
222 strip=True,
245 min=3,
223 min=3,
246 not_empty=True,
224 not_empty=True,
247 messages={
225 messages={
248 'empty':_('Please enter a login'),
226 'empty':_('Please enter a login'),
249 'tooShort':_('Enter a value %(min)i characters long or more')}
227 'tooShort':_('Enter a value %(min)i characters long or more')}
250 )
228 )
251
229
252 password = UnicodeString(
230 password = UnicodeString(
253 strip=True,
231 strip=True,
254 min=3,
232 min=3,
255 not_empty=True,
233 not_empty=True,
256 messages={
234 messages={
257 'empty':_('Please enter a password'),
235 'empty':_('Please enter a password'),
258 'tooShort':_('Enter a value %(min)i characters long or more')}
236 'tooShort':_('Enter a value %(min)i characters long or more')}
259 )
237 )
260
238
261
239
262 #chained validators have access to all data
240 #chained validators have access to all data
263 chained_validators = [ValidAuth]
241 chained_validators = [ValidAuth]
264
242
265 def UserForm(edit=False, old_data={}):
243 def UserForm(edit=False, old_data={}):
266 class _UserForm(formencode.Schema):
244 class _UserForm(formencode.Schema):
267 allow_extra_fields = True
245 allow_extra_fields = True
268 filter_extra_fields = True
246 filter_extra_fields = True
269 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
247 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
270 if edit:
248 if edit:
271 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
249 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
272 admin = StringBoolean(if_missing=False)
250 admin = StringBoolean(if_missing=False)
273 else:
251 else:
274 password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
252 password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
275 active = StringBoolean(if_missing=False)
253 active = StringBoolean(if_missing=False)
276 name = UnicodeString(strip=True, min=3, not_empty=True)
254 name = UnicodeString(strip=True, min=3, not_empty=True)
277 lastname = UnicodeString(strip=True, min=3, not_empty=True)
255 lastname = UnicodeString(strip=True, min=3, not_empty=True)
278 email = Email(not_empty=True)
256 email = Email(not_empty=True)
279
257
280 return _UserForm
258 return _UserForm
281
259
282 RegisterForm = UserForm
260 RegisterForm = UserForm
283
261
284
262
285 def RepoForm(edit=False, old_data={}):
263 def RepoForm(edit=False, old_data={}):
286 class _RepoForm(formencode.Schema):
264 class _RepoForm(formencode.Schema):
287 allow_extra_fields = True
265 allow_extra_fields = True
288 filter_extra_fields = False
266 filter_extra_fields = False
289 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
267 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
290 description = UnicodeString(strip=True, min=3, not_empty=True)
268 description = UnicodeString(strip=True, min=3, not_empty=True)
291 private = StringBoolean(if_missing=False)
269 private = StringBoolean(if_missing=False)
292
270
293 if edit:
271 if edit:
294 user = All(Int(not_empty=True), ValidRepoUser)
272 user = All(Int(not_empty=True), ValidRepoUser)
295
273
296 chained_validators = [ValidPerms]
274 chained_validators = [ValidPerms]
297 return _RepoForm
275 return _RepoForm
298
276
299 def RepoSettingsForm(edit=False, old_data={}):
277 def RepoSettingsForm(edit=False, old_data={}):
300 class _RepoForm(formencode.Schema):
278 class _RepoForm(formencode.Schema):
301 allow_extra_fields = True
279 allow_extra_fields = True
302 filter_extra_fields = False
280 filter_extra_fields = False
303 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
281 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
304 description = UnicodeString(strip=True, min=3, not_empty=True)
282 description = UnicodeString(strip=True, min=3, not_empty=True)
305 private = StringBoolean(if_missing=False)
283 private = StringBoolean(if_missing=False)
306
284
307 chained_validators = [ValidPerms, ValidSettings]
285 chained_validators = [ValidPerms, ValidSettings]
308 return _RepoForm
286 return _RepoForm
309
287
310
288
311 def ApplicationSettingsForm():
289 def ApplicationSettingsForm():
312 class _ApplicationSettingsForm(formencode.Schema):
290 class _ApplicationSettingsForm(formencode.Schema):
313 allow_extra_fields = True
291 allow_extra_fields = True
314 filter_extra_fields = False
292 filter_extra_fields = False
315 hg_app_title = UnicodeString(strip=True, min=3, not_empty=True)
293 hg_app_title = UnicodeString(strip=True, min=3, not_empty=True)
316 hg_app_realm = UnicodeString(strip=True, min=3, not_empty=True)
294 hg_app_realm = UnicodeString(strip=True, min=3, not_empty=True)
317
295
318 return _ApplicationSettingsForm
296 return _ApplicationSettingsForm
319
297
320 def ApplicationUiSettingsForm():
298 def ApplicationUiSettingsForm():
321 class _ApplicationUiSettingsForm(formencode.Schema):
299 class _ApplicationUiSettingsForm(formencode.Schema):
322 allow_extra_fields = True
300 allow_extra_fields = True
323 filter_extra_fields = False
301 filter_extra_fields = False
324 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
302 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
325 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=3, not_empty=True))
303 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=3, not_empty=True))
326 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
304 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
327 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
305 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
328
306
329 return _ApplicationUiSettingsForm
307 return _ApplicationUiSettingsForm
330
308
331 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
309 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
332 class _DefaultPermissionsForm(formencode.Schema):
310 class _DefaultPermissionsForm(formencode.Schema):
333 allow_extra_fields = True
311 allow_extra_fields = True
334 filter_extra_fields = True
312 filter_extra_fields = True
335 overwrite_default = OneOf(['true', 'false'], if_missing='false')
313 overwrite_default = OneOf(['true', 'false'], if_missing='false')
336 default_perm = OneOf(perms_choices)
314 default_perm = OneOf(perms_choices)
337 default_register = OneOf(register_choices)
315 default_register = OneOf(register_choices)
338 default_create = OneOf(create_choices)
316 default_create = OneOf(create_choices)
339
317
340 return _DefaultPermissionsForm
318 return _DefaultPermissionsForm
@@ -1,128 +1,131 b''
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_default(self):
40 def get_default(self):
41 return self.sa.query(User).filter(User.username == 'default').scalar()
41 return self.sa.query(User).filter(User.username == 'default').scalar()
42
42
43 def get_user(self, id):
43 def get_user(self, id):
44 return self.sa.query(User).get(id)
44 return self.sa.query(User).get(id)
45
45
46 def get_user_by_name(self,name):
47 return self.sa.query(User).filter(User.username == name).scalar()
48
46 def create(self, form_data):
49 def create(self, form_data):
47 try:
50 try:
48 new_user = User()
51 new_user = User()
49 for k, v in form_data.items():
52 for k, v in form_data.items():
50 setattr(new_user, k, v)
53 setattr(new_user, k, v)
51
54
52 self.sa.add(new_user)
55 self.sa.add(new_user)
53 self.sa.commit()
56 self.sa.commit()
54 except Exception as e:
57 except Exception as e:
55 log.error(e)
58 log.error(e)
56 self.sa.rollback()
59 self.sa.rollback()
57 raise
60 raise
58
61
59 def create_registration(self, form_data):
62 def create_registration(self, form_data):
60 try:
63 try:
61 new_user = User()
64 new_user = User()
62 for k, v in form_data.items():
65 for k, v in form_data.items():
63 if k != 'admin':
66 if k != 'admin':
64 setattr(new_user, k, v)
67 setattr(new_user, k, v)
65
68
66 self.sa.add(new_user)
69 self.sa.add(new_user)
67 self.sa.commit()
70 self.sa.commit()
68 except Exception as e:
71 except Exception as e:
69 log.error(e)
72 log.error(e)
70 self.sa.rollback()
73 self.sa.rollback()
71 raise
74 raise
72
75
73 def update(self, uid, form_data):
76 def update(self, uid, form_data):
74 try:
77 try:
75 new_user = self.sa.query(User).get(uid)
78 new_user = self.sa.query(User).get(uid)
76 if new_user.username == 'default':
79 if new_user.username == 'default':
77 raise DefaultUserException(
80 raise DefaultUserException(
78 _("You can't Edit this user since it's"
81 _("You can't Edit this user since it's"
79 " crucial for entire application"))
82 " crucial for entire application"))
80 for k, v in form_data.items():
83 for k, v in form_data.items():
81 if k == 'new_password' and v != '':
84 if k == 'new_password' and v != '':
82 new_user.password = v
85 new_user.password = v
83 else:
86 else:
84 setattr(new_user, k, v)
87 setattr(new_user, k, v)
85
88
86 self.sa.add(new_user)
89 self.sa.add(new_user)
87 self.sa.commit()
90 self.sa.commit()
88 except Exception as e:
91 except Exception as e:
89 log.error(e)
92 log.error(e)
90 self.sa.rollback()
93 self.sa.rollback()
91 raise
94 raise
92
95
93 def update_my_account(self, uid, form_data):
96 def update_my_account(self, uid, form_data):
94 try:
97 try:
95 new_user = self.sa.query(User).get(uid)
98 new_user = self.sa.query(User).get(uid)
96 if new_user.username == 'default':
99 if new_user.username == 'default':
97 raise DefaultUserException(
100 raise DefaultUserException(
98 _("You can't Edit this user since it's"
101 _("You can't Edit this user since it's"
99 " crucial for entire application"))
102 " crucial for entire application"))
100 for k, v in form_data.items():
103 for k, v in form_data.items():
101 if k == 'new_password' and v != '':
104 if k == 'new_password' and v != '':
102 new_user.password = v
105 new_user.password = v
103 else:
106 else:
104 if k not in ['admin', 'active']:
107 if k not in ['admin', 'active']:
105 setattr(new_user, k, v)
108 setattr(new_user, k, v)
106
109
107 self.sa.add(new_user)
110 self.sa.add(new_user)
108 self.sa.commit()
111 self.sa.commit()
109 except Exception as e:
112 except Exception as e:
110 log.error(e)
113 log.error(e)
111 self.sa.rollback()
114 self.sa.rollback()
112 raise
115 raise
113
116
114 def delete(self, id):
117 def delete(self, id):
115
118
116 try:
119 try:
117
120
118 user = self.sa.query(User).get(id)
121 user = self.sa.query(User).get(id)
119 if user.username == 'default':
122 if user.username == 'default':
120 raise DefaultUserException(
123 raise DefaultUserException(
121 _("You can't remove this user since it's"
124 _("You can't remove this user since it's"
122 " crucial for entire application"))
125 " crucial for entire application"))
123 self.sa.delete(user)
126 self.sa.delete(user)
124 self.sa.commit()
127 self.sa.commit()
125 except Exception as e:
128 except Exception as e:
126 log.error(e)
129 log.error(e)
127 self.sa.rollback()
130 self.sa.rollback()
128 raise
131 raise
General Comments 0
You need to be logged in to leave comments. Login now