##// END OF EJS Templates
fixes #35 hg-app does not respect SCRIPT_NAME
marcink -
r508:fdb78a14 default
parent child Browse files
Show More
@@ -1,103 +1,105
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # summary controller for pylons
3 # summary 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 Created on April 18, 2010
21 Created on April 18, 2010
22 summary controller for pylons
22 summary controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from pylons import tmpl_context as c, request, url
25 from pylons import tmpl_context as c, request, url
26 from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
26 from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
27 from pylons_app.lib.base import BaseController, render
27 from pylons_app.lib.base import BaseController, render
28 from pylons_app.lib.utils import OrderedDict
28 from pylons_app.lib.utils import OrderedDict
29 from pylons_app.model.hg_model import HgModel
29 from pylons_app.model.hg_model import HgModel
30 from pylons_app.model.db import Statistics
30 from pylons_app.model.db import Statistics
31 from webhelpers.paginate import Page
31 from webhelpers.paginate import Page
32 from pylons_app.lib.celerylib import run_task
32 from pylons_app.lib.celerylib import run_task
33 from pylons_app.lib.celerylib.tasks import get_commits_stats
33 from pylons_app.lib.celerylib.tasks import get_commits_stats
34 from datetime import datetime, timedelta
34 from datetime import datetime, timedelta
35 from time import mktime
35 from time import mktime
36 import calendar
36 import calendar
37 import logging
37 import logging
38 import json
38 import json
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41 class SummaryController(BaseController):
41 class SummaryController(BaseController):
42
42
43 @LoginRequired()
43 @LoginRequired()
44 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
44 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
45 'repository.admin')
45 'repository.admin')
46 def __before__(self):
46 def __before__(self):
47 super(SummaryController, self).__before__()
47 super(SummaryController, self).__before__()
48
48
49 def index(self):
49 def index(self):
50 hg_model = HgModel()
50 hg_model = HgModel()
51 c.repo_info = hg_model.get_repo(c.repo_name)
51 c.repo_info = hg_model.get_repo(c.repo_name)
52 c.repo_changesets = Page(list(c.repo_info[:10]), page=1, items_per_page=20)
52 c.repo_changesets = Page(list(c.repo_info[:10]), page=1, items_per_page=20)
53 e = request.environ
53 e = request.environ
54 uri = u'%(protocol)s://%(user)s@%(host)s/%(repo_name)s' % {
54
55 uri = u'%(protocol)s://%(user)s@%(host)s%(prefix)s/%(repo_name)s' % {
55 'protocol': e.get('wsgi.url_scheme'),
56 'protocol': e.get('wsgi.url_scheme'),
56 'user':str(c.hg_app_user.username),
57 'user':str(c.hg_app_user.username),
57 'host':e.get('HTTP_HOST'),
58 'host':e.get('HTTP_HOST'),
59 'prefix':e.get('SCRIPT_NAME'),
58 'repo_name':c.repo_name, }
60 'repo_name':c.repo_name, }
59 c.clone_repo_url = uri
61 c.clone_repo_url = uri
60 c.repo_tags = OrderedDict()
62 c.repo_tags = OrderedDict()
61 for name, hash in c.repo_info.tags.items()[:10]:
63 for name, hash in c.repo_info.tags.items()[:10]:
62 c.repo_tags[name] = c.repo_info.get_changeset(hash)
64 c.repo_tags[name] = c.repo_info.get_changeset(hash)
63
65
64 c.repo_branches = OrderedDict()
66 c.repo_branches = OrderedDict()
65 for name, hash in c.repo_info.branches.items()[:10]:
67 for name, hash in c.repo_info.branches.items()[:10]:
66 c.repo_branches[name] = c.repo_info.get_changeset(hash)
68 c.repo_branches[name] = c.repo_info.get_changeset(hash)
67
69
68 td = datetime.today() + timedelta(days=1)
70 td = datetime.today() + timedelta(days=1)
69 y, m, d = td.year, td.month, td.day
71 y, m, d = td.year, td.month, td.day
70
72
71 ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
73 ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
72 d, 0, 0, 0, 0, 0, 0,))
74 d, 0, 0, 0, 0, 0, 0,))
73 ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
75 ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
74 d, 0, 0, 0, 0, 0, 0,))
76 d, 0, 0, 0, 0, 0, 0,))
75
77
76 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
78 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
77
79
78 run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
80 run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
79 c.ts_min = ts_min_m
81 c.ts_min = ts_min_m
80 c.ts_max = ts_max_y
82 c.ts_max = ts_max_y
81
83
82 stats = self.sa.query(Statistics)\
84 stats = self.sa.query(Statistics)\
83 .filter(Statistics.repository == c.repo_info.dbrepo)\
85 .filter(Statistics.repository == c.repo_info.dbrepo)\
84 .scalar()
86 .scalar()
85
87
86
88
87 if stats and stats.languages:
89 if stats and stats.languages:
88 lang_stats = json.loads(stats.languages)
90 lang_stats = json.loads(stats.languages)
89 c.commit_data = stats.commit_activity
91 c.commit_data = stats.commit_activity
90 c.overview_data = stats.commit_activity_combined
92 c.overview_data = stats.commit_activity_combined
91 c.trending_languages = json.dumps(OrderedDict(
93 c.trending_languages = json.dumps(OrderedDict(
92 sorted(lang_stats.items(), reverse=True,
94 sorted(lang_stats.items(), reverse=True,
93 key=lambda k: k[1])[:2]
95 key=lambda k: k[1])[:2]
94 )
96 )
95 )
97 )
96 print c.trending_languages
98 print c.trending_languages
97 else:
99 else:
98 c.commit_data = json.dumps({})
100 c.commit_data = json.dumps({})
99 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 0] ])
101 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 0] ])
100 c.trending_languages = json.dumps({})
102 c.trending_languages = json.dumps({})
101
103
102 return render('summary/summary.html')
104 return render('summary/summary.html')
103
105
@@ -1,481 +1,486
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 import random
37 import random
38
38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41 class PasswordGenerator(object):
41 class PasswordGenerator(object):
42 """This is a simple class for generating password from
42 """This is a simple class for generating password from
43 different sets of characters
43 different sets of characters
44 usage:
44 usage:
45 passwd_gen = PasswordGenerator()
45 passwd_gen = PasswordGenerator()
46 #print 8-letter password containing only big and small letters of alphabet
46 #print 8-letter password containing only big and small letters of alphabet
47 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
47 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
48 """
48 """
49 ALPHABETS_NUM = r'''1234567890'''#[0]
49 ALPHABETS_NUM = r'''1234567890'''#[0]
50 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
50 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
51 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
51 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
52 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
52 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
53 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
53 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
54 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
54 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
55 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
55 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
56 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
56 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
57 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
57 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
58
58
59 def __init__(self, passwd=''):
59 def __init__(self, passwd=''):
60 self.passwd = passwd
60 self.passwd = passwd
61
61
62 def gen_password(self, len, type):
62 def gen_password(self, len, type):
63 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
63 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
64 return self.passwd
64 return self.passwd
65
65
66
66
67 def get_crypt_password(password):
67 def get_crypt_password(password):
68 """Cryptographic function used for password hashing based on sha1
68 """Cryptographic function used for password hashing based on sha1
69 @param password: password to hash
69 @param password: password to hash
70 """
70 """
71 return bcrypt.hashpw(password, bcrypt.gensalt(10))
71 return bcrypt.hashpw(password, bcrypt.gensalt(10))
72
72
73 def check_password(password, hashed):
73 def check_password(password, hashed):
74 return bcrypt.hashpw(password, hashed) == hashed
74 return bcrypt.hashpw(password, hashed) == hashed
75
75
76 @cache_region('super_short_term', 'cached_user')
76 @cache_region('super_short_term', 'cached_user')
77 def get_user_cached(username):
77 def get_user_cached(username):
78 sa = meta.Session
78 sa = meta.Session
79 try:
79 try:
80 user = sa.query(User).filter(User.username == username).one()
80 user = sa.query(User).filter(User.username == username).one()
81 finally:
81 finally:
82 meta.Session.remove()
82 meta.Session.remove()
83 return user
83 return user
84
84
85 def authfunc(environ, username, password):
85 def authfunc(environ, username, password):
86 try:
86 try:
87 user = get_user_cached(username)
87 user = get_user_cached(username)
88 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
88 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
89 log.error(e)
89 log.error(e)
90 user = None
90 user = None
91
91
92 if user:
92 if user:
93 if user.active:
93 if user.active:
94 if user.username == username and check_password(password, user.password):
94 if user.username == username and check_password(password, user.password):
95 log.info('user %s authenticated correctly', username)
95 log.info('user %s authenticated correctly', username)
96 return True
96 return True
97 else:
97 else:
98 log.error('user %s is disabled', username)
98 log.error('user %s is disabled', username)
99
99
100 return False
100 return False
101
101
102 class AuthUser(object):
102 class AuthUser(object):
103 """
103 """
104 A simple object that handles a mercurial username for authentication
104 A simple object that handles a mercurial username for authentication
105 """
105 """
106 def __init__(self):
106 def __init__(self):
107 self.username = 'None'
107 self.username = 'None'
108 self.name = ''
108 self.name = ''
109 self.lastname = ''
109 self.lastname = ''
110 self.email = ''
110 self.email = ''
111 self.user_id = None
111 self.user_id = None
112 self.is_authenticated = False
112 self.is_authenticated = False
113 self.is_admin = False
113 self.is_admin = False
114 self.permissions = {}
114 self.permissions = {}
115
115
116
116
117 def set_available_permissions(config):
117 def set_available_permissions(config):
118 """
118 """
119 This function will propagate pylons globals with all available defined
119 This function will propagate pylons globals with all available defined
120 permission given in db. We don't wannt to check each time from db for new
120 permission given in db. We don't wannt to check each time from db for new
121 permissions since adding a new permission also requires application restart
121 permissions since adding a new permission also requires application restart
122 ie. to decorate new views with the newly created permission
122 ie. to decorate new views with the newly created permission
123 @param config:
123 @param config:
124 """
124 """
125 log.info('getting information about all available permissions')
125 log.info('getting information about all available permissions')
126 try:
126 try:
127 sa = meta.Session
127 sa = meta.Session
128 all_perms = sa.query(Permission).all()
128 all_perms = sa.query(Permission).all()
129 finally:
129 finally:
130 meta.Session.remove()
130 meta.Session.remove()
131
131
132 config['available_permissions'] = [x.permission_name for x in all_perms]
132 config['available_permissions'] = [x.permission_name for x in all_perms]
133
133
134 def set_base_path(config):
134 def set_base_path(config):
135 config['base_path'] = config['pylons.app_globals'].base_path
135 config['base_path'] = config['pylons.app_globals'].base_path
136
136
137 def fill_data(user):
137 def fill_data(user):
138 """
138 """
139 Fills user data with those from database and log out user if not present
139 Fills user data with those from database and log out user if not present
140 in database
140 in database
141 @param user:
141 @param user:
142 """
142 """
143 sa = meta.Session
143 sa = meta.Session
144 dbuser = sa.query(User).get(user.user_id)
144 dbuser = sa.query(User).get(user.user_id)
145 if dbuser:
145 if dbuser:
146 user.username = dbuser.username
146 user.username = dbuser.username
147 user.is_admin = dbuser.admin
147 user.is_admin = dbuser.admin
148 user.name = dbuser.name
148 user.name = dbuser.name
149 user.lastname = dbuser.lastname
149 user.lastname = dbuser.lastname
150 user.email = dbuser.email
150 user.email = dbuser.email
151 else:
151 else:
152 user.is_authenticated = False
152 user.is_authenticated = False
153 meta.Session.remove()
153 meta.Session.remove()
154 return user
154 return user
155
155
156 def fill_perms(user):
156 def fill_perms(user):
157 """
157 """
158 Fills user permission attribute with permissions taken from database
158 Fills user permission attribute with permissions taken from database
159 @param user:
159 @param user:
160 """
160 """
161
161
162 sa = meta.Session
162 sa = meta.Session
163 user.permissions['repositories'] = {}
163 user.permissions['repositories'] = {}
164 user.permissions['global'] = set()
164 user.permissions['global'] = set()
165
165
166 #===========================================================================
166 #===========================================================================
167 # fetch default permissions
167 # fetch default permissions
168 #===========================================================================
168 #===========================================================================
169 default_perms = sa.query(RepoToPerm, Repository, Permission)\
169 default_perms = sa.query(RepoToPerm, Repository, Permission)\
170 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
170 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
171 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
171 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
172 .filter(RepoToPerm.user == sa.query(User).filter(User.username ==
172 .filter(RepoToPerm.user == sa.query(User).filter(User.username ==
173 'default').scalar()).all()
173 'default').scalar()).all()
174
174
175 if user.is_admin:
175 if user.is_admin:
176 #=======================================================================
176 #=======================================================================
177 # #admin have all default rights set to admin
177 # #admin have all default rights set to admin
178 #=======================================================================
178 #=======================================================================
179 user.permissions['global'].add('hg.admin')
179 user.permissions['global'].add('hg.admin')
180
180
181 for perm in default_perms:
181 for perm in default_perms:
182 p = 'repository.admin'
182 p = 'repository.admin'
183 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
183 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
184
184
185 else:
185 else:
186 #=======================================================================
186 #=======================================================================
187 # set default permissions
187 # set default permissions
188 #=======================================================================
188 #=======================================================================
189
189
190 #default global
190 #default global
191 default_global_perms = sa.query(UserToPerm)\
191 default_global_perms = sa.query(UserToPerm)\
192 .filter(UserToPerm.user == sa.query(User).filter(User.username ==
192 .filter(UserToPerm.user == sa.query(User).filter(User.username ==
193 'default').one())
193 'default').one())
194
194
195 for perm in default_global_perms:
195 for perm in default_global_perms:
196 user.permissions['global'].add(perm.permission.permission_name)
196 user.permissions['global'].add(perm.permission.permission_name)
197
197
198 #default repositories
198 #default repositories
199 for perm in default_perms:
199 for perm in default_perms:
200 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
200 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
201 #disable defaults for private repos,
201 #disable defaults for private repos,
202 p = 'repository.none'
202 p = 'repository.none'
203 elif perm.Repository.user_id == user.user_id:
203 elif perm.Repository.user_id == user.user_id:
204 #set admin if owner
204 #set admin if owner
205 p = 'repository.admin'
205 p = 'repository.admin'
206 else:
206 else:
207 p = perm.Permission.permission_name
207 p = perm.Permission.permission_name
208
208
209 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
209 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
210
210
211 #=======================================================================
211 #=======================================================================
212 # #overwrite default with user permissions if any
212 # #overwrite default with user permissions if any
213 #=======================================================================
213 #=======================================================================
214 user_perms = sa.query(RepoToPerm, Permission, Repository)\
214 user_perms = sa.query(RepoToPerm, Permission, Repository)\
215 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
215 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
216 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
216 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
217 .filter(RepoToPerm.user_id == user.user_id).all()
217 .filter(RepoToPerm.user_id == user.user_id).all()
218
218
219 for perm in user_perms:
219 for perm in user_perms:
220 if perm.Repository.user_id == user.user_id:#set admin if owner
220 if perm.Repository.user_id == user.user_id:#set admin if owner
221 p = 'repository.admin'
221 p = 'repository.admin'
222 else:
222 else:
223 p = perm.Permission.permission_name
223 p = perm.Permission.permission_name
224 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
224 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
225 meta.Session.remove()
225 meta.Session.remove()
226 return user
226 return user
227
227
228 def get_user(session):
228 def get_user(session):
229 """
229 """
230 Gets user from session, and wraps permissions into user
230 Gets user from session, and wraps permissions into user
231 @param session:
231 @param session:
232 """
232 """
233 user = session.get('hg_app_user', AuthUser())
233 user = session.get('hg_app_user', AuthUser())
234 if user.is_authenticated:
234 if user.is_authenticated:
235 user = fill_data(user)
235 user = fill_data(user)
236 user = fill_perms(user)
236 user = fill_perms(user)
237 session['hg_app_user'] = user
237 session['hg_app_user'] = user
238 session.save()
238 session.save()
239 return user
239 return user
240
240
241 #===============================================================================
241 #===============================================================================
242 # CHECK DECORATORS
242 # CHECK DECORATORS
243 #===============================================================================
243 #===============================================================================
244 class LoginRequired(object):
244 class LoginRequired(object):
245 """Must be logged in to execute this function else redirect to login page"""
245 """Must be logged in to execute this function else redirect to login page"""
246
246
247 def __call__(self, func):
247 def __call__(self, func):
248 return decorator(self.__wrapper, func)
248 return decorator(self.__wrapper, func)
249
249
250 def __wrapper(self, func, *fargs, **fkwargs):
250 def __wrapper(self, func, *fargs, **fkwargs):
251 user = session.get('hg_app_user', AuthUser())
251 user = session.get('hg_app_user', AuthUser())
252 log.debug('Checking login required for user:%s', user.username)
252 log.debug('Checking login required for user:%s', user.username)
253 if user.is_authenticated:
253 if user.is_authenticated:
254 log.debug('user %s is authenticated', user.username)
254 log.debug('user %s is authenticated', user.username)
255 return func(*fargs, **fkwargs)
255 return func(*fargs, **fkwargs)
256 else:
256 else:
257 log.warn('user %s not authenticated', user.username)
257 log.warn('user %s not authenticated', user.username)
258
258
259 p = request.environ.get('PATH_INFO')
259 p = ''
260 if request.environ.get('SCRIPT_NAME') != '/':
261 p += request.environ.get('SCRIPT_NAME')
262
263 p += request.environ.get('PATH_INFO')
260 if request.environ.get('QUERY_STRING'):
264 if request.environ.get('QUERY_STRING'):
261 p += '?' + request.environ.get('QUERY_STRING')
265 p += '?' + request.environ.get('QUERY_STRING')
266
262 log.debug('redirecting to login page with %s', p)
267 log.debug('redirecting to login page with %s', p)
263 return redirect(url('login_home', came_from=p))
268 return redirect(url('login_home', came_from=p))
264
269
265 class PermsDecorator(object):
270 class PermsDecorator(object):
266 """Base class for decorators"""
271 """Base class for decorators"""
267
272
268 def __init__(self, *required_perms):
273 def __init__(self, *required_perms):
269 available_perms = config['available_permissions']
274 available_perms = config['available_permissions']
270 for perm in required_perms:
275 for perm in required_perms:
271 if perm not in available_perms:
276 if perm not in available_perms:
272 raise Exception("'%s' permission is not defined" % perm)
277 raise Exception("'%s' permission is not defined" % perm)
273 self.required_perms = set(required_perms)
278 self.required_perms = set(required_perms)
274 self.user_perms = None
279 self.user_perms = None
275
280
276 def __call__(self, func):
281 def __call__(self, func):
277 return decorator(self.__wrapper, func)
282 return decorator(self.__wrapper, func)
278
283
279
284
280 def __wrapper(self, func, *fargs, **fkwargs):
285 def __wrapper(self, func, *fargs, **fkwargs):
281 # _wrapper.__name__ = func.__name__
286 # _wrapper.__name__ = func.__name__
282 # _wrapper.__dict__.update(func.__dict__)
287 # _wrapper.__dict__.update(func.__dict__)
283 # _wrapper.__doc__ = func.__doc__
288 # _wrapper.__doc__ = func.__doc__
284
289
285 self.user_perms = session.get('hg_app_user', AuthUser()).permissions
290 self.user_perms = session.get('hg_app_user', AuthUser()).permissions
286 log.debug('checking %s permissions %s for %s',
291 log.debug('checking %s permissions %s for %s',
287 self.__class__.__name__, self.required_perms, func.__name__)
292 self.__class__.__name__, self.required_perms, func.__name__)
288
293
289 if self.check_permissions():
294 if self.check_permissions():
290 log.debug('Permission granted for %s', func.__name__)
295 log.debug('Permission granted for %s', func.__name__)
291
296
292 return func(*fargs, **fkwargs)
297 return func(*fargs, **fkwargs)
293
298
294 else:
299 else:
295 log.warning('Permission denied for %s', func.__name__)
300 log.warning('Permission denied for %s', func.__name__)
296 #redirect with forbidden ret code
301 #redirect with forbidden ret code
297 return abort(403)
302 return abort(403)
298
303
299
304
300
305
301 def check_permissions(self):
306 def check_permissions(self):
302 """Dummy function for overriding"""
307 """Dummy function for overriding"""
303 raise Exception('You have to write this function in child class')
308 raise Exception('You have to write this function in child class')
304
309
305 class HasPermissionAllDecorator(PermsDecorator):
310 class HasPermissionAllDecorator(PermsDecorator):
306 """Checks for access permission for all given predicates. All of them
311 """Checks for access permission for all given predicates. All of them
307 have to be meet in order to fulfill the request
312 have to be meet in order to fulfill the request
308 """
313 """
309
314
310 def check_permissions(self):
315 def check_permissions(self):
311 if self.required_perms.issubset(self.user_perms.get('global')):
316 if self.required_perms.issubset(self.user_perms.get('global')):
312 return True
317 return True
313 return False
318 return False
314
319
315
320
316 class HasPermissionAnyDecorator(PermsDecorator):
321 class HasPermissionAnyDecorator(PermsDecorator):
317 """Checks for access permission for any of given predicates. In order to
322 """Checks for access permission for any of given predicates. In order to
318 fulfill the request any of predicates must be meet
323 fulfill the request any of predicates must be meet
319 """
324 """
320
325
321 def check_permissions(self):
326 def check_permissions(self):
322 if self.required_perms.intersection(self.user_perms.get('global')):
327 if self.required_perms.intersection(self.user_perms.get('global')):
323 return True
328 return True
324 return False
329 return False
325
330
326 class HasRepoPermissionAllDecorator(PermsDecorator):
331 class HasRepoPermissionAllDecorator(PermsDecorator):
327 """Checks for access permission for all given predicates for specific
332 """Checks for access permission for all given predicates for specific
328 repository. All of them have to be meet in order to fulfill the request
333 repository. All of them have to be meet in order to fulfill the request
329 """
334 """
330
335
331 def check_permissions(self):
336 def check_permissions(self):
332 repo_name = get_repo_slug(request)
337 repo_name = get_repo_slug(request)
333 try:
338 try:
334 user_perms = set([self.user_perms['repositories'][repo_name]])
339 user_perms = set([self.user_perms['repositories'][repo_name]])
335 except KeyError:
340 except KeyError:
336 return False
341 return False
337 if self.required_perms.issubset(user_perms):
342 if self.required_perms.issubset(user_perms):
338 return True
343 return True
339 return False
344 return False
340
345
341
346
342 class HasRepoPermissionAnyDecorator(PermsDecorator):
347 class HasRepoPermissionAnyDecorator(PermsDecorator):
343 """Checks for access permission for any of given predicates for specific
348 """Checks for access permission for any of given predicates for specific
344 repository. In order to fulfill the request any of predicates must be meet
349 repository. In order to fulfill the request any of predicates must be meet
345 """
350 """
346
351
347 def check_permissions(self):
352 def check_permissions(self):
348 repo_name = get_repo_slug(request)
353 repo_name = get_repo_slug(request)
349
354
350 try:
355 try:
351 user_perms = set([self.user_perms['repositories'][repo_name]])
356 user_perms = set([self.user_perms['repositories'][repo_name]])
352 except KeyError:
357 except KeyError:
353 return False
358 return False
354 if self.required_perms.intersection(user_perms):
359 if self.required_perms.intersection(user_perms):
355 return True
360 return True
356 return False
361 return False
357 #===============================================================================
362 #===============================================================================
358 # CHECK FUNCTIONS
363 # CHECK FUNCTIONS
359 #===============================================================================
364 #===============================================================================
360
365
361 class PermsFunction(object):
366 class PermsFunction(object):
362 """Base function for other check functions"""
367 """Base function for other check functions"""
363
368
364 def __init__(self, *perms):
369 def __init__(self, *perms):
365 available_perms = config['available_permissions']
370 available_perms = config['available_permissions']
366
371
367 for perm in perms:
372 for perm in perms:
368 if perm not in available_perms:
373 if perm not in available_perms:
369 raise Exception("'%s' permission in not defined" % perm)
374 raise Exception("'%s' permission in not defined" % perm)
370 self.required_perms = set(perms)
375 self.required_perms = set(perms)
371 self.user_perms = None
376 self.user_perms = None
372 self.granted_for = ''
377 self.granted_for = ''
373 self.repo_name = None
378 self.repo_name = None
374
379
375 def __call__(self, check_Location=''):
380 def __call__(self, check_Location=''):
376 user = session.get('hg_app_user', False)
381 user = session.get('hg_app_user', False)
377 if not user:
382 if not user:
378 return False
383 return False
379 self.user_perms = user.permissions
384 self.user_perms = user.permissions
380 self.granted_for = user.username
385 self.granted_for = user.username
381 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
386 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
382
387
383 if self.check_permissions():
388 if self.check_permissions():
384 log.debug('Permission granted for %s @%s', self.granted_for,
389 log.debug('Permission granted for %s @%s', self.granted_for,
385 check_Location)
390 check_Location)
386 return True
391 return True
387
392
388 else:
393 else:
389 log.warning('Permission denied for %s @%s', self.granted_for,
394 log.warning('Permission denied for %s @%s', self.granted_for,
390 check_Location)
395 check_Location)
391 return False
396 return False
392
397
393 def check_permissions(self):
398 def check_permissions(self):
394 """Dummy function for overriding"""
399 """Dummy function for overriding"""
395 raise Exception('You have to write this function in child class')
400 raise Exception('You have to write this function in child class')
396
401
397 class HasPermissionAll(PermsFunction):
402 class HasPermissionAll(PermsFunction):
398 def check_permissions(self):
403 def check_permissions(self):
399 if self.required_perms.issubset(self.user_perms.get('global')):
404 if self.required_perms.issubset(self.user_perms.get('global')):
400 return True
405 return True
401 return False
406 return False
402
407
403 class HasPermissionAny(PermsFunction):
408 class HasPermissionAny(PermsFunction):
404 def check_permissions(self):
409 def check_permissions(self):
405 if self.required_perms.intersection(self.user_perms.get('global')):
410 if self.required_perms.intersection(self.user_perms.get('global')):
406 return True
411 return True
407 return False
412 return False
408
413
409 class HasRepoPermissionAll(PermsFunction):
414 class HasRepoPermissionAll(PermsFunction):
410
415
411 def __call__(self, repo_name=None, check_Location=''):
416 def __call__(self, repo_name=None, check_Location=''):
412 self.repo_name = repo_name
417 self.repo_name = repo_name
413 return super(HasRepoPermissionAll, self).__call__(check_Location)
418 return super(HasRepoPermissionAll, self).__call__(check_Location)
414
419
415 def check_permissions(self):
420 def check_permissions(self):
416 if not self.repo_name:
421 if not self.repo_name:
417 self.repo_name = get_repo_slug(request)
422 self.repo_name = get_repo_slug(request)
418
423
419 try:
424 try:
420 self.user_perms = set([self.user_perms['repositories']\
425 self.user_perms = set([self.user_perms['repositories']\
421 [self.repo_name]])
426 [self.repo_name]])
422 except KeyError:
427 except KeyError:
423 return False
428 return False
424 self.granted_for = self.repo_name
429 self.granted_for = self.repo_name
425 if self.required_perms.issubset(self.user_perms):
430 if self.required_perms.issubset(self.user_perms):
426 return True
431 return True
427 return False
432 return False
428
433
429 class HasRepoPermissionAny(PermsFunction):
434 class HasRepoPermissionAny(PermsFunction):
430
435
431 def __call__(self, repo_name=None, check_Location=''):
436 def __call__(self, repo_name=None, check_Location=''):
432 self.repo_name = repo_name
437 self.repo_name = repo_name
433 return super(HasRepoPermissionAny, self).__call__(check_Location)
438 return super(HasRepoPermissionAny, self).__call__(check_Location)
434
439
435 def check_permissions(self):
440 def check_permissions(self):
436 if not self.repo_name:
441 if not self.repo_name:
437 self.repo_name = get_repo_slug(request)
442 self.repo_name = get_repo_slug(request)
438
443
439 try:
444 try:
440 self.user_perms = set([self.user_perms['repositories']\
445 self.user_perms = set([self.user_perms['repositories']\
441 [self.repo_name]])
446 [self.repo_name]])
442 except KeyError:
447 except KeyError:
443 return False
448 return False
444 self.granted_for = self.repo_name
449 self.granted_for = self.repo_name
445 if self.required_perms.intersection(self.user_perms):
450 if self.required_perms.intersection(self.user_perms):
446 return True
451 return True
447 return False
452 return False
448
453
449 #===============================================================================
454 #===============================================================================
450 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
455 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
451 #===============================================================================
456 #===============================================================================
452
457
453 class HasPermissionAnyMiddleware(object):
458 class HasPermissionAnyMiddleware(object):
454 def __init__(self, *perms):
459 def __init__(self, *perms):
455 self.required_perms = set(perms)
460 self.required_perms = set(perms)
456
461
457 def __call__(self, user, repo_name):
462 def __call__(self, user, repo_name):
458 usr = AuthUser()
463 usr = AuthUser()
459 usr.user_id = user.user_id
464 usr.user_id = user.user_id
460 usr.username = user.username
465 usr.username = user.username
461 usr.is_admin = user.admin
466 usr.is_admin = user.admin
462
467
463 try:
468 try:
464 self.user_perms = set([fill_perms(usr)\
469 self.user_perms = set([fill_perms(usr)\
465 .permissions['repositories'][repo_name]])
470 .permissions['repositories'][repo_name]])
466 except:
471 except:
467 self.user_perms = set()
472 self.user_perms = set()
468 self.granted_for = ''
473 self.granted_for = ''
469 self.username = user.username
474 self.username = user.username
470 self.repo_name = repo_name
475 self.repo_name = repo_name
471 return self.check_permissions()
476 return self.check_permissions()
472
477
473 def check_permissions(self):
478 def check_permissions(self):
474 log.debug('checking mercurial protocol '
479 log.debug('checking mercurial protocol '
475 'permissions for user:%s repository:%s',
480 'permissions for user:%s repository:%s',
476 self.username, self.repo_name)
481 self.username, self.repo_name)
477 if self.required_perms.intersection(self.user_perms):
482 if self.required_perms.intersection(self.user_perms):
478 log.debug('permission granted')
483 log.debug('permission granted')
479 return True
484 return True
480 log.debug('permission denied')
485 log.debug('permission denied')
481 return False
486 return False
General Comments 0
You need to be logged in to leave comments. Login now