##// END OF EJS Templates
permission refactoring,...
marcink -
r417:3ed2d46a default
parent child Browse files
Show More
@@ -0,0 +1,51 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 # Model for permissions
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
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
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
20 """
21 Created on Aug 20, 2010
22 Model for permissions
23 @author: marcink
24 """
25
26 from pylons.i18n.translation import _
27 from pylons_app.model.db import User, Permission
28 from pylons_app.model.meta import Session
29 import logging
30 log = logging.getLogger(__name__)
31
32
33 class PermissionModel(object):
34
35 def __init__(self):
36 self.sa = Session()
37
38 def get_default(self):
39 return self.sa.query(User).filter(User.username == 'default').scalar()
40
41 def get_permission(self, id):
42 return self.sa.query(Permission).get(id)
43
44 def get_permission_by_name(self, name):
45 return self.sa.query(Permission)\
46 .filter(Permission.permission_name == name).scalar()
47
48
49 def update(self, form_result):
50 print form_result
51 pass
@@ -1,90 +1,162 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # permissions controller for pylons
3 # permissions 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 27, 2010
21 Created on April 27, 2010
22 permissions controller for pylons
22 permissions controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25
25 from formencode import htmlfill
26 from formencode import htmlfill
26 from pylons import request, session, tmpl_context as c, url
27 from pylons import request, session, tmpl_context as c, url
27 from pylons.controllers.util import abort, redirect
28 from pylons.controllers.util import abort, redirect
28 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
29 from pylons_app.lib import helpers as h
30 from pylons_app.lib import helpers as h
30 from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator
31 from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator
31 from pylons_app.lib.base import BaseController, render
32 from pylons_app.lib.base import BaseController, render
32 from pylons_app.model.db import User, UserLog
33 from pylons_app.model.db import User, UserLog
33 from pylons_app.model.forms import UserForm
34 from pylons_app.model.forms import UserForm, DefaultPermissionsForm
35 from pylons_app.model.permission_model import PermissionModel
34 from pylons_app.model.user_model import UserModel
36 from pylons_app.model.user_model import UserModel
35 import formencode
37 import formencode
36 import logging
38 import logging
39 import traceback
37
40
38 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
39
42
40 class PermissionsController(BaseController):
43 class PermissionsController(BaseController):
41 """REST Controller styled on the Atom Publishing Protocol"""
44 """REST Controller styled on the Atom Publishing Protocol"""
42 # To properly map this controller, ensure your config/routing.py
45 # To properly map this controller, ensure your config/routing.py
43 # file has a resource setup:
46 # file has a resource setup:
44 # map.resource('permission', 'permissions')
47 # map.resource('permission', 'permissions')
45
48
46 @LoginRequired()
49 @LoginRequired()
47 #@HasPermissionAllDecorator('hg.admin')
50 @HasPermissionAllDecorator('hg.admin')
48 def __before__(self):
51 def __before__(self):
49 c.admin_user = session.get('admin_user')
52 c.admin_user = session.get('admin_user')
50 c.admin_username = session.get('admin_username')
53 c.admin_username = session.get('admin_username')
51 super(PermissionsController, self).__before__()
54 super(PermissionsController, self).__before__()
52
55
56 self.perms_choices = [('repository.none', _('None'),),
57 ('repository.read', _('Read'),),
58 ('repository.write', _('Write'),),
59 ('repository.admin', _('Admin'),)]
60 self.register_choices = [
61 ('hg.register.none', 'disabled'),
62 ('hg.register.manual_activate',
63 _('allowed with manual account activation')),
64 ('hg.register.auto_activate',
65 _('allowed with automatic account activation')), ]
66
67 self.create_choices = [('hg.create.none', _('Disabled')),
68 ('hg.create.repository', _('Enabled'))]
69
70
53 def index(self, format='html'):
71 def index(self, format='html'):
54 """GET /permissions: All items in the collection"""
72 """GET /permissions: All items in the collection"""
55 # url('permissions')
73 # url('permissions')
56 return render('admin/permissions/permissions.html')
57
74
58 def create(self):
75 def create(self):
59 """POST /permissions: Create a new item"""
76 """POST /permissions: Create a new item"""
60 # url('permissions')
77 # url('permissions')
61
78
62 def new(self, format='html'):
79 def new(self, format='html'):
63 """GET /permissions/new: Form to create a new item"""
80 """GET /permissions/new: Form to create a new item"""
64 # url('new_permission')
81 # url('new_permission')
65
82
66 def update(self, id):
83 def update(self, id):
67 """PUT /permissions/id: Update an existing item"""
84 """PUT /permissions/id: Update an existing item"""
68 # Forms posted to this method should contain a hidden field:
85 # Forms posted to this method should contain a hidden field:
69 # <input type="hidden" name="_method" value="PUT" />
86 # <input type="hidden" name="_method" value="PUT" />
70 # Or using helpers:
87 # Or using helpers:
71 # h.form(url('permission', id=ID),
88 # h.form(url('permission', id=ID),
72 # method='put')
89 # method='put')
73 # url('permission', id=ID)
90 # url('permission', id=ID)
74
91
92 permission_model = PermissionModel()
93
94 _form = DefaultPermissionsForm([x[0] for x in self.perms_choices],
95 [x[0] for x in self.register_choices],
96 [x[0] for x in self.create_choices])()
97
98 try:
99 form_result = _form.to_python(dict(request.POST))
100 permission_model.update(form_result)
101 h.flash(_('Default permissions updated succesfully'),
102 category='success')
103
104 except formencode.Invalid as errors:
105 c.perms_choices = self.perms_choices
106 c.register_choices = self.register_choices
107 c.create_choices = self.create_choices
108
109 return htmlfill.render(
110 render('admin/permissions/permissions.html'),
111 defaults=errors.value,
112 errors=errors.error_dict or {},
113 prefix_error=False,
114 encoding="UTF-8")
115 except Exception:
116 log.error(traceback.format_exc())
117 h.flash(_('error occured during update of permissions'),
118 category='error')
119
120 return redirect(url('edit_permission', id=id))
121
122
123
75 def delete(self, id):
124 def delete(self, id):
76 """DELETE /permissions/id: Delete an existing item"""
125 """DELETE /permissions/id: Delete an existing item"""
77 # Forms posted to this method should contain a hidden field:
126 # Forms posted to this method should contain a hidden field:
78 # <input type="hidden" name="_method" value="DELETE" />
127 # <input type="hidden" name="_method" value="DELETE" />
79 # Or using helpers:
128 # Or using helpers:
80 # h.form(url('permission', id=ID),
129 # h.form(url('permission', id=ID),
81 # method='delete')
130 # method='delete')
82 # url('permission', id=ID)
131 # url('permission', id=ID)
83
132
84 def show(self, id, format='html'):
133 def show(self, id, format='html'):
85 """GET /permissions/id: Show a specific item"""
134 """GET /permissions/id: Show a specific item"""
86 # url('permission', id=ID)
135 # url('permission', id=ID)
87
136
88 def edit(self, id, format='html'):
137 def edit(self, id, format='html'):
89 """GET /permissions/id/edit: Form to edit an existing item"""
138 """GET /permissions/id/edit: Form to edit an existing item"""
90 # url('edit_permission', id=ID)
139 #url('edit_permission', id=ID)
140 c.perms_choices = self.perms_choices
141 c.register_choices = self.register_choices
142 c.create_choices = self.create_choices
143
144 if id == 'default':
145 defaults = {'_method':'put'}
146 for p in UserModel().get_default().user_perms:
147 if p.permission.permission_name.startswith('repository.'):
148 defaults['default_perm'] = p.permission.permission_name
149
150 if p.permission.permission_name.startswith('hg.register.'):
151 defaults['default_register'] = p.permission.permission_name
152
153 if p.permission.permission_name.startswith('hg.create.'):
154 defaults['default_create'] = p.permission.permission_name
155
156 return htmlfill.render(
157 render('admin/permissions/permissions.html'),
158 defaults=defaults,
159 encoding="UTF-8",
160 force_defaults=True,)
161 else:
162 return redirect(url('admin_home'))
@@ -1,234 +1,234 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # repos controller for pylons
3 # repos 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 7, 2010
21 Created on April 7, 2010
22 admin controller for pylons
22 admin controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from formencode import htmlfill
25 from formencode import htmlfill
26 from operator import itemgetter
26 from operator import itemgetter
27 from paste.httpexceptions import HTTPInternalServerError
27 from paste.httpexceptions import HTTPInternalServerError
28 from pylons import request, response, session, tmpl_context as c, url
28 from pylons import request, response, session, tmpl_context as c, url
29 from pylons.controllers.util import abort, redirect
29 from pylons.controllers.util import abort, redirect
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31 from pylons_app.lib import helpers as h
31 from pylons_app.lib import helpers as h
32 from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator, \
32 from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator, \
33 HasPermissionAnyDecorator
33 HasPermissionAnyDecorator
34 from pylons_app.lib.base import BaseController, render
34 from pylons_app.lib.base import BaseController, render
35 from pylons_app.lib.utils import invalidate_cache
35 from pylons_app.lib.utils import invalidate_cache
36 from pylons_app.model.db import User
36 from pylons_app.model.db import User
37 from pylons_app.model.forms import RepoForm
37 from pylons_app.model.forms import RepoForm
38 from pylons_app.model.hg_model import HgModel
38 from pylons_app.model.hg_model import HgModel
39 from pylons_app.model.repo_model import RepoModel
39 from pylons_app.model.repo_model import RepoModel
40 import formencode
40 import formencode
41 import logging
41 import logging
42 import traceback
42 import traceback
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46 class ReposController(BaseController):
46 class ReposController(BaseController):
47 """REST Controller styled on the Atom Publishing Protocol"""
47 """REST Controller styled on the Atom Publishing Protocol"""
48 # To properly map this controller, ensure your config/routing.py
48 # To properly map this controller, ensure your config/routing.py
49 # file has a resource setup:
49 # file has a resource setup:
50 # map.resource('repo', 'repos')
50 # map.resource('repo', 'repos')
51
51
52 @LoginRequired()
52 @LoginRequired()
53 @HasPermissionAnyDecorator('hg.admin', 'repository.create')
53 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
54 def __before__(self):
54 def __before__(self):
55 c.admin_user = session.get('admin_user')
55 c.admin_user = session.get('admin_user')
56 c.admin_username = session.get('admin_username')
56 c.admin_username = session.get('admin_username')
57 super(ReposController, self).__before__()
57 super(ReposController, self).__before__()
58
58
59 @HasPermissionAllDecorator('hg.admin')
59 @HasPermissionAllDecorator('hg.admin')
60 def index(self, format='html'):
60 def index(self, format='html'):
61 """GET /repos: All items in the collection"""
61 """GET /repos: All items in the collection"""
62 # url('repos')
62 # url('repos')
63 cached_repo_list = HgModel().get_repos()
63 cached_repo_list = HgModel().get_repos()
64 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
64 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
65 return render('admin/repos/repos.html')
65 return render('admin/repos/repos.html')
66
66
67 @HasPermissionAnyDecorator('hg.admin', 'repository.create')
67 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
68 def create(self):
68 def create(self):
69 """POST /repos: Create a new item"""
69 """POST /repos: Create a new item"""
70 # url('repos')
70 # url('repos')
71 repo_model = RepoModel()
71 repo_model = RepoModel()
72 _form = RepoForm()()
72 _form = RepoForm()()
73 form_result = {}
73 form_result = {}
74 try:
74 try:
75 form_result = _form.to_python(dict(request.POST))
75 form_result = _form.to_python(dict(request.POST))
76 repo_model.create(form_result, c.hg_app_user)
76 repo_model.create(form_result, c.hg_app_user)
77 invalidate_cache('cached_repo_list')
77 invalidate_cache('cached_repo_list')
78 h.flash(_('created repository %s') % form_result['repo_name'],
78 h.flash(_('created repository %s') % form_result['repo_name'],
79 category='success')
79 category='success')
80
80
81 except formencode.Invalid as errors:
81 except formencode.Invalid as errors:
82 c.new_repo = errors.value['repo_name']
82 c.new_repo = errors.value['repo_name']
83
83
84 if request.POST.get('user_created'):
84 if request.POST.get('user_created'):
85 r = render('admin/repos/repo_add_create_repository.html')
85 r = render('admin/repos/repo_add_create_repository.html')
86 else:
86 else:
87 r = render('admin/repos/repo_add.html')
87 r = render('admin/repos/repo_add.html')
88
88
89 return htmlfill.render(
89 return htmlfill.render(
90 r,
90 r,
91 defaults=errors.value,
91 defaults=errors.value,
92 errors=errors.error_dict or {},
92 errors=errors.error_dict or {},
93 prefix_error=False,
93 prefix_error=False,
94 encoding="UTF-8")
94 encoding="UTF-8")
95
95
96 except Exception:
96 except Exception:
97 log.error(traceback.format_exc())
97 log.error(traceback.format_exc())
98 msg = _('error occured during creation of repository %s') \
98 msg = _('error occured during creation of repository %s') \
99 % form_result.get('repo_name')
99 % form_result.get('repo_name')
100 h.flash(msg, category='error')
100 h.flash(msg, category='error')
101 if request.POST.get('user_created'):
101 if request.POST.get('user_created'):
102 return redirect(url('hg_home'))
102 return redirect(url('hg_home'))
103 return redirect(url('repos'))
103 return redirect(url('repos'))
104
104
105 @HasPermissionAllDecorator('hg.admin')
105 @HasPermissionAllDecorator('hg.admin')
106 def new(self, format='html'):
106 def new(self, format='html'):
107 """GET /repos/new: Form to create a new item"""
107 """GET /repos/new: Form to create a new item"""
108 new_repo = request.GET.get('repo', '')
108 new_repo = request.GET.get('repo', '')
109 c.new_repo = h.repo_name_slug(new_repo)
109 c.new_repo = h.repo_name_slug(new_repo)
110
110
111 return render('admin/repos/repo_add.html')
111 return render('admin/repos/repo_add.html')
112
112
113 @HasPermissionAllDecorator('hg.admin')
113 @HasPermissionAllDecorator('hg.admin')
114 def update(self, repo_name):
114 def update(self, repo_name):
115 """PUT /repos/repo_name: Update an existing item"""
115 """PUT /repos/repo_name: Update an existing item"""
116 # Forms posted to this method should contain a hidden field:
116 # Forms posted to this method should contain a hidden field:
117 # <input type="hidden" name="_method" value="PUT" />
117 # <input type="hidden" name="_method" value="PUT" />
118 # Or using helpers:
118 # Or using helpers:
119 # h.form(url('repo', repo_name=ID),
119 # h.form(url('repo', repo_name=ID),
120 # method='put')
120 # method='put')
121 # url('repo', repo_name=ID)
121 # url('repo', repo_name=ID)
122 repo_model = RepoModel()
122 repo_model = RepoModel()
123 changed_name = repo_name
123 changed_name = repo_name
124 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
124 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
125
125
126 try:
126 try:
127 form_result = _form.to_python(dict(request.POST))
127 form_result = _form.to_python(dict(request.POST))
128 repo_model.update(repo_name, form_result)
128 repo_model.update(repo_name, form_result)
129 invalidate_cache('cached_repo_list')
129 invalidate_cache('cached_repo_list')
130 h.flash(_('Repository %s updated succesfully' % repo_name),
130 h.flash(_('Repository %s updated succesfully' % repo_name),
131 category='success')
131 category='success')
132 changed_name = form_result['repo_name']
132 changed_name = form_result['repo_name']
133 except formencode.Invalid as errors:
133 except formencode.Invalid as errors:
134 c.repo_info = repo_model.get(repo_name)
134 c.repo_info = repo_model.get(repo_name)
135 c.users_array = repo_model.get_users_js()
135 c.users_array = repo_model.get_users_js()
136 errors.value.update({'user':c.repo_info.user.username})
136 errors.value.update({'user':c.repo_info.user.username})
137 return htmlfill.render(
137 return htmlfill.render(
138 render('admin/repos/repo_edit.html'),
138 render('admin/repos/repo_edit.html'),
139 defaults=errors.value,
139 defaults=errors.value,
140 errors=errors.error_dict or {},
140 errors=errors.error_dict or {},
141 prefix_error=False,
141 prefix_error=False,
142 encoding="UTF-8")
142 encoding="UTF-8")
143
143
144 except Exception:
144 except Exception:
145 log.error(traceback.format_exc())
145 log.error(traceback.format_exc())
146 h.flash(_('error occured during update of repository %s') \
146 h.flash(_('error occured during update of repository %s') \
147 % repo_name, category='error')
147 % repo_name, category='error')
148
148
149 return redirect(url('edit_repo', repo_name=changed_name))
149 return redirect(url('edit_repo', repo_name=changed_name))
150
150
151 @HasPermissionAllDecorator('hg.admin')
151 @HasPermissionAllDecorator('hg.admin')
152 def delete(self, repo_name):
152 def delete(self, repo_name):
153 """DELETE /repos/repo_name: Delete an existing item"""
153 """DELETE /repos/repo_name: Delete an existing item"""
154 # Forms posted to this method should contain a hidden field:
154 # Forms posted to this method should contain a hidden field:
155 # <input type="hidden" name="_method" value="DELETE" />
155 # <input type="hidden" name="_method" value="DELETE" />
156 # Or using helpers:
156 # Or using helpers:
157 # h.form(url('repo', repo_name=ID),
157 # h.form(url('repo', repo_name=ID),
158 # method='delete')
158 # method='delete')
159 # url('repo', repo_name=ID)
159 # url('repo', repo_name=ID)
160
160
161 repo_model = RepoModel()
161 repo_model = RepoModel()
162 repo = repo_model.get(repo_name)
162 repo = repo_model.get(repo_name)
163 if not repo:
163 if not repo:
164 h.flash(_('%s repository is not mapped to db perhaps'
164 h.flash(_('%s repository is not mapped to db perhaps'
165 ' it was moved or renamed from the filesystem'
165 ' it was moved or renamed from the filesystem'
166 ' please run the application again'
166 ' please run the application again'
167 ' in order to rescan repositories') % repo_name,
167 ' in order to rescan repositories') % repo_name,
168 category='error')
168 category='error')
169
169
170 return redirect(url('repos'))
170 return redirect(url('repos'))
171 try:
171 try:
172 repo_model.delete(repo)
172 repo_model.delete(repo)
173 invalidate_cache('cached_repo_list')
173 invalidate_cache('cached_repo_list')
174 h.flash(_('deleted repository %s') % repo_name, category='success')
174 h.flash(_('deleted repository %s') % repo_name, category='success')
175 except Exception:
175 except Exception:
176 h.flash(_('An error occured during deletion of %s') % repo_name,
176 h.flash(_('An error occured during deletion of %s') % repo_name,
177 category='error')
177 category='error')
178
178
179 return redirect(url('repos'))
179 return redirect(url('repos'))
180
180
181 @HasPermissionAllDecorator('hg.admin')
181 @HasPermissionAllDecorator('hg.admin')
182 def delete_perm_user(self, repo_name):
182 def delete_perm_user(self, repo_name):
183 """
183 """
184 DELETE an existing repository permission user
184 DELETE an existing repository permission user
185 @param repo_name:
185 @param repo_name:
186 """
186 """
187
187
188 try:
188 try:
189 repo_model = RepoModel()
189 repo_model = RepoModel()
190 repo_model.delete_perm_user(request.POST, repo_name)
190 repo_model.delete_perm_user(request.POST, repo_name)
191 except Exception as e:
191 except Exception as e:
192 h.flash(_('An error occured during deletion of repository user'),
192 h.flash(_('An error occured during deletion of repository user'),
193 category='error')
193 category='error')
194 raise HTTPInternalServerError()
194 raise HTTPInternalServerError()
195
195
196 @HasPermissionAllDecorator('hg.admin')
196 @HasPermissionAllDecorator('hg.admin')
197 def show(self, repo_name, format='html'):
197 def show(self, repo_name, format='html'):
198 """GET /repos/repo_name: Show a specific item"""
198 """GET /repos/repo_name: Show a specific item"""
199 # url('repo', repo_name=ID)
199 # url('repo', repo_name=ID)
200
200
201 @HasPermissionAllDecorator('hg.admin')
201 @HasPermissionAllDecorator('hg.admin')
202 def edit(self, repo_name, format='html'):
202 def edit(self, repo_name, format='html'):
203 """GET /repos/repo_name/edit: Form to edit an existing item"""
203 """GET /repos/repo_name/edit: Form to edit an existing item"""
204 # url('edit_repo', repo_name=ID)
204 # url('edit_repo', repo_name=ID)
205 repo_model = RepoModel()
205 repo_model = RepoModel()
206 c.repo_info = repo = repo_model.get(repo_name)
206 c.repo_info = repo = repo_model.get(repo_name)
207 if not repo:
207 if not repo:
208 h.flash(_('%s repository is not mapped to db perhaps'
208 h.flash(_('%s repository is not mapped to db perhaps'
209 ' it was created or renamed from the filesystem'
209 ' it was created or renamed from the filesystem'
210 ' please run the application again'
210 ' please run the application again'
211 ' in order to rescan repositories') % repo_name,
211 ' in order to rescan repositories') % repo_name,
212 category='error')
212 category='error')
213
213
214 return redirect(url('repos'))
214 return redirect(url('repos'))
215 defaults = c.repo_info.__dict__
215 defaults = c.repo_info.__dict__
216 if c.repo_info.user:
216 if c.repo_info.user:
217 defaults.update({'user':c.repo_info.user.username})
217 defaults.update({'user':c.repo_info.user.username})
218 else:
218 else:
219 replacement_user = self.sa.query(User)\
219 replacement_user = self.sa.query(User)\
220 .filter(User.admin == True).first().username
220 .filter(User.admin == True).first().username
221 defaults.update({'user':replacement_user})
221 defaults.update({'user':replacement_user})
222
222
223 c.users_array = repo_model.get_users_js()
223 c.users_array = repo_model.get_users_js()
224
224
225 for p in c.repo_info.repo_to_perm:
225 for p in c.repo_info.repo_to_perm:
226 defaults.update({'perm_%s' % p.user.username:
226 defaults.update({'perm_%s' % p.user.username:
227 p.permission.permission_name})
227 p.permission.permission_name})
228
228
229 return htmlfill.render(
229 return htmlfill.render(
230 render('admin/repos/repo_edit.html'),
230 render('admin/repos/repo_edit.html'),
231 defaults=defaults,
231 defaults=defaults,
232 encoding="UTF-8",
232 encoding="UTF-8",
233 force_defaults=False
233 force_defaults=False
234 )
234 )
@@ -1,281 +1,281 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # settings controller for pylons
3 # settings 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 July 14, 2010
21 Created on July 14, 2010
22 settings controller for pylons
22 settings controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from formencode import htmlfill
25 from formencode import htmlfill
26 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
26 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
27 config
27 config
28 from pylons.controllers.util import abort, redirect
28 from pylons.controllers.util import abort, redirect
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30 from pylons_app.lib import helpers as h
30 from pylons_app.lib import helpers as h
31 from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator, \
31 from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator, \
32 HasPermissionAnyDecorator
32 HasPermissionAnyDecorator
33 from pylons_app.lib.base import BaseController, render
33 from pylons_app.lib.base import BaseController, render
34 from pylons_app.lib.utils import repo2db_mapper, invalidate_cache, \
34 from pylons_app.lib.utils import repo2db_mapper, invalidate_cache, \
35 set_hg_app_config, get_hg_settings, get_hg_ui_settings, make_ui
35 set_hg_app_config, get_hg_settings, get_hg_ui_settings, make_ui
36 from pylons_app.model.db import User, UserLog, HgAppSettings, HgAppUi
36 from pylons_app.model.db import User, UserLog, HgAppSettings, HgAppUi
37 from pylons_app.model.forms import UserForm, ApplicationSettingsForm, \
37 from pylons_app.model.forms import UserForm, ApplicationSettingsForm, \
38 ApplicationUiSettingsForm
38 ApplicationUiSettingsForm
39 from pylons_app.model.hg_model import HgModel
39 from pylons_app.model.hg_model import HgModel
40 from pylons_app.model.user_model import UserModel
40 from pylons_app.model.user_model import UserModel
41 import formencode
41 import formencode
42 import logging
42 import logging
43 import traceback
43 import traceback
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 class SettingsController(BaseController):
48 class SettingsController(BaseController):
49 """REST Controller styled on the Atom Publishing Protocol"""
49 """REST Controller styled on the Atom Publishing Protocol"""
50 # To properly map this controller, ensure your config/routing.py
50 # To properly map this controller, ensure your config/routing.py
51 # file has a resource setup:
51 # file has a resource setup:
52 # map.resource('setting', 'settings', controller='admin/settings',
52 # map.resource('setting', 'settings', controller='admin/settings',
53 # path_prefix='/admin', name_prefix='admin_')
53 # path_prefix='/admin', name_prefix='admin_')
54
54
55
55
56 @LoginRequired()
56 @LoginRequired()
57 def __before__(self):
57 def __before__(self):
58 c.admin_user = session.get('admin_user')
58 c.admin_user = session.get('admin_user')
59 c.admin_username = session.get('admin_username')
59 c.admin_username = session.get('admin_username')
60 super(SettingsController, self).__before__()
60 super(SettingsController, self).__before__()
61
61
62
62
63 @HasPermissionAllDecorator('hg.admin')
63 @HasPermissionAllDecorator('hg.admin')
64 def index(self, format='html'):
64 def index(self, format='html'):
65 """GET /admin/settings: All items in the collection"""
65 """GET /admin/settings: All items in the collection"""
66 # url('admin_settings')
66 # url('admin_settings')
67
67
68 defaults = get_hg_settings()
68 defaults = get_hg_settings()
69 defaults.update(get_hg_ui_settings())
69 defaults.update(get_hg_ui_settings())
70 return htmlfill.render(
70 return htmlfill.render(
71 render('admin/settings/settings.html'),
71 render('admin/settings/settings.html'),
72 defaults=defaults,
72 defaults=defaults,
73 encoding="UTF-8",
73 encoding="UTF-8",
74 force_defaults=False
74 force_defaults=False
75 )
75 )
76
76
77 @HasPermissionAllDecorator('hg.admin')
77 @HasPermissionAllDecorator('hg.admin')
78 def create(self):
78 def create(self):
79 """POST /admin/settings: Create a new item"""
79 """POST /admin/settings: Create a new item"""
80 # url('admin_settings')
80 # url('admin_settings')
81
81
82 @HasPermissionAllDecorator('hg.admin')
82 @HasPermissionAllDecorator('hg.admin')
83 def new(self, format='html'):
83 def new(self, format='html'):
84 """GET /admin/settings/new: Form to create a new item"""
84 """GET /admin/settings/new: Form to create a new item"""
85 # url('admin_new_setting')
85 # url('admin_new_setting')
86
86
87 @HasPermissionAllDecorator('hg.admin')
87 @HasPermissionAllDecorator('hg.admin')
88 def update(self, setting_id):
88 def update(self, setting_id):
89 """PUT /admin/settings/setting_id: Update an existing item"""
89 """PUT /admin/settings/setting_id: Update an existing item"""
90 # Forms posted to this method should contain a hidden field:
90 # Forms posted to this method should contain a hidden field:
91 # <input type="hidden" name="_method" value="PUT" />
91 # <input type="hidden" name="_method" value="PUT" />
92 # Or using helpers:
92 # Or using helpers:
93 # h.form(url('admin_setting', setting_id=ID),
93 # h.form(url('admin_setting', setting_id=ID),
94 # method='put')
94 # method='put')
95 # url('admin_setting', setting_id=ID)
95 # url('admin_setting', setting_id=ID)
96 if setting_id == 'mapping':
96 if setting_id == 'mapping':
97 rm_obsolete = request.POST.get('destroy', False)
97 rm_obsolete = request.POST.get('destroy', False)
98 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
98 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
99
99
100 initial = HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
100 initial = HgModel.repo_scan(g.paths[0][0], g.paths[0][1], g.baseui)
101 repo2db_mapper(initial, rm_obsolete)
101 repo2db_mapper(initial, rm_obsolete)
102 invalidate_cache('cached_repo_list')
102 invalidate_cache('cached_repo_list')
103 h.flash(_('Repositories sucessfully rescanned'), category='success')
103 h.flash(_('Repositories sucessfully rescanned'), category='success')
104
104
105 if setting_id == 'global':
105 if setting_id == 'global':
106
106
107 application_form = ApplicationSettingsForm()()
107 application_form = ApplicationSettingsForm()()
108 try:
108 try:
109 form_result = application_form.to_python(dict(request.POST))
109 form_result = application_form.to_python(dict(request.POST))
110
110
111 try:
111 try:
112 hgsettings1 = self.sa.query(HgAppSettings)\
112 hgsettings1 = self.sa.query(HgAppSettings)\
113 .filter(HgAppSettings.app_settings_name == 'title').one()
113 .filter(HgAppSettings.app_settings_name == 'title').one()
114 hgsettings1.app_settings_value = form_result['hg_app_title']
114 hgsettings1.app_settings_value = form_result['hg_app_title']
115
115
116 hgsettings2 = self.sa.query(HgAppSettings)\
116 hgsettings2 = self.sa.query(HgAppSettings)\
117 .filter(HgAppSettings.app_settings_name == 'realm').one()
117 .filter(HgAppSettings.app_settings_name == 'realm').one()
118 hgsettings2.app_settings_value = form_result['hg_app_realm']
118 hgsettings2.app_settings_value = form_result['hg_app_realm']
119
119
120
120
121 self.sa.add(hgsettings1)
121 self.sa.add(hgsettings1)
122 self.sa.add(hgsettings2)
122 self.sa.add(hgsettings2)
123 self.sa.commit()
123 self.sa.commit()
124 set_hg_app_config(config)
124 set_hg_app_config(config)
125 h.flash(_('Updated application settings'),
125 h.flash(_('Updated application settings'),
126 category='success')
126 category='success')
127
127
128 except:
128 except:
129 log.error(traceback.format_exc())
129 log.error(traceback.format_exc())
130 h.flash(_('error occured during updating application settings'),
130 h.flash(_('error occured during updating application settings'),
131 category='error')
131 category='error')
132
132
133 self.sa.rollback()
133 self.sa.rollback()
134
134
135
135
136 except formencode.Invalid as errors:
136 except formencode.Invalid as errors:
137 return htmlfill.render(
137 return htmlfill.render(
138 render('admin/settings/settings.html'),
138 render('admin/settings/settings.html'),
139 defaults=errors.value,
139 defaults=errors.value,
140 errors=errors.error_dict or {},
140 errors=errors.error_dict or {},
141 prefix_error=False,
141 prefix_error=False,
142 encoding="UTF-8")
142 encoding="UTF-8")
143
143
144 if setting_id == 'mercurial':
144 if setting_id == 'mercurial':
145 application_form = ApplicationUiSettingsForm()()
145 application_form = ApplicationUiSettingsForm()()
146 try:
146 try:
147 form_result = application_form.to_python(dict(request.POST))
147 form_result = application_form.to_python(dict(request.POST))
148
148
149 try:
149 try:
150
150
151 hgsettings1 = self.sa.query(HgAppUi)\
151 hgsettings1 = self.sa.query(HgAppUi)\
152 .filter(HgAppUi.ui_key == 'push_ssl').one()
152 .filter(HgAppUi.ui_key == 'push_ssl').one()
153 hgsettings1.ui_value = form_result['web_push_ssl']
153 hgsettings1.ui_value = form_result['web_push_ssl']
154
154
155 hgsettings2 = self.sa.query(HgAppUi)\
155 hgsettings2 = self.sa.query(HgAppUi)\
156 .filter(HgAppUi.ui_key == '/').one()
156 .filter(HgAppUi.ui_key == '/').one()
157 hgsettings2.ui_value = form_result['paths_root_path']
157 hgsettings2.ui_value = form_result['paths_root_path']
158
158
159
159
160 #HOOKS
160 #HOOKS
161 hgsettings3 = self.sa.query(HgAppUi)\
161 hgsettings3 = self.sa.query(HgAppUi)\
162 .filter(HgAppUi.ui_key == 'changegroup.update').one()
162 .filter(HgAppUi.ui_key == 'changegroup.update').one()
163 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
163 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
164
164
165 hgsettings4 = self.sa.query(HgAppUi)\
165 hgsettings4 = self.sa.query(HgAppUi)\
166 .filter(HgAppUi.ui_key == 'changegroup.repo_size').one()
166 .filter(HgAppUi.ui_key == 'changegroup.repo_size').one()
167 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
167 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
168
168
169
169
170
170
171
171
172 self.sa.add(hgsettings1)
172 self.sa.add(hgsettings1)
173 self.sa.add(hgsettings2)
173 self.sa.add(hgsettings2)
174 self.sa.add(hgsettings3)
174 self.sa.add(hgsettings3)
175 self.sa.add(hgsettings4)
175 self.sa.add(hgsettings4)
176 self.sa.commit()
176 self.sa.commit()
177
177
178 h.flash(_('Updated mercurial settings'),
178 h.flash(_('Updated mercurial settings'),
179 category='success')
179 category='success')
180
180
181 except:
181 except:
182 log.error(traceback.format_exc())
182 log.error(traceback.format_exc())
183 h.flash(_('error occured during updating application settings'),
183 h.flash(_('error occured during updating application settings'),
184 category='error')
184 category='error')
185
185
186 self.sa.rollback()
186 self.sa.rollback()
187
187
188
188
189 except formencode.Invalid as errors:
189 except formencode.Invalid as errors:
190 return htmlfill.render(
190 return htmlfill.render(
191 render('admin/settings/settings.html'),
191 render('admin/settings/settings.html'),
192 defaults=errors.value,
192 defaults=errors.value,
193 errors=errors.error_dict or {},
193 errors=errors.error_dict or {},
194 prefix_error=False,
194 prefix_error=False,
195 encoding="UTF-8")
195 encoding="UTF-8")
196
196
197
197
198
198
199 return redirect(url('admin_settings'))
199 return redirect(url('admin_settings'))
200
200
201 @HasPermissionAllDecorator('hg.admin')
201 @HasPermissionAllDecorator('hg.admin')
202 def delete(self, setting_id):
202 def delete(self, setting_id):
203 """DELETE /admin/settings/setting_id: Delete an existing item"""
203 """DELETE /admin/settings/setting_id: Delete an existing item"""
204 # Forms posted to this method should contain a hidden field:
204 # Forms posted to this method should contain a hidden field:
205 # <input type="hidden" name="_method" value="DELETE" />
205 # <input type="hidden" name="_method" value="DELETE" />
206 # Or using helpers:
206 # Or using helpers:
207 # h.form(url('admin_setting', setting_id=ID),
207 # h.form(url('admin_setting', setting_id=ID),
208 # method='delete')
208 # method='delete')
209 # url('admin_setting', setting_id=ID)
209 # url('admin_setting', setting_id=ID)
210
210
211 @HasPermissionAllDecorator('hg.admin')
211 @HasPermissionAllDecorator('hg.admin')
212 def show(self, setting_id, format='html'):
212 def show(self, setting_id, format='html'):
213 """GET /admin/settings/setting_id: Show a specific item"""
213 """GET /admin/settings/setting_id: Show a specific item"""
214 # url('admin_setting', setting_id=ID)
214 # url('admin_setting', setting_id=ID)
215
215
216 @HasPermissionAllDecorator('hg.admin')
216 @HasPermissionAllDecorator('hg.admin')
217 def edit(self, setting_id, format='html'):
217 def edit(self, setting_id, format='html'):
218 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
218 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
219 # url('admin_edit_setting', setting_id=ID)
219 # url('admin_edit_setting', setting_id=ID)
220
220
221
221
222 def my_account(self):
222 def my_account(self):
223 """
223 """
224 GET /_admin/my_account Displays info about my account
224 GET /_admin/my_account Displays info about my account
225 """
225 """
226 # url('admin_settings_my_account')
226 # url('admin_settings_my_account')
227 c.user = self.sa.query(User).get(c.hg_app_user.user_id)
227 c.user = self.sa.query(User).get(c.hg_app_user.user_id)
228 if c.user.username == 'default':
228 if c.user.username == 'default':
229 h.flash(_("You can't edit this user since it's"
229 h.flash(_("You can't edit this user since it's"
230 " crucial for entire application"), category='warning')
230 " crucial for entire application"), category='warning')
231 return redirect(url('users'))
231 return redirect(url('users'))
232
232
233 defaults = c.user.__dict__
233 defaults = c.user.__dict__
234 return htmlfill.render(
234 return htmlfill.render(
235 render('admin/users/user_edit_my_account.html'),
235 render('admin/users/user_edit_my_account.html'),
236 defaults=defaults,
236 defaults=defaults,
237 encoding="UTF-8",
237 encoding="UTF-8",
238 force_defaults=False
238 force_defaults=False
239 )
239 )
240
240
241 def my_account_update(self):
241 def my_account_update(self):
242 """PUT /_admin/my_account_update: Update an existing item"""
242 """PUT /_admin/my_account_update: Update an existing item"""
243 # Forms posted to this method should contain a hidden field:
243 # Forms posted to this method should contain a hidden field:
244 # <input type="hidden" name="_method" value="PUT" />
244 # <input type="hidden" name="_method" value="PUT" />
245 # Or using helpers:
245 # Or using helpers:
246 # h.form(url('admin_settings_my_account_update'),
246 # h.form(url('admin_settings_my_account_update'),
247 # method='put')
247 # method='put')
248 # url('admin_settings_my_account_update', id=ID)
248 # url('admin_settings_my_account_update', id=ID)
249 user_model = UserModel()
249 user_model = UserModel()
250 uid = c.hg_app_user.user_id
250 uid = c.hg_app_user.user_id
251 _form = UserForm(edit=True, old_data={'user_id':uid})()
251 _form = UserForm(edit=True, old_data={'user_id':uid})()
252 form_result = {}
252 form_result = {}
253 try:
253 try:
254 form_result = _form.to_python(dict(request.POST))
254 form_result = _form.to_python(dict(request.POST))
255 user_model.update_my_account(uid, form_result)
255 user_model.update_my_account(uid, form_result)
256 h.flash(_('Your account was updated succesfully'),
256 h.flash(_('Your account was updated succesfully'),
257 category='success')
257 category='success')
258
258
259 except formencode.Invalid as errors:
259 except formencode.Invalid as errors:
260 #c.user = self.sa.query(User).get(c.hg_app_user.user_id)
260 #c.user = self.sa.query(User).get(c.hg_app_user.user_id)
261 return htmlfill.render(
261 return htmlfill.render(
262 render('admin/users/user_edit_my_account.html'),
262 render('admin/users/user_edit_my_account.html'),
263 defaults=errors.value,
263 defaults=errors.value,
264 errors=errors.error_dict or {},
264 errors=errors.error_dict or {},
265 prefix_error=False,
265 prefix_error=False,
266 encoding="UTF-8")
266 encoding="UTF-8")
267 except Exception:
267 except Exception:
268 log.error(traceback.format_exc())
268 log.error(traceback.format_exc())
269 h.flash(_('error occured during update of user %s') \
269 h.flash(_('error occured during update of user %s') \
270 % form_result.get('username'), category='error')
270 % form_result.get('username'), category='error')
271
271
272 return redirect(url('my_account'))
272 return redirect(url('my_account'))
273
273
274 @HasPermissionAnyDecorator('repository.create', 'hg.admin')
274 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
275 def create_repository(self):
275 def create_repository(self):
276 """GET /_admin/create_repository: Form to create a new item"""
276 """GET /_admin/create_repository: Form to create a new item"""
277 new_repo = request.GET.get('repo', '')
277 new_repo = request.GET.get('repo', '')
278 c.new_repo = h.repo_name_slug(new_repo)
278 c.new_repo = h.repo_name_slug(new_repo)
279
279
280 return render('admin/repos/repo_add_create_repository.html')
280 return render('admin/repos/repo_add_create_repository.html')
281
281
@@ -1,163 +1,162 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # users controller for pylons
3 # users 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 4, 2010
21 Created on April 4, 2010
22 users controller for pylons
22 users controller for pylons
23 @author: marcink
23 @author: marcink
24 """
24 """
25
25
26 from formencode import htmlfill
26 from formencode import htmlfill
27 from pylons import request, session, tmpl_context as c, url
27 from pylons import request, 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.i18n.translation import _
29 from pylons.i18n.translation import _
30 from pylons_app.lib import helpers as h
30 from pylons_app.lib import helpers as h
31 from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator
31 from pylons_app.lib.auth import LoginRequired, HasPermissionAllDecorator
32 from pylons_app.lib.base import BaseController, render
32 from pylons_app.lib.base import BaseController, render
33 from pylons_app.model.db import User, UserLog
33 from pylons_app.model.db import User, UserLog
34 from pylons_app.model.forms import UserForm
34 from pylons_app.model.forms import UserForm
35 from pylons_app.model.user_model import UserModel, DefaultUserException
35 from pylons_app.model.user_model import UserModel, DefaultUserException
36 import formencode
36 import formencode
37 import logging
37 import logging
38 import traceback
38 import traceback
39
39
40
41 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
42
41
43 class UsersController(BaseController):
42 class UsersController(BaseController):
44 """REST Controller styled on the Atom Publishing Protocol"""
43 """REST Controller styled on the Atom Publishing Protocol"""
45 # To properly map this controller, ensure your config/routing.py
44 # To properly map this controller, ensure your config/routing.py
46 # file has a resource setup:
45 # file has a resource setup:
47 # map.resource('user', 'users')
46 # map.resource('user', 'users')
48
47
49 @LoginRequired()
48 @LoginRequired()
50 @HasPermissionAllDecorator('hg.admin')
49 @HasPermissionAllDecorator('hg.admin')
51 def __before__(self):
50 def __before__(self):
52 c.admin_user = session.get('admin_user')
51 c.admin_user = session.get('admin_user')
53 c.admin_username = session.get('admin_username')
52 c.admin_username = session.get('admin_username')
54 super(UsersController, self).__before__()
53 super(UsersController, self).__before__()
55
54
56
55
57 def index(self, format='html'):
56 def index(self, format='html'):
58 """GET /users: All items in the collection"""
57 """GET /users: All items in the collection"""
59 # url('users')
58 # url('users')
60
59
61 c.users_list = self.sa.query(User).all()
60 c.users_list = self.sa.query(User).all()
62 return render('admin/users/users.html')
61 return render('admin/users/users.html')
63
62
64 def create(self):
63 def create(self):
65 """POST /users: Create a new item"""
64 """POST /users: Create a new item"""
66 # url('users')
65 # url('users')
67
66
68 user_model = UserModel()
67 user_model = UserModel()
69 login_form = UserForm()()
68 login_form = UserForm()()
70 try:
69 try:
71 form_result = login_form.to_python(dict(request.POST))
70 form_result = login_form.to_python(dict(request.POST))
72 user_model.create(form_result)
71 user_model.create(form_result)
73 h.flash(_('created user %s') % form_result['username'],
72 h.flash(_('created user %s') % form_result['username'],
74 category='success')
73 category='success')
75 except formencode.Invalid as errors:
74 except formencode.Invalid as errors:
76 return htmlfill.render(
75 return htmlfill.render(
77 render('admin/users/user_add.html'),
76 render('admin/users/user_add.html'),
78 defaults=errors.value,
77 defaults=errors.value,
79 errors=errors.error_dict or {},
78 errors=errors.error_dict or {},
80 prefix_error=False,
79 prefix_error=False,
81 encoding="UTF-8")
80 encoding="UTF-8")
82 except Exception:
81 except Exception:
83 log.error(traceback.format_exc())
82 log.error(traceback.format_exc())
84 h.flash(_('error occured during creation of user %s') \
83 h.flash(_('error occured during creation of user %s') \
85 % request.POST.get('username'), category='error')
84 % request.POST.get('username'), category='error')
86 return redirect(url('users'))
85 return redirect(url('users'))
87
86
88 def new(self, format='html'):
87 def new(self, format='html'):
89 """GET /users/new: Form to create a new item"""
88 """GET /users/new: Form to create a new item"""
90 # url('new_user')
89 # url('new_user')
91 return render('admin/users/user_add.html')
90 return render('admin/users/user_add.html')
92
91
93 def update(self, id):
92 def update(self, id):
94 """PUT /users/id: Update an existing item"""
93 """PUT /users/id: Update an existing item"""
95 # Forms posted to this method should contain a hidden field:
94 # Forms posted to this method should contain a hidden field:
96 # <input type="hidden" name="_method" value="PUT" />
95 # <input type="hidden" name="_method" value="PUT" />
97 # Or using helpers:
96 # Or using helpers:
98 # h.form(url('user', id=ID),
97 # h.form(url('user', id=ID),
99 # method='put')
98 # method='put')
100 # url('user', id=ID)
99 # url('user', id=ID)
101 user_model = UserModel()
100 user_model = UserModel()
102 _form = UserForm(edit=True, old_data={'user_id':id})()
101 _form = UserForm(edit=True, old_data={'user_id':id})()
103 form_result = {}
102 form_result = {}
104 try:
103 try:
105 form_result = _form.to_python(dict(request.POST))
104 form_result = _form.to_python(dict(request.POST))
106 user_model.update(id, form_result)
105 user_model.update(id, form_result)
107 h.flash(_('User updated succesfully'), category='success')
106 h.flash(_('User updated succesfully'), category='success')
108
107
109 except formencode.Invalid as errors:
108 except formencode.Invalid as errors:
110 c.user = user_model.get_user(id)
109 c.user = user_model.get_user(id)
111 return htmlfill.render(
110 return htmlfill.render(
112 render('admin/users/user_edit.html'),
111 render('admin/users/user_edit.html'),
113 defaults=errors.value,
112 defaults=errors.value,
114 errors=errors.error_dict or {},
113 errors=errors.error_dict or {},
115 prefix_error=False,
114 prefix_error=False,
116 encoding="UTF-8")
115 encoding="UTF-8")
117 except Exception:
116 except Exception:
118 log.error(traceback.format_exc())
117 log.error(traceback.format_exc())
119 h.flash(_('error occured during update of user %s') \
118 h.flash(_('error occured during update of user %s') \
120 % form_result.get('username'), category='error')
119 % form_result.get('username'), category='error')
121
120
122 return redirect(url('users'))
121 return redirect(url('users'))
123
122
124 def delete(self, id):
123 def delete(self, id):
125 """DELETE /users/id: Delete an existing item"""
124 """DELETE /users/id: Delete an existing item"""
126 # Forms posted to this method should contain a hidden field:
125 # Forms posted to this method should contain a hidden field:
127 # <input type="hidden" name="_method" value="DELETE" />
126 # <input type="hidden" name="_method" value="DELETE" />
128 # Or using helpers:
127 # Or using helpers:
129 # h.form(url('user', id=ID),
128 # h.form(url('user', id=ID),
130 # method='delete')
129 # method='delete')
131 # url('user', id=ID)
130 # url('user', id=ID)
132 user_model = UserModel()
131 user_model = UserModel()
133 try:
132 try:
134 user_model.delete(id)
133 user_model.delete(id)
135 h.flash(_('sucessfully deleted user'), category='success')
134 h.flash(_('sucessfully deleted user'), category='success')
136 except DefaultUserException as e:
135 except DefaultUserException as e:
137 h.flash(str(e), category='warning')
136 h.flash(str(e), category='warning')
138 except Exception:
137 except Exception:
139 h.flash(_('An error occured during deletion of user'),
138 h.flash(_('An error occured during deletion of user'),
140 category='error')
139 category='error')
141 return redirect(url('users'))
140 return redirect(url('users'))
142
141
143 def show(self, id, format='html'):
142 def show(self, id, format='html'):
144 """GET /users/id: Show a specific item"""
143 """GET /users/id: Show a specific item"""
145 # url('user', id=ID)
144 # url('user', id=ID)
146
145
147
146
148 def edit(self, id, format='html'):
147 def edit(self, id, format='html'):
149 """GET /users/id/edit: Form to edit an existing item"""
148 """GET /users/id/edit: Form to edit an existing item"""
150 # url('edit_user', id=ID)
149 # url('edit_user', id=ID)
151 c.user = self.sa.query(User).get(id)
150 c.user = self.sa.query(User).get(id)
152 if c.user.username == 'default':
151 if c.user.username == 'default':
153 h.flash(_("You can't edit this user since it's"
152 h.flash(_("You can't edit this user since it's"
154 " crucial for entire application"), category='warning')
153 " crucial for entire application"), category='warning')
155 return redirect(url('users'))
154 return redirect(url('users'))
156
155
157 defaults = c.user.__dict__
156 defaults = c.user.__dict__
158 return htmlfill.render(
157 return htmlfill.render(
159 render('admin/users/user_edit.html'),
158 render('admin/users/user_edit.html'),
160 defaults=defaults,
159 defaults=defaults,
161 encoding="UTF-8",
160 encoding="UTF-8",
162 force_defaults=False
161 force_defaults=False
163 )
162 )
@@ -1,88 +1,97 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
21 """
22 Created on April 22, 2010
23 login controller for pylons
24 @author: marcink
25 """
20 from formencode import htmlfill
26 from formencode import htmlfill
21 from pylons import request, response, session, tmpl_context as c, url
27 from pylons import request, response, session, tmpl_context as c, url
22 from pylons.controllers.util import abort, redirect
28 from pylons.controllers.util import abort, redirect
23 from pylons_app.lib.auth import AuthUser
29 from pylons_app.lib.auth import AuthUser, HasPermissionAnyDecorator
24 from pylons_app.lib.base import BaseController, render
30 from pylons_app.lib.base import BaseController, render
25 from pylons_app.model.forms import LoginForm, RegisterForm
31 from pylons_app.model.forms import LoginForm, RegisterForm
26 from pylons_app.model.user_model import UserModel
32 from pylons_app.model.user_model import UserModel
27 import formencode
33 import formencode
28 import logging
34 import logging
29 """
30 Created on April 22, 2010
31 login controller for pylons
32 @author: marcink
33 """
34
35
35 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
36
37
37 class LoginController(BaseController):
38 class LoginController(BaseController):
38
39
39 def __before__(self):
40 def __before__(self):
40 super(LoginController, self).__before__()
41 super(LoginController, self).__before__()
41
42
42 def index(self):
43 def index(self):
43 #redirect if already logged in
44 #redirect if already logged in
44 if c.hg_app_user.is_authenticated:
45 if c.hg_app_user.is_authenticated:
45 return redirect(url('hg_home'))
46 return redirect(url('hg_home'))
46
47
47 if request.POST:
48 if request.POST:
48 #import Login Form validator class
49 #import Login Form validator class
49 login_form = LoginForm()
50 login_form = LoginForm()
50 try:
51 try:
51 c.form_result = login_form.to_python(dict(request.POST))
52 c.form_result = login_form.to_python(dict(request.POST))
52 return redirect(url('hg_home'))
53 return redirect(url('hg_home'))
53
54
54 except formencode.Invalid as errors:
55 except formencode.Invalid as errors:
55 return htmlfill.render(
56 return htmlfill.render(
56 render('/login.html'),
57 render('/login.html'),
57 defaults=errors.value,
58 defaults=errors.value,
58 errors=errors.error_dict or {},
59 errors=errors.error_dict or {},
59 prefix_error=False,
60 prefix_error=False,
60 encoding="UTF-8")
61 encoding="UTF-8")
61
62
62 return render('/login.html')
63 return render('/login.html')
63
64
64
65 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
65 def register(self):
66 def register(self):
67 user_model = UserModel()
68 c.auto_active = False
69 for perm in user_model.get_default().user_perms:
70 if perm.permission.permission_name == 'hg.register.auto_activate':
71 c.auto_active = False
72 break
73
66 if request.POST:
74 if request.POST:
67 user_model = UserModel()
75
68 register_form = RegisterForm()()
76 register_form = RegisterForm()()
69 try:
77 try:
70 form_result = register_form.to_python(dict(request.POST))
78 form_result = register_form.to_python(dict(request.POST))
79 form_result['active'] = c.auto_active
71 user_model.create_registration(form_result)
80 user_model.create_registration(form_result)
72 return redirect(url('login_home'))
81 return redirect(url('login_home'))
73
82
74 except formencode.Invalid as errors:
83 except formencode.Invalid as errors:
75 return htmlfill.render(
84 return htmlfill.render(
76 render('/register.html'),
85 render('/register.html'),
77 defaults=errors.value,
86 defaults=errors.value,
78 errors=errors.error_dict or {},
87 errors=errors.error_dict or {},
79 prefix_error=False,
88 prefix_error=False,
80 encoding="UTF-8")
89 encoding="UTF-8")
81
90
82 return render('/register.html')
91 return render('/register.html')
83
92
84 def logout(self):
93 def logout(self):
85 session['hg_app_user'] = AuthUser()
94 session['hg_app_user'] = AuthUser()
86 session.save()
95 session.save()
87 log.info('Logging out and setting user as Empty')
96 log.info('Logging out and setting user as Empty')
88 redirect(url('hg_home'))
97 redirect(url('hg_home'))
@@ -1,433 +1,451 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 from sqlalchemy.exc import OperationalError
32 from sqlalchemy.exc import OperationalError
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 import bcrypt
34 import bcrypt
34 from decorator import decorator
35 from decorator import decorator
35 import logging
36 import logging
36
37
37 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
38
39
39 def get_crypt_password(password):
40 def get_crypt_password(password):
40 """Cryptographic function used for password hashing based on sha1
41 """Cryptographic function used for password hashing based on sha1
41 @param password: password to hash
42 @param password: password to hash
42 """
43 """
43 return bcrypt.hashpw(password, bcrypt.gensalt(10))
44 return bcrypt.hashpw(password, bcrypt.gensalt(10))
44
45
45 def check_password(password, hashed):
46 def check_password(password, hashed):
46 return bcrypt.hashpw(password, hashed) == hashed
47 return bcrypt.hashpw(password, hashed) == hashed
47
48
48 @cache_region('super_short_term', 'cached_user')
49 @cache_region('super_short_term', 'cached_user')
49 def get_user_cached(username):
50 def get_user_cached(username):
50 sa = meta.Session
51 sa = meta.Session
51 try:
52 try:
52 user = sa.query(User).filter(User.username == username).one()
53 user = sa.query(User).filter(User.username == username).one()
53 finally:
54 finally:
54 meta.Session.remove()
55 meta.Session.remove()
55 return user
56 return user
56
57
57 def authfunc(environ, username, password):
58 def authfunc(environ, username, password):
58 try:
59 try:
59 user = get_user_cached(username)
60 user = get_user_cached(username)
60 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
61 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
61 log.error(e)
62 log.error(e)
62 user = None
63 user = None
63
64
64 if user:
65 if user:
65 if user.active:
66 if user.active:
66 if user.username == username and check_password(password, user.password):
67 if user.username == username and check_password(password, user.password):
67 log.info('user %s authenticated correctly', username)
68 log.info('user %s authenticated correctly', username)
68 return True
69 return True
69 else:
70 else:
70 log.error('user %s is disabled', username)
71 log.error('user %s is disabled', username)
71
72
72 return False
73 return False
73
74
74 class AuthUser(object):
75 class AuthUser(object):
75 """
76 """
76 A simple object that handles a mercurial username for authentication
77 A simple object that handles a mercurial username for authentication
77 """
78 """
78 def __init__(self):
79 def __init__(self):
79 self.username = 'None'
80 self.username = 'None'
80 self.name = ''
81 self.name = ''
81 self.lastname = ''
82 self.lastname = ''
82 self.email = ''
83 self.email = ''
83 self.user_id = None
84 self.user_id = None
84 self.is_authenticated = False
85 self.is_authenticated = False
85 self.is_admin = False
86 self.is_admin = False
86 self.permissions = {}
87 self.permissions = {}
87
88
88
89
89 def set_available_permissions(config):
90 def set_available_permissions(config):
90 """
91 """
91 This function will propagate pylons globals with all available defined
92 This function will propagate pylons globals with all available defined
92 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
93 permissions since adding a new permission also requires application restart
94 permissions since adding a new permission also requires application restart
94 ie. to decorate new views with the newly created permission
95 ie. to decorate new views with the newly created permission
95 @param config:
96 @param config:
96 """
97 """
97 log.info('getting information about all available permissions')
98 log.info('getting information about all available permissions')
98 try:
99 try:
99 sa = meta.Session
100 sa = meta.Session
100 all_perms = sa.query(Permission).all()
101 all_perms = sa.query(Permission).all()
101 finally:
102 finally:
102 meta.Session.remove()
103 meta.Session.remove()
103
104
104 config['available_permissions'] = [x.permission_name for x in all_perms]
105 config['available_permissions'] = [x.permission_name for x in all_perms]
105
106
106 def set_base_path(config):
107 def set_base_path(config):
107 config['base_path'] = config['pylons.app_globals'].base_path
108 config['base_path'] = config['pylons.app_globals'].base_path
108
109
109 def fill_data(user):
110 def fill_data(user):
110 """
111 """
111 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
112 in database
113 in database
113 @param user:
114 @param user:
114 """
115 """
115 sa = meta.Session
116 sa = meta.Session
116 dbuser = sa.query(User).get(user.user_id)
117 dbuser = sa.query(User).get(user.user_id)
117 if dbuser:
118 if dbuser:
118 user.username = dbuser.username
119 user.username = dbuser.username
119 user.is_admin = dbuser.admin
120 user.is_admin = dbuser.admin
120 user.name = dbuser.name
121 user.name = dbuser.name
121 user.lastname = dbuser.lastname
122 user.lastname = dbuser.lastname
122 user.email = dbuser.email
123 user.email = dbuser.email
123 else:
124 else:
124 user.is_authenticated = False
125 user.is_authenticated = False
125 meta.Session.remove()
126 meta.Session.remove()
126 return user
127 return user
127
128
128 def fill_perms(user):
129 def fill_perms(user):
129 """
130 """
130 Fills user permission attribute with permissions taken from database
131 Fills user permission attribute with permissions taken from database
131 @param user:
132 @param user:
132 """
133 """
133
134
134 sa = meta.Session
135 sa = meta.Session
135 user.permissions['repositories'] = {}
136 user.permissions['repositories'] = {}
136 user.permissions['global'] = set()
137 user.permissions['global'] = set()
137
138
138 #first fetch default permissions
139 #===========================================================================
139 default_perms = sa.query(RepoToPerm, Repository, Permission)\
140 # fetch default permissions
141 #===========================================================================
142 default_perms = sa.query(RepoToPerm, UserToPerm, Repository, Permission)\
143 .outerjoin((UserToPerm, RepoToPerm.user_id == UserToPerm.user_id))\
140 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
144 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
141 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
145 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
142 .filter(RepoToPerm.user_id == sa.query(User).filter(User.username ==
146 .filter(RepoToPerm.user_id == sa.query(User).filter(User.username ==
143 'default').one().user_id).all()
147 'default').one().user_id).all()
144
148
145 if user.is_admin:
149 if user.is_admin:
150 #=======================================================================
151 # #admin have all rights set to admin
152 #=======================================================================
146 user.permissions['global'].add('hg.admin')
153 user.permissions['global'].add('hg.admin')
147 #admin have all rights set to admin
154
148 for perm in default_perms:
155 for perm in default_perms:
149 p = 'repository.admin'
156 p = 'repository.admin'
150 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
157 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
151
158
152 else:
159 else:
153 user.permissions['global'].add('repository.create')
160 #=======================================================================
154 user.permissions['global'].add('hg.register')
161 # set default permissions
162 #=======================================================================
155
163
164 #default global
165 for perm in default_perms:
166 user.permissions['global'].add(perm.UserToPerm.permission.permission_name)
167
168 # user.permissions['global'].add('hg.create.repository')
169 # user.permissions['global'].add('hg.register')
170
171 #default repositories
156 for perm in default_perms:
172 for perm in default_perms:
157 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:
158 #disable defaults for private repos,
174 #disable defaults for private repos,
159 p = 'repository.none'
175 p = 'repository.none'
160 elif perm.Repository.user_id == user.user_id:
176 elif perm.Repository.user_id == user.user_id:
161 #set admin if owner
177 #set admin if owner
162 p = 'repository.admin'
178 p = 'repository.admin'
163 else:
179 else:
164 p = perm.Permission.permission_name
180 p = perm.Permission.permission_name
165
181
166 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
182 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
167
183
168
184 #=======================================================================
169 user_perms = sa.query(RepoToPerm, Permission, Repository)\
185 # #overwrite default with user permissions if any
186 #=======================================================================
187 user_perms = sa.query(RepoToPerm, UserToPerm, Permission, Repository)\
188 .outerjoin((UserToPerm, RepoToPerm.user_id == UserToPerm.user_id))\
170 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
189 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
171 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
190 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
172 .filter(RepoToPerm.user_id == user.user_id).all()
191 .filter(RepoToPerm.user_id == user.user_id).all()
173 #overwrite userpermissions with defaults
192
174 for perm in user_perms:
193 for perm in user_perms:
175 #set write if owner
194 if perm.Repository.user_id == user.user_id:#set admin if owner
176 if perm.Repository.user_id == user.user_id:
195 p = 'repository.admin'
177 p = 'repository.write'
178 else:
196 else:
179 p = perm.Permission.permission_name
197 p = perm.Permission.permission_name
180 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
198 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
181 meta.Session.remove()
199 meta.Session.remove()
182 return user
200 return user
183
201
184 def get_user(session):
202 def get_user(session):
185 """
203 """
186 Gets user from session, and wraps permissions into user
204 Gets user from session, and wraps permissions into user
187 @param session:
205 @param session:
188 """
206 """
189 user = session.get('hg_app_user', AuthUser())
207 user = session.get('hg_app_user', AuthUser())
190 if user.is_authenticated:
208 if user.is_authenticated:
191 user = fill_data(user)
209 user = fill_data(user)
192 user = fill_perms(user)
210 user = fill_perms(user)
193 session['hg_app_user'] = user
211 session['hg_app_user'] = user
194 session.save()
212 session.save()
195 return user
213 return user
196
214
197 #===============================================================================
215 #===============================================================================
198 # CHECK DECORATORS
216 # CHECK DECORATORS
199 #===============================================================================
217 #===============================================================================
200 class LoginRequired(object):
218 class LoginRequired(object):
201 """Must be logged in to execute this function else redirect to login page"""
219 """Must be logged in to execute this function else redirect to login page"""
202
220
203 def __call__(self, func):
221 def __call__(self, func):
204 return decorator(self.__wrapper, func)
222 return decorator(self.__wrapper, func)
205
223
206 def __wrapper(self, func, *fargs, **fkwargs):
224 def __wrapper(self, func, *fargs, **fkwargs):
207 user = session.get('hg_app_user', AuthUser())
225 user = session.get('hg_app_user', AuthUser())
208 log.debug('Checking login required for user:%s', user.username)
226 log.debug('Checking login required for user:%s', user.username)
209 if user.is_authenticated:
227 if user.is_authenticated:
210 log.debug('user %s is authenticated', user.username)
228 log.debug('user %s is authenticated', user.username)
211 return func(*fargs, **fkwargs)
229 return func(*fargs, **fkwargs)
212 else:
230 else:
213 log.warn('user %s not authenticated', user.username)
231 log.warn('user %s not authenticated', user.username)
214 log.debug('redirecting to login page')
232 log.debug('redirecting to login page')
215 return redirect(url('login_home'))
233 return redirect(url('login_home'))
216
234
217 class PermsDecorator(object):
235 class PermsDecorator(object):
218 """Base class for decorators"""
236 """Base class for decorators"""
219
237
220 def __init__(self, *required_perms):
238 def __init__(self, *required_perms):
221 available_perms = config['available_permissions']
239 available_perms = config['available_permissions']
222 for perm in required_perms:
240 for perm in required_perms:
223 if perm not in available_perms:
241 if perm not in available_perms:
224 raise Exception("'%s' permission is not defined" % perm)
242 raise Exception("'%s' permission is not defined" % perm)
225 self.required_perms = set(required_perms)
243 self.required_perms = set(required_perms)
226 self.user_perms = None
244 self.user_perms = None
227
245
228 def __call__(self, func):
246 def __call__(self, func):
229 return decorator(self.__wrapper, func)
247 return decorator(self.__wrapper, func)
230
248
231
249
232 def __wrapper(self, func, *fargs, **fkwargs):
250 def __wrapper(self, func, *fargs, **fkwargs):
233 # _wrapper.__name__ = func.__name__
251 # _wrapper.__name__ = func.__name__
234 # _wrapper.__dict__.update(func.__dict__)
252 # _wrapper.__dict__.update(func.__dict__)
235 # _wrapper.__doc__ = func.__doc__
253 # _wrapper.__doc__ = func.__doc__
236
254
237 self.user_perms = session.get('hg_app_user', AuthUser()).permissions
255 self.user_perms = session.get('hg_app_user', AuthUser()).permissions
238 log.debug('checking %s permissions %s for %s',
256 log.debug('checking %s permissions %s for %s',
239 self.__class__.__name__, self.required_perms, func.__name__)
257 self.__class__.__name__, self.required_perms, func.__name__)
240
258
241 if self.check_permissions():
259 if self.check_permissions():
242 log.debug('Permission granted for %s', func.__name__)
260 log.debug('Permission granted for %s', func.__name__)
243
261
244 return func(*fargs, **fkwargs)
262 return func(*fargs, **fkwargs)
245
263
246 else:
264 else:
247 log.warning('Permission denied for %s', func.__name__)
265 log.warning('Permission denied for %s', func.__name__)
248 #redirect with forbidden ret code
266 #redirect with forbidden ret code
249 return abort(403)
267 return abort(403)
250
268
251
269
252
270
253 def check_permissions(self):
271 def check_permissions(self):
254 """Dummy function for overriding"""
272 """Dummy function for overriding"""
255 raise Exception('You have to write this function in child class')
273 raise Exception('You have to write this function in child class')
256
274
257 class HasPermissionAllDecorator(PermsDecorator):
275 class HasPermissionAllDecorator(PermsDecorator):
258 """Checks for access permission for all given predicates. All of them
276 """Checks for access permission for all given predicates. All of them
259 have to be meet in order to fulfill the request
277 have to be meet in order to fulfill the request
260 """
278 """
261
279
262 def check_permissions(self):
280 def check_permissions(self):
263 if self.required_perms.issubset(self.user_perms.get('global')):
281 if self.required_perms.issubset(self.user_perms.get('global')):
264 return True
282 return True
265 return False
283 return False
266
284
267
285
268 class HasPermissionAnyDecorator(PermsDecorator):
286 class HasPermissionAnyDecorator(PermsDecorator):
269 """Checks for access permission for any of given predicates. In order to
287 """Checks for access permission for any of given predicates. In order to
270 fulfill the request any of predicates must be meet
288 fulfill the request any of predicates must be meet
271 """
289 """
272
290
273 def check_permissions(self):
291 def check_permissions(self):
274 if self.required_perms.intersection(self.user_perms.get('global')):
292 if self.required_perms.intersection(self.user_perms.get('global')):
275 return True
293 return True
276 return False
294 return False
277
295
278 class HasRepoPermissionAllDecorator(PermsDecorator):
296 class HasRepoPermissionAllDecorator(PermsDecorator):
279 """Checks for access permission for all given predicates for specific
297 """Checks for access permission for all given predicates for specific
280 repository. All of them have to be meet in order to fulfill the request
298 repository. All of them have to be meet in order to fulfill the request
281 """
299 """
282
300
283 def check_permissions(self):
301 def check_permissions(self):
284 repo_name = get_repo_slug(request)
302 repo_name = get_repo_slug(request)
285 try:
303 try:
286 user_perms = set([self.user_perms['repositories'][repo_name]])
304 user_perms = set([self.user_perms['repositories'][repo_name]])
287 except KeyError:
305 except KeyError:
288 return False
306 return False
289 if self.required_perms.issubset(user_perms):
307 if self.required_perms.issubset(user_perms):
290 return True
308 return True
291 return False
309 return False
292
310
293
311
294 class HasRepoPermissionAnyDecorator(PermsDecorator):
312 class HasRepoPermissionAnyDecorator(PermsDecorator):
295 """Checks for access permission for any of given predicates for specific
313 """Checks for access permission for any of given predicates for specific
296 repository. In order to fulfill the request any of predicates must be meet
314 repository. In order to fulfill the request any of predicates must be meet
297 """
315 """
298
316
299 def check_permissions(self):
317 def check_permissions(self):
300 repo_name = get_repo_slug(request)
318 repo_name = get_repo_slug(request)
301
319
302 try:
320 try:
303 user_perms = set([self.user_perms['repositories'][repo_name]])
321 user_perms = set([self.user_perms['repositories'][repo_name]])
304 except KeyError:
322 except KeyError:
305 return False
323 return False
306 if self.required_perms.intersection(user_perms):
324 if self.required_perms.intersection(user_perms):
307 return True
325 return True
308 return False
326 return False
309 #===============================================================================
327 #===============================================================================
310 # CHECK FUNCTIONS
328 # CHECK FUNCTIONS
311 #===============================================================================
329 #===============================================================================
312
330
313 class PermsFunction(object):
331 class PermsFunction(object):
314 """Base function for other check functions"""
332 """Base function for other check functions"""
315
333
316 def __init__(self, *perms):
334 def __init__(self, *perms):
317 available_perms = config['available_permissions']
335 available_perms = config['available_permissions']
318
336
319 for perm in perms:
337 for perm in perms:
320 if perm not in available_perms:
338 if perm not in available_perms:
321 raise Exception("'%s' permission in not defined" % perm)
339 raise Exception("'%s' permission in not defined" % perm)
322 self.required_perms = set(perms)
340 self.required_perms = set(perms)
323 self.user_perms = None
341 self.user_perms = None
324 self.granted_for = ''
342 self.granted_for = ''
325 self.repo_name = None
343 self.repo_name = None
326
344
327 def __call__(self, check_Location=''):
345 def __call__(self, check_Location=''):
328 user = session.get('hg_app_user', False)
346 user = session.get('hg_app_user', False)
329 if not user:
347 if not user:
330 return False
348 return False
331 self.user_perms = user.permissions
349 self.user_perms = user.permissions
332 self.granted_for = user.username
350 self.granted_for = user.username
333 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
351 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
334
352
335 if self.check_permissions():
353 if self.check_permissions():
336 log.debug('Permission granted for %s @%s', self.granted_for,
354 log.debug('Permission granted for %s @%s', self.granted_for,
337 check_Location)
355 check_Location)
338 return True
356 return True
339
357
340 else:
358 else:
341 log.warning('Permission denied for %s @%s', self.granted_for,
359 log.warning('Permission denied for %s @%s', self.granted_for,
342 check_Location)
360 check_Location)
343 return False
361 return False
344
362
345 def check_permissions(self):
363 def check_permissions(self):
346 """Dummy function for overriding"""
364 """Dummy function for overriding"""
347 raise Exception('You have to write this function in child class')
365 raise Exception('You have to write this function in child class')
348
366
349 class HasPermissionAll(PermsFunction):
367 class HasPermissionAll(PermsFunction):
350 def check_permissions(self):
368 def check_permissions(self):
351 if self.required_perms.issubset(self.user_perms.get('global')):
369 if self.required_perms.issubset(self.user_perms.get('global')):
352 return True
370 return True
353 return False
371 return False
354
372
355 class HasPermissionAny(PermsFunction):
373 class HasPermissionAny(PermsFunction):
356 def check_permissions(self):
374 def check_permissions(self):
357 if self.required_perms.intersection(self.user_perms.get('global')):
375 if self.required_perms.intersection(self.user_perms.get('global')):
358 return True
376 return True
359 return False
377 return False
360
378
361 class HasRepoPermissionAll(PermsFunction):
379 class HasRepoPermissionAll(PermsFunction):
362
380
363 def __call__(self, repo_name=None, check_Location=''):
381 def __call__(self, repo_name=None, check_Location=''):
364 self.repo_name = repo_name
382 self.repo_name = repo_name
365 return super(HasRepoPermissionAll, self).__call__(check_Location)
383 return super(HasRepoPermissionAll, self).__call__(check_Location)
366
384
367 def check_permissions(self):
385 def check_permissions(self):
368 if not self.repo_name:
386 if not self.repo_name:
369 self.repo_name = get_repo_slug(request)
387 self.repo_name = get_repo_slug(request)
370
388
371 try:
389 try:
372 self.user_perms = set([self.user_perms['repositories']\
390 self.user_perms = set([self.user_perms['repositories']\
373 [self.repo_name]])
391 [self.repo_name]])
374 except KeyError:
392 except KeyError:
375 return False
393 return False
376 self.granted_for = self.repo_name
394 self.granted_for = self.repo_name
377 if self.required_perms.issubset(self.user_perms):
395 if self.required_perms.issubset(self.user_perms):
378 return True
396 return True
379 return False
397 return False
380
398
381 class HasRepoPermissionAny(PermsFunction):
399 class HasRepoPermissionAny(PermsFunction):
382
400
383 def __call__(self, repo_name=None, check_Location=''):
401 def __call__(self, repo_name=None, check_Location=''):
384 self.repo_name = repo_name
402 self.repo_name = repo_name
385 return super(HasRepoPermissionAny, self).__call__(check_Location)
403 return super(HasRepoPermissionAny, self).__call__(check_Location)
386
404
387 def check_permissions(self):
405 def check_permissions(self):
388 if not self.repo_name:
406 if not self.repo_name:
389 self.repo_name = get_repo_slug(request)
407 self.repo_name = get_repo_slug(request)
390
408
391 try:
409 try:
392 self.user_perms = set([self.user_perms['repositories']\
410 self.user_perms = set([self.user_perms['repositories']\
393 [self.repo_name]])
411 [self.repo_name]])
394 except KeyError:
412 except KeyError:
395 return False
413 return False
396 self.granted_for = self.repo_name
414 self.granted_for = self.repo_name
397 if self.required_perms.intersection(self.user_perms):
415 if self.required_perms.intersection(self.user_perms):
398 return True
416 return True
399 return False
417 return False
400
418
401 #===============================================================================
419 #===============================================================================
402 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
420 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
403 #===============================================================================
421 #===============================================================================
404
422
405 class HasPermissionAnyMiddleware(object):
423 class HasPermissionAnyMiddleware(object):
406 def __init__(self, *perms):
424 def __init__(self, *perms):
407 self.required_perms = set(perms)
425 self.required_perms = set(perms)
408
426
409 def __call__(self, user, repo_name):
427 def __call__(self, user, repo_name):
410 usr = AuthUser()
428 usr = AuthUser()
411 usr.user_id = user.user_id
429 usr.user_id = user.user_id
412 usr.username = user.username
430 usr.username = user.username
413 usr.is_admin = user.admin
431 usr.is_admin = user.admin
414
432
415 try:
433 try:
416 self.user_perms = set([fill_perms(usr)\
434 self.user_perms = set([fill_perms(usr)\
417 .permissions['repositories'][repo_name]])
435 .permissions['repositories'][repo_name]])
418 except:
436 except:
419 self.user_perms = set()
437 self.user_perms = set()
420 self.granted_for = ''
438 self.granted_for = ''
421 self.username = user.username
439 self.username = user.username
422 self.repo_name = repo_name
440 self.repo_name = repo_name
423 return self.check_permissions()
441 return self.check_permissions()
424
442
425 def check_permissions(self):
443 def check_permissions(self):
426 log.debug('checking mercurial protocol '
444 log.debug('checking mercurial protocol '
427 'permissions for user:%s repository:%s',
445 'permissions for user:%s repository:%s',
428 self.username, self.repo_name)
446 self.username, self.repo_name)
429 if self.required_perms.intersection(self.user_perms):
447 if self.required_perms.intersection(self.user_perms):
430 log.debug('permission granted')
448 log.debug('permission granted')
431 return True
449 return True
432 log.debug('permission denied')
450 log.debug('permission denied')
433 return False
451 return False
@@ -1,205 +1,244 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # database managment for hg app
3 # database managment for hg app
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 10, 2010
22 Created on April 10, 2010
23 database managment and creation for hg app
23 database managment and creation for hg app
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26
27 from os.path import dirname as dn, join as jn
27 from os.path import dirname as dn, join as jn
28 import os
28 import os
29 import sys
29 import sys
30 import uuid
30 import uuid
31 ROOT = dn(dn(dn(os.path.realpath(__file__))))
31 ROOT = dn(dn(dn(os.path.realpath(__file__))))
32 sys.path.append(ROOT)
32 sys.path.append(ROOT)
33
33
34 from pylons_app.lib.auth import get_crypt_password
34 from pylons_app.lib.auth import get_crypt_password
35 from pylons_app.lib.utils import ask_ok
35 from pylons_app.lib.utils import ask_ok
36 from pylons_app.model import init_model
36 from pylons_app.model import init_model
37 from pylons_app.model.db import User, Permission, HgAppUi, HgAppSettings
37 from pylons_app.model.db import User, Permission, HgAppUi, HgAppSettings, \
38 UserToPerm
38 from pylons_app.model import meta
39 from pylons_app.model import meta
39 from sqlalchemy.engine import create_engine
40 from sqlalchemy.engine import create_engine
40 import logging
41 import logging
41
42
42 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
43
44
44 class DbManage(object):
45 class DbManage(object):
45 def __init__(self, log_sql):
46 def __init__(self, log_sql):
46 self.dbname = 'hg_app.db'
47 self.dbname = 'hg_app.db'
47 dburi = 'sqlite:////%s' % jn(ROOT, self.dbname)
48 dburi = 'sqlite:////%s' % jn(ROOT, self.dbname)
48 engine = create_engine(dburi, echo=log_sql)
49 engine = create_engine(dburi, echo=log_sql)
49 init_model(engine)
50 init_model(engine)
50 self.sa = meta.Session
51 self.sa = meta.Session
51 self.db_exists = False
52 self.db_exists = False
52
53
53 def check_for_db(self, override):
54 def check_for_db(self, override):
54 log.info('checking for exisiting db')
55 log.info('checking for exisiting db')
55 if os.path.isfile(jn(ROOT, self.dbname)):
56 if os.path.isfile(jn(ROOT, self.dbname)):
56 self.db_exists = True
57 self.db_exists = True
57 log.info('database exisist')
58 log.info('database exisist')
58 if not override:
59 if not override:
59 raise Exception('database already exists')
60 raise Exception('database already exists')
60
61
61 def create_tables(self, override=False):
62 def create_tables(self, override=False):
62 """
63 """
63 Create a auth database
64 Create a auth database
64 """
65 """
65 self.check_for_db(override)
66 self.check_for_db(override)
66 if override:
67 if override:
67 log.info("database exisist and it's going to be destroyed")
68 log.info("database exisist and it's going to be destroyed")
68 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
69 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
69 if not destroy:
70 if not destroy:
70 sys.exit()
71 sys.exit()
71 if self.db_exists and destroy:
72 if self.db_exists and destroy:
72 os.remove(jn(ROOT, self.dbname))
73 os.remove(jn(ROOT, self.dbname))
73 checkfirst = not override
74 checkfirst = not override
74 meta.Base.metadata.create_all(checkfirst=checkfirst)
75 meta.Base.metadata.create_all(checkfirst=checkfirst)
75 log.info('Created tables for %s', self.dbname)
76 log.info('Created tables for %s', self.dbname)
76
77
77 def admin_prompt(self):
78 def admin_prompt(self):
78 import getpass
79 import getpass
79 username = raw_input('Specify admin username:')
80 username = raw_input('Specify admin username:')
80 password = getpass.getpass('Specify admin password:')
81 password = getpass.getpass('Specify admin password:')
81 self.create_user(username, password, True)
82 self.create_user(username, password, True)
82
83
83 def config_prompt(self):
84 def config_prompt(self):
84 log.info('Setting up repositories config')
85 log.info('Setting up repositories config')
85
86
86 path = raw_input('Specify valid full path to your repositories'
87 path = raw_input('Specify valid full path to your repositories'
87 ' you can change this later in application settings:')
88 ' you can change this later in application settings:')
88
89
89 if not os.path.isdir(path):
90 if not os.path.isdir(path):
90 log.error('You entered wrong path')
91 log.error('You entered wrong path')
91 sys.exit()
92 sys.exit()
92
93
93 hooks1 = HgAppUi()
94 hooks1 = HgAppUi()
94 hooks1.ui_section = 'hooks'
95 hooks1.ui_section = 'hooks'
95 hooks1.ui_key = 'changegroup.update'
96 hooks1.ui_key = 'changegroup.update'
96 hooks1.ui_value = 'hg update >&2'
97 hooks1.ui_value = 'hg update >&2'
97
98
98 hooks2 = HgAppUi()
99 hooks2 = HgAppUi()
99 hooks2.ui_section = 'hooks'
100 hooks2.ui_section = 'hooks'
100 hooks2.ui_key = 'changegroup.repo_size'
101 hooks2.ui_key = 'changegroup.repo_size'
101 hooks2.ui_value = 'python:pylons_app.lib.hooks.repo_size'
102 hooks2.ui_value = 'python:pylons_app.lib.hooks.repo_size'
102
103
103 web1 = HgAppUi()
104 web1 = HgAppUi()
104 web1.ui_section = 'web'
105 web1.ui_section = 'web'
105 web1.ui_key = 'push_ssl'
106 web1.ui_key = 'push_ssl'
106 web1.ui_value = 'false'
107 web1.ui_value = 'false'
107
108
108 web2 = HgAppUi()
109 web2 = HgAppUi()
109 web2.ui_section = 'web'
110 web2.ui_section = 'web'
110 web2.ui_key = 'allow_archive'
111 web2.ui_key = 'allow_archive'
111 web2.ui_value = 'gz zip bz2'
112 web2.ui_value = 'gz zip bz2'
112
113
113 web3 = HgAppUi()
114 web3 = HgAppUi()
114 web3.ui_section = 'web'
115 web3.ui_section = 'web'
115 web3.ui_key = 'allow_push'
116 web3.ui_key = 'allow_push'
116 web3.ui_value = '*'
117 web3.ui_value = '*'
117
118
118 web4 = HgAppUi()
119 web4 = HgAppUi()
119 web4.ui_section = 'web'
120 web4.ui_section = 'web'
120 web4.ui_key = 'baseurl'
121 web4.ui_key = 'baseurl'
121 web4.ui_value = '/'
122 web4.ui_value = '/'
122
123
123 paths = HgAppUi()
124 paths = HgAppUi()
124 paths.ui_section = 'paths'
125 paths.ui_section = 'paths'
125 paths.ui_key = '/'
126 paths.ui_key = '/'
126 paths.ui_value = os.path.join(path, '*')
127 paths.ui_value = os.path.join(path, '*')
127
128
128
129
129 hgsettings1 = HgAppSettings()
130 hgsettings1 = HgAppSettings()
130
131
131 hgsettings1.app_settings_name = 'realm'
132 hgsettings1.app_settings_name = 'realm'
132 hgsettings1.app_settings_value = 'hg-app authentication'
133 hgsettings1.app_settings_value = 'hg-app authentication'
133
134
134 hgsettings2 = HgAppSettings()
135 hgsettings2 = HgAppSettings()
135 hgsettings2.app_settings_name = 'title'
136 hgsettings2.app_settings_name = 'title'
136 hgsettings2.app_settings_value = 'hg-app'
137 hgsettings2.app_settings_value = 'hg-app'
137
138
138 try:
139 try:
139 self.sa.add(hooks1)
140 self.sa.add(hooks1)
140 self.sa.add(hooks2)
141 self.sa.add(hooks2)
141 self.sa.add(web1)
142 self.sa.add(web1)
142 self.sa.add(web2)
143 self.sa.add(web2)
143 self.sa.add(web3)
144 self.sa.add(web3)
144 self.sa.add(web4)
145 self.sa.add(web4)
145 self.sa.add(paths)
146 self.sa.add(paths)
146 self.sa.add(hgsettings1)
147 self.sa.add(hgsettings1)
147 self.sa.add(hgsettings2)
148 self.sa.add(hgsettings2)
148 self.sa.commit()
149 self.sa.commit()
149 except:
150 except:
150 self.sa.rollback()
151 self.sa.rollback()
151 raise
152 raise
152 log.info('created ui config')
153 log.info('created ui config')
153
154
154 def create_user(self, username, password, admin=False):
155 def create_user(self, username, password, admin=False):
155
156
156 log.info('creating default user')
157 log.info('creating default user')
157 #create default user for handling default permissions.
158 #create default user for handling default permissions.
158 def_user = User()
159 def_user = User()
159 def_user.username = 'default'
160 def_user.username = 'default'
160 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
161 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
161 def_user.name = 'default'
162 def_user.name = 'default'
162 def_user.lastname = 'default'
163 def_user.lastname = 'default'
163 def_user.email = 'default@default.com'
164 def_user.email = 'default@default.com'
164 def_user.admin = False
165 def_user.admin = False
165 def_user.active = False
166 def_user.active = False
166
167
167 log.info('creating administrator user %s', username)
168 log.info('creating administrator user %s', username)
168 new_user = User()
169 new_user = User()
169 new_user.username = username
170 new_user.username = username
170 new_user.password = get_crypt_password(password)
171 new_user.password = get_crypt_password(password)
171 new_user.name = 'Hg'
172 new_user.name = 'Hg'
172 new_user.lastname = 'Admin'
173 new_user.lastname = 'Admin'
173 new_user.email = 'admin@localhost'
174 new_user.email = 'admin@localhost'
174 new_user.admin = admin
175 new_user.admin = admin
175 new_user.active = True
176 new_user.active = True
176
177
177 try:
178 try:
178 self.sa.add(def_user)
179 self.sa.add(def_user)
179 self.sa.add(new_user)
180 self.sa.add(new_user)
180 self.sa.commit()
181 self.sa.commit()
181 except:
182 except:
182 self.sa.rollback()
183 self.sa.rollback()
183 raise
184 raise
184
185
185 def create_permissions(self):
186 def create_permissions(self):
186 #module.(access|create|change|delete)_[name]
187 #module.(access|create|change|delete)_[name]
187 #module.(read|write|owner)
188 #module.(read|write|owner)
188 perms = [('repository.none', 'Repository no access'),
189 perms = [('repository.none', 'Repository no access'),
189 ('repository.read', 'Repository read access'),
190 ('repository.read', 'Repository read access'),
190 ('repository.write', 'Repository write access'),
191 ('repository.write', 'Repository write access'),
191 ('repository.admin', 'Repository admin access'),
192 ('repository.admin', 'Repository admin access'),
192 ('repository.create', 'Repository create'),
193 ('hg.admin', 'Hg Administrator'),
193 ('hg.admin', 'Hg Administrator'),
194 ('hg.create.repository', 'Repository create'),
195 ('hg.create.none', 'Repository creation disabled'),
196 ('hg.register.none', 'Register disabled'),
197 ('hg.register.manual_activate', 'Register new user with hg-app without manual activation'),
198 ('hg.register.auto_activate', 'Register new user with hg-app without auto activation'),
194 ]
199 ]
195
200
196 for p in perms:
201 for p in perms:
197 new_perm = Permission()
202 new_perm = Permission()
198 new_perm.permission_name = p[0]
203 new_perm.permission_name = p[0]
199 new_perm.permission_longname = p[1]
204 new_perm.permission_longname = p[1]
200 try:
205 try:
201 self.sa.add(new_perm)
206 self.sa.add(new_perm)
202 self.sa.commit()
207 self.sa.commit()
203 except:
208 except:
204 self.sa.rollback()
209 self.sa.rollback()
205 raise
210 raise
211
212 def populate_default_permissions(self):
213 log.info('creating default user permissions')
214
215 default_user = self.sa.query(User)\
216 .filter(User.username == 'default').scalar()
217
218 reg_perm = UserToPerm()
219 reg_perm.user = default_user
220 reg_perm.permission = self.sa.query(Permission)\
221 .filter(Permission.permission_name == 'hg.register.manual_activate')\
222 .scalar()
223
224 create_repo_perm = UserToPerm()
225 create_repo_perm.user = default_user
226 create_repo_perm.permission = self.sa.query(Permission)\
227 .filter(Permission.permission_name == 'hg.create.repository')\
228 .scalar()
229
230 default_repo_perm = UserToPerm()
231 default_repo_perm.user = default_user
232 default_repo_perm.permission = self.sa.query(Permission)\
233 .filter(Permission.permission_name == 'repository.read')\
234 .scalar()
235
236 try:
237 self.sa.add(reg_perm)
238 self.sa.add(create_repo_perm)
239 self.sa.add(default_repo_perm)
240 self.sa.commit()
241 except:
242 self.sa.rollback()
243 raise
244
@@ -1,103 +1,107 b''
1 from pylons_app.model.meta import Base
1 from pylons_app.model.meta import Base
2 from sqlalchemy.orm import relation, backref
2 from sqlalchemy.orm import relation, backref
3 from sqlalchemy import *
3 from sqlalchemy import *
4 from vcs.utils.lazy import LazyProperty
4 from vcs.utils.lazy import LazyProperty
5
5
6 class HgAppSettings(Base):
6 class HgAppSettings(Base):
7 __tablename__ = 'hg_app_settings'
7 __tablename__ = 'hg_app_settings'
8 __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True})
8 __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)
9 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)
10 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)
11 app_settings_value = Column("app_settings_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
12
12
13 class HgAppUi(Base):
13 class HgAppUi(Base):
14 __tablename__ = 'hg_app_ui'
14 __tablename__ = 'hg_app_ui'
15 __table_args__ = {'useexisting':True}
15 __table_args__ = {'useexisting':True}
16 ui_id = Column("ui_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
16 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)
17 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)
18 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)
19 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)
20 ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True)
21
21
22
22
23 class User(Base):
23 class User(Base):
24 __tablename__ = 'users'
24 __tablename__ = 'users'
25 __table_args__ = {'useexisting':True}
25 __table_args__ = {'useexisting':True}
26 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
26 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)
27 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)
28 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)
29 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
30 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=False)
30 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)
31 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)
32 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)
33 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)
34 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
35
35
36 user_log = relation('UserLog')
36 user_log = relation('UserLog')
37 user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id")
37
38
38 @LazyProperty
39 @LazyProperty
39 def full_contact(self):
40 def full_contact(self):
40 return '%s %s <%s>' % (self.name, self.lastname, self.email)
41 return '%s %s <%s>' % (self.name, self.lastname, self.email)
41
42
42 def __repr__(self):
43 def __repr__(self):
43 return "<User('%s:%s')>" % (self.user_id, self.username)
44 return "<User('id:%s:%s')>" % (self.user_id, self.username)
44
45
45 class UserLog(Base):
46 class UserLog(Base):
46 __tablename__ = 'user_logs'
47 __tablename__ = 'user_logs'
47 __table_args__ = {'useexisting':True}
48 __table_args__ = {'useexisting':True}
48 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
49 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
49 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
50 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
50 user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, 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)
51 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_name'), nullable=False, 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)
52 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
53 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
53 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
54 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
54
55
55 user = relation('User')
56 user = relation('User')
56
57
57 class Repository(Base):
58 class Repository(Base):
58 __tablename__ = 'repositories'
59 __tablename__ = 'repositories'
59 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
60 __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},)
60 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
61 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
61 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
62 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
62 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
63 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=False, default=None)
63 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
64 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
64 description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), 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)
65
66
66 user = relation('User')
67 user = relation('User')
67 repo_to_perm = relation('RepoToPerm', cascade='all')
68 repo_to_perm = relation('RepoToPerm', cascade='all')
68
69
70 def __repr__(self):
71 return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name)
72
69 class Permission(Base):
73 class Permission(Base):
70 __tablename__ = 'permissions'
74 __tablename__ = 'permissions'
71 __table_args__ = {'useexisting':True}
75 __table_args__ = {'useexisting':True}
72 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
76 permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
73 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
77 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
74 permission_longname = Column("permission_longname", 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)
75
79
76 def __repr__(self):
80 def __repr__(self):
77 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
81 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
78
82
79 class RepoToPerm(Base):
83 class RepoToPerm(Base):
80 __tablename__ = 'repo_to_perm'
84 __tablename__ = 'repo_to_perm'
81 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
85 __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True})
82 repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
86 repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
83 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
87 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
84 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_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)
85 repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_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)
86
90
87 user = relation('User')
91 user = relation('User')
88 permission = relation('Permission')
92 permission = relation('Permission')
89 repository = relation('Repository')
93 repository = relation('Repository')
90
94
91 class UserToPerm(Base):
95 class UserToPerm(Base):
92 __tablename__ = 'user_to_perm'
96 __tablename__ = 'user_to_perm'
93 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
97 __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True})
94 user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
98 user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True)
95 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
99 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None)
96 permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_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)
97
101
98 user = relation('User')
102 user = relation('User')
99 permission = relation('Permission')
103 permission = relation('Permission')
100
104
101
105
102
106
103
107
@@ -1,330 +1,339 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.db import User, Repository
29 from pylons_app.model.db import User, Repository
30 from sqlalchemy.exc import OperationalError
30 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
31 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from webhelpers.pylonslib.secure_form import authentication_token
32 from webhelpers.pylonslib.secure_form import authentication_token
33 import datetime
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
96 sa = meta.Session
97 password = value['password']
97 password = value['password']
98 username = value['username']
98 username = value['username']
99 try:
99 try:
100 user = sa.query(User).filter(User.username == username).one()
100 user = sa.query(User).filter(User.username == username).one()
101 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
101 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
102 log.error(e)
102 log.error(e)
103 user = None
103 user = None
104 raise formencode.Invalid(self.message('invalid_password',
104 raise formencode.Invalid(self.message('invalid_password',
105 state=State_obj), value, state,
105 state=State_obj), value, state,
106 error_dict=self.e_dict)
106 error_dict=self.e_dict)
107 if user:
107 if user:
108 if user.active:
108 if user.active:
109 if user.username == username and check_password(password, user.password):
109 if user.username == username and check_password(password, user.password):
110 from pylons_app.lib.auth import AuthUser
110 from pylons_app.lib.auth import AuthUser
111 auth_user = AuthUser()
111 auth_user = AuthUser()
112 auth_user.username = username
112 auth_user.username = username
113 auth_user.is_authenticated = True
113 auth_user.is_authenticated = True
114 auth_user.is_admin = user.admin
114 auth_user.is_admin = user.admin
115 auth_user.user_id = user.user_id
115 auth_user.user_id = user.user_id
116 auth_user.name = user.name
116 auth_user.name = user.name
117 auth_user.lastname = user.lastname
117 auth_user.lastname = user.lastname
118 session['hg_app_user'] = auth_user
118 session['hg_app_user'] = auth_user
119 session.save()
119 session.save()
120 log.info('user %s is now authenticated', username)
120 log.info('user %s is now authenticated', username)
121
121
122 try:
122 try:
123 user.last_login = datetime.datetime.now()
123 user.last_login = datetime.datetime.now()
124 sa.add(user)
124 sa.add(user)
125 sa.commit()
125 sa.commit()
126 except (OperationalError) as e:
126 except (OperationalError) as e:
127 log.error(e)
127 log.error(e)
128 sa.rollback()
128 sa.rollback()
129
129
130 return value
130 return value
131 else:
131 else:
132 log.warning('user %s not authenticated', username)
132 log.warning('user %s not authenticated', username)
133 raise formencode.Invalid(self.message('invalid_password',
133 raise formencode.Invalid(self.message('invalid_password',
134 state=State_obj), value, state,
134 state=State_obj), value, state,
135 error_dict=self.e_dict)
135 error_dict=self.e_dict)
136 else:
136 else:
137 log.warning('user %s is disabled', username)
137 log.warning('user %s is disabled', username)
138 raise formencode.Invalid(self.message('disabled_account',
138 raise formencode.Invalid(self.message('disabled_account',
139 state=State_obj),
139 state=State_obj),
140 value, state,
140 value, state,
141 error_dict=self.e_dict_disable)
141 error_dict=self.e_dict_disable)
142
142
143 meta.Session.remove()
143 meta.Session.remove()
144
144
145
145
146 class ValidRepoUser(formencode.validators.FancyValidator):
146 class ValidRepoUser(formencode.validators.FancyValidator):
147
147
148 def to_python(self, value, state):
148 def to_python(self, value, state):
149 sa = meta.Session
149 sa = meta.Session
150 try:
150 try:
151 self.user_db = sa.query(User)\
151 self.user_db = sa.query(User)\
152 .filter(User.active == True)\
152 .filter(User.active == True)\
153 .filter(User.username == value).one()
153 .filter(User.username == value).one()
154 except Exception:
154 except Exception:
155 raise formencode.Invalid(_('This username is not valid'),
155 raise formencode.Invalid(_('This username is not valid'),
156 value, state)
156 value, state)
157 meta.Session.remove()
157 meta.Session.remove()
158 return self.user_db.user_id
158 return self.user_db.user_id
159
159
160 def ValidRepoName(edit, old_data):
160 def ValidRepoName(edit, old_data):
161 class _ValidRepoName(formencode.validators.FancyValidator):
161 class _ValidRepoName(formencode.validators.FancyValidator):
162
162
163 def to_python(self, value, state):
163 def to_python(self, value, state):
164 slug = h.repo_name_slug(value)
164 slug = h.repo_name_slug(value)
165 if slug in ['_admin']:
165 if slug in ['_admin']:
166 raise formencode.Invalid(_('This repository name is disallowed'),
166 raise formencode.Invalid(_('This repository name is disallowed'),
167 value, state)
167 value, state)
168 if old_data.get('repo_name') != value or not edit:
168 if old_data.get('repo_name') != value or not edit:
169 sa = meta.Session
169 sa = meta.Session
170 if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
170 if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
171 raise formencode.Invalid(_('This repository already exists') ,
171 raise formencode.Invalid(_('This repository already exists') ,
172 value, state)
172 value, state)
173 meta.Session.remove()
173 meta.Session.remove()
174 return slug
174 return slug
175
175
176
176
177 return _ValidRepoName
177 return _ValidRepoName
178
178
179 class ValidPerms(formencode.validators.FancyValidator):
179 class ValidPerms(formencode.validators.FancyValidator):
180 messages = {'perm_new_user_name':_('This username is not valid')}
180 messages = {'perm_new_user_name':_('This username is not valid')}
181
181
182 def to_python(self, value, state):
182 def to_python(self, value, state):
183 perms_update = []
183 perms_update = []
184 perms_new = []
184 perms_new = []
185 #build a list of permission to update and new permission to create
185 #build a list of permission to update and new permission to create
186 for k, v in value.items():
186 for k, v in value.items():
187 if k.startswith('perm_'):
187 if k.startswith('perm_'):
188 if k.startswith('perm_new_user'):
188 if k.startswith('perm_new_user'):
189 new_perm = value.get('perm_new_user', False)
189 new_perm = value.get('perm_new_user', False)
190 new_user = value.get('perm_new_user_name', False)
190 new_user = value.get('perm_new_user_name', False)
191 if new_user and new_perm:
191 if new_user and new_perm:
192 if (new_user, new_perm) not in perms_new:
192 if (new_user, new_perm) not in perms_new:
193 perms_new.append((new_user, new_perm))
193 perms_new.append((new_user, new_perm))
194 else:
194 else:
195 usr = k[5:]
195 usr = k[5:]
196 if usr == 'default':
196 if usr == 'default':
197 if value['private']:
197 if value['private']:
198 #set none for default when updating to private repo
198 #set none for default when updating to private repo
199 v = 'repository.none'
199 v = 'repository.none'
200 perms_update.append((usr, v))
200 perms_update.append((usr, v))
201 value['perms_updates'] = perms_update
201 value['perms_updates'] = perms_update
202 value['perms_new'] = perms_new
202 value['perms_new'] = perms_new
203 sa = meta.Session
203 sa = meta.Session
204 for k, v in perms_new:
204 for k, v in perms_new:
205 try:
205 try:
206 self.user_db = sa.query(User)\
206 self.user_db = sa.query(User)\
207 .filter(User.active == True)\
207 .filter(User.active == True)\
208 .filter(User.username == k).one()
208 .filter(User.username == k).one()
209 except Exception:
209 except Exception:
210 msg = self.message('perm_new_user_name',
210 msg = self.message('perm_new_user_name',
211 state=State_obj)
211 state=State_obj)
212 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
212 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
213 return value
213 return value
214
214
215 class ValidSettings(formencode.validators.FancyValidator):
215 class ValidSettings(formencode.validators.FancyValidator):
216
216
217 def to_python(self, value, state):
217 def to_python(self, value, state):
218 #settings form can't edit user
218 #settings form can't edit user
219 if value.has_key('user'):
219 if value.has_key('user'):
220 del['value']['user']
220 del['value']['user']
221
221
222 return value
222 return value
223
223
224 class ValidPath(formencode.validators.FancyValidator):
224 class ValidPath(formencode.validators.FancyValidator):
225 def to_python(self, value, state):
225 def to_python(self, value, state):
226 isdir = os.path.isdir(value.replace('*', ''))
226 isdir = os.path.isdir(value.replace('*', ''))
227 if (value.endswith('/*') or value.endswith('/**')) and isdir:
227 if (value.endswith('/*') or value.endswith('/**')) and isdir:
228 return value
228 return value
229 elif not isdir:
229 elif not isdir:
230 msg = _('This is not a valid path')
230 msg = _('This is not a valid path')
231 else:
231 else:
232 msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
232 msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
233
233
234 raise formencode.Invalid(msg, value, state,
234 raise formencode.Invalid(msg, value, state,
235 error_dict={'paths_root_path':msg})
235 error_dict={'paths_root_path':msg})
236
236
237 #===============================================================================
237 #===============================================================================
238 # FORMS
238 # FORMS
239 #===============================================================================
239 #===============================================================================
240 class LoginForm(formencode.Schema):
240 class LoginForm(formencode.Schema):
241 allow_extra_fields = True
241 allow_extra_fields = True
242 filter_extra_fields = True
242 filter_extra_fields = True
243 username = UnicodeString(
243 username = UnicodeString(
244 strip=True,
244 strip=True,
245 min=3,
245 min=3,
246 not_empty=True,
246 not_empty=True,
247 messages={
247 messages={
248 'empty':_('Please enter a login'),
248 'empty':_('Please enter a login'),
249 'tooShort':_('Enter a value %(min)i characters long or more')}
249 'tooShort':_('Enter a value %(min)i characters long or more')}
250 )
250 )
251
251
252 password = UnicodeString(
252 password = UnicodeString(
253 strip=True,
253 strip=True,
254 min=3,
254 min=3,
255 not_empty=True,
255 not_empty=True,
256 messages={
256 messages={
257 'empty':_('Please enter a password'),
257 'empty':_('Please enter a password'),
258 'tooShort':_('Enter a value %(min)i characters long or more')}
258 'tooShort':_('Enter a value %(min)i characters long or more')}
259 )
259 )
260
260
261
261
262 #chained validators have access to all data
262 #chained validators have access to all data
263 chained_validators = [ValidAuth]
263 chained_validators = [ValidAuth]
264
264
265 def UserForm(edit=False, old_data={}):
265 def UserForm(edit=False, old_data={}):
266 class _UserForm(formencode.Schema):
266 class _UserForm(formencode.Schema):
267 allow_extra_fields = True
267 allow_extra_fields = True
268 filter_extra_fields = True
268 filter_extra_fields = True
269 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
269 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
270 if edit:
270 if edit:
271 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
271 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
272 admin = StringBoolean(if_missing=False)
272 admin = StringBoolean(if_missing=False)
273 else:
273 else:
274 password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
274 password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
275 active = StringBoolean(if_missing=False)
275 active = StringBoolean(if_missing=False)
276 name = UnicodeString(strip=True, min=3, not_empty=True)
276 name = UnicodeString(strip=True, min=3, not_empty=True)
277 lastname = UnicodeString(strip=True, min=3, not_empty=True)
277 lastname = UnicodeString(strip=True, min=3, not_empty=True)
278 email = Email(not_empty=True)
278 email = Email(not_empty=True)
279
279
280 return _UserForm
280 return _UserForm
281
281
282 RegisterForm = UserForm
282 RegisterForm = UserForm
283
283
284
284
285 def RepoForm(edit=False, old_data={}):
285 def RepoForm(edit=False, old_data={}):
286 class _RepoForm(formencode.Schema):
286 class _RepoForm(formencode.Schema):
287 allow_extra_fields = True
287 allow_extra_fields = True
288 filter_extra_fields = False
288 filter_extra_fields = False
289 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
289 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
290 description = UnicodeString(strip=True, min=3, not_empty=True)
290 description = UnicodeString(strip=True, min=3, not_empty=True)
291 private = StringBoolean(if_missing=False)
291 private = StringBoolean(if_missing=False)
292
292
293 if edit:
293 if edit:
294 user = All(Int(not_empty=True), ValidRepoUser)
294 user = All(Int(not_empty=True), ValidRepoUser)
295
295
296 chained_validators = [ValidPerms]
296 chained_validators = [ValidPerms]
297 return _RepoForm
297 return _RepoForm
298
298
299 def RepoSettingsForm(edit=False, old_data={}):
299 def RepoSettingsForm(edit=False, old_data={}):
300 class _RepoForm(formencode.Schema):
300 class _RepoForm(formencode.Schema):
301 allow_extra_fields = True
301 allow_extra_fields = True
302 filter_extra_fields = False
302 filter_extra_fields = False
303 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
303 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)
304 description = UnicodeString(strip=True, min=3, not_empty=True)
305 private = StringBoolean(if_missing=False)
305 private = StringBoolean(if_missing=False)
306
306
307 chained_validators = [ValidPerms, ValidSettings]
307 chained_validators = [ValidPerms, ValidSettings]
308 return _RepoForm
308 return _RepoForm
309
309
310
310
311 def ApplicationSettingsForm():
311 def ApplicationSettingsForm():
312 class _ApplicationSettingsForm(formencode.Schema):
312 class _ApplicationSettingsForm(formencode.Schema):
313 allow_extra_fields = True
313 allow_extra_fields = True
314 filter_extra_fields = False
314 filter_extra_fields = False
315 hg_app_title = UnicodeString(strip=True, min=3, not_empty=True)
315 hg_app_title = UnicodeString(strip=True, min=3, not_empty=True)
316 hg_app_realm = UnicodeString(strip=True, min=3, not_empty=True)
316 hg_app_realm = UnicodeString(strip=True, min=3, not_empty=True)
317
317
318 return _ApplicationSettingsForm
318 return _ApplicationSettingsForm
319
319
320 def ApplicationUiSettingsForm():
320 def ApplicationUiSettingsForm():
321 class _ApplicationUiSettingsForm(formencode.Schema):
321 class _ApplicationUiSettingsForm(formencode.Schema):
322 allow_extra_fields = True
322 allow_extra_fields = True
323 filter_extra_fields = False
323 filter_extra_fields = False
324 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
324 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
325 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=3, not_empty=True))
325 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=3, not_empty=True))
326 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
326 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
327 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
327 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
328
328
329 return _ApplicationUiSettingsForm
329 return _ApplicationUiSettingsForm
330
330
331 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
332 class _DefaultPermissionsForm(formencode.Schema):
333 allow_extra_fields = True
334 filter_extra_fields = True
335 default_perm = OneOf(perms_choices)
336 default_register = OneOf(register_choices)
337 default_create = OneOf(create_choices)
338
339 return _DefaultPermissionsForm
@@ -1,178 +1,185 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # model for handling repositories actions
3 # model for handling repositories actions
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
8 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
19 """
19 """
20 Created on Jun 5, 2010
20 Created on Jun 5, 2010
21 model for handling repositories actions
21 model for handling repositories actions
22 @author: marcink
22 @author: marcink
23 """
23 """
24 from datetime import datetime
24 from datetime import datetime
25 from pylons import app_globals as g
25 from pylons import app_globals as g
26 from pylons_app.lib.utils import check_repo
26 from pylons_app.lib.utils import check_repo
27 from pylons_app.model.db import Repository, RepoToPerm, User, Permission
27 from pylons_app.model.db import Repository, RepoToPerm, User, Permission
28 from pylons_app.model.meta import Session
28 from pylons_app.model.meta import Session
29 from pylons_app.model.user_model import UserModel
29 import logging
30 import logging
30 import os
31 import os
31 import shutil
32 import shutil
32 import traceback
33 import traceback
33 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
34
35
35 class RepoModel(object):
36 class RepoModel(object):
36
37
37 def __init__(self):
38 def __init__(self):
38 self.sa = Session()
39 self.sa = Session()
39
40
40 def get(self, id):
41 def get(self, id):
41 return self.sa.query(Repository).filter(Repository.repo_name == id).scalar()
42 return self.sa.query(Repository).filter(Repository.repo_name == id).scalar()
42
43
43 def get_users_js(self):
44 def get_users_js(self):
44
45
45 users = self.sa.query(User).filter(User.active == True).all()
46 users = self.sa.query(User).filter(User.active == True).all()
46 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
47 u_tmpl = '''{id:%s, fname:"%s", lname:"%s", nname:"%s"},'''
47 users_array = '[%s];' % '\n'.join([u_tmpl % (u.user_id, u.name,
48 users_array = '[%s];' % '\n'.join([u_tmpl % (u.user_id, u.name,
48 u.lastname, u.username)
49 u.lastname, u.username)
49 for u in users])
50 for u in users])
50 return users_array
51 return users_array
51
52
52
53
53 def update(self, repo_name, form_data):
54 def update(self, repo_name, form_data):
54 try:
55 try:
55
56
56 #update permissions
57 #update permissions
57 for username, perm in form_data['perms_updates']:
58 for username, perm in form_data['perms_updates']:
58 r2p = self.sa.query(RepoToPerm)\
59 r2p = self.sa.query(RepoToPerm)\
59 .filter(RepoToPerm.user == self.sa.query(User)\
60 .filter(RepoToPerm.user == self.sa.query(User)\
60 .filter(User.username == username).one())\
61 .filter(User.username == username).one())\
61 .filter(RepoToPerm.repository == self.get(repo_name))\
62 .filter(RepoToPerm.repository == self.get(repo_name))\
62 .one()
63 .one()
63
64
64 r2p.permission_id = self.sa.query(Permission).filter(
65 r2p.permission_id = self.sa.query(Permission).filter(
65 Permission.permission_name ==
66 Permission.permission_name ==
66 perm).one().permission_id
67 perm).one().permission_id
67 self.sa.add(r2p)
68 self.sa.add(r2p)
68
69
69 #set new permissions
70 #set new permissions
70 for username, perm in form_data['perms_new']:
71 for username, perm in form_data['perms_new']:
71 r2p = RepoToPerm()
72 r2p = RepoToPerm()
72 r2p.repository = self.get(repo_name)
73 r2p.repository = self.get(repo_name)
73 r2p.user = self.sa.query(User)\
74 r2p.user = self.sa.query(User)\
74 .filter(User.username == username).one()
75 .filter(User.username == username).one()
75
76
76 r2p.permission_id = self.sa.query(Permission).filter(
77 r2p.permission_id = self.sa.query(Permission).filter(
77 Permission.permission_name == perm)\
78 Permission.permission_name == perm)\
78 .one().permission_id
79 .one().permission_id
79 self.sa.add(r2p)
80 self.sa.add(r2p)
80
81
81 #update current repo
82 #update current repo
82 cur_repo = self.get(repo_name)
83 cur_repo = self.get(repo_name)
83
84
84 for k, v in form_data.items():
85 for k, v in form_data.items():
85 if k == 'user':
86 if k == 'user':
86 cur_repo.user_id = v
87 cur_repo.user_id = v
87 else:
88 else:
88 setattr(cur_repo, k, v)
89 setattr(cur_repo, k, v)
89
90
90 self.sa.add(cur_repo)
91 self.sa.add(cur_repo)
91
92
92 if repo_name != form_data['repo_name']:
93 if repo_name != form_data['repo_name']:
93 #rename our data
94 #rename our data
94 self.__rename_repo(repo_name, form_data['repo_name'])
95 self.__rename_repo(repo_name, form_data['repo_name'])
95
96
96 self.sa.commit()
97 self.sa.commit()
97 except:
98 except:
98 log.error(traceback.format_exc())
99 log.error(traceback.format_exc())
99 self.sa.rollback()
100 self.sa.rollback()
100 raise
101 raise
101
102
102 def create(self, form_data, cur_user, just_db=False):
103 def create(self, form_data, cur_user, just_db=False):
103 try:
104 try:
104 repo_name = form_data['repo_name']
105 repo_name = form_data['repo_name']
105 new_repo = Repository()
106 new_repo = Repository()
106 for k, v in form_data.items():
107 for k, v in form_data.items():
107 setattr(new_repo, k, v)
108 setattr(new_repo, k, v)
108
109
109 new_repo.user_id = cur_user.user_id
110 new_repo.user_id = cur_user.user_id
110 self.sa.add(new_repo)
111 self.sa.add(new_repo)
111
112
112 #create default permission
113 #create default permission
113 repo_to_perm = RepoToPerm()
114 repo_to_perm = RepoToPerm()
114 default_perm = 'repository.none' if form_data['private'] \
115 default = 'repository.read'
115 else 'repository.read'
116 for p in UserModel().get_default().user_perms:
117 if p.permission.permission_name.startswith('repository.'):
118 default = p.permission.permission_name
119 break
120
121 default_perm = 'repository.none' if form_data['private'] else default
122
116 repo_to_perm.permission_id = self.sa.query(Permission)\
123 repo_to_perm.permission_id = self.sa.query(Permission)\
117 .filter(Permission.permission_name == default_perm)\
124 .filter(Permission.permission_name == default_perm)\
118 .one().permission_id
125 .one().permission_id
119
126
120 repo_to_perm.repository_id = new_repo.repo_id
127 repo_to_perm.repository_id = new_repo.repo_id
121 repo_to_perm.user_id = self.sa.query(User)\
128 repo_to_perm.user_id = self.sa.query(User)\
122 .filter(User.username == 'default').one().user_id
129 .filter(User.username == 'default').one().user_id
123
130
124 self.sa.add(repo_to_perm)
131 self.sa.add(repo_to_perm)
125 self.sa.commit()
132 self.sa.commit()
126 if not just_db:
133 if not just_db:
127 self.__create_repo(repo_name)
134 self.__create_repo(repo_name)
128 except:
135 except:
129 log.error(traceback.format_exc())
136 log.error(traceback.format_exc())
130 self.sa.rollback()
137 self.sa.rollback()
131 raise
138 raise
132
139
133 def delete(self, repo):
140 def delete(self, repo):
134 try:
141 try:
135 self.sa.delete(repo)
142 self.sa.delete(repo)
136 self.sa.commit()
143 self.sa.commit()
137 self.__delete_repo(repo.repo_name)
144 self.__delete_repo(repo.repo_name)
138 except:
145 except:
139 log.error(traceback.format_exc())
146 log.error(traceback.format_exc())
140 self.sa.rollback()
147 self.sa.rollback()
141 raise
148 raise
142
149
143 def delete_perm_user(self, form_data, repo_name):
150 def delete_perm_user(self, form_data, repo_name):
144 try:
151 try:
145 self.sa.query(RepoToPerm)\
152 self.sa.query(RepoToPerm)\
146 .filter(RepoToPerm.repository == self.get(repo_name))\
153 .filter(RepoToPerm.repository == self.get(repo_name))\
147 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
154 .filter(RepoToPerm.user_id == form_data['user_id']).delete()
148 self.sa.commit()
155 self.sa.commit()
149 except:
156 except:
150 log.error(traceback.format_exc())
157 log.error(traceback.format_exc())
151 self.sa.rollback()
158 self.sa.rollback()
152 raise
159 raise
153
160
154 def __create_repo(self, repo_name):
161 def __create_repo(self, repo_name):
155 repo_path = os.path.join(g.base_path, repo_name)
162 repo_path = os.path.join(g.base_path, repo_name)
156 if check_repo(repo_name, g.base_path):
163 if check_repo(repo_name, g.base_path):
157 log.info('creating repo %s in %s', repo_name, repo_path)
164 log.info('creating repo %s in %s', repo_name, repo_path)
158 from vcs.backends.hg import MercurialRepository
165 from vcs.backends.hg import MercurialRepository
159 MercurialRepository(repo_path, create=True)
166 MercurialRepository(repo_path, create=True)
160
167
161 def __rename_repo(self, old, new):
168 def __rename_repo(self, old, new):
162 log.info('renaming repo from %s to %s', old, new)
169 log.info('renaming repo from %s to %s', old, new)
163
170
164 old_path = os.path.join(g.base_path, old)
171 old_path = os.path.join(g.base_path, old)
165 new_path = os.path.join(g.base_path, new)
172 new_path = os.path.join(g.base_path, new)
166 if os.path.isdir(new_path):
173 if os.path.isdir(new_path):
167 raise Exception('Was trying to rename to already existing dir %s',
174 raise Exception('Was trying to rename to already existing dir %s',
168 new_path)
175 new_path)
169 shutil.move(old_path, new_path)
176 shutil.move(old_path, new_path)
170
177
171 def __delete_repo(self, name):
178 def __delete_repo(self, name):
172 rm_path = os.path.join(g.base_path, name)
179 rm_path = os.path.join(g.base_path, name)
173 log.info("Removing %s", rm_path)
180 log.info("Removing %s", rm_path)
174 #disable hg
181 #disable hg
175 shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
182 shutil.move(os.path.join(rm_path, '.hg'), os.path.join(rm_path, 'rm__.hg'))
176 #disable repo
183 #disable repo
177 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
184 shutil.move(rm_path, os.path.join(g.base_path, 'rm__%s__%s' \
178 % (datetime.today(), name)))
185 % (datetime.today(), name)))
@@ -1,126 +1,128 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):
41 return self.sa.query(User).filter(User.username == 'default').scalar()
42
40 def get_user(self, id):
43 def get_user(self, id):
41 return self.sa.query(User).get(id)
44 return self.sa.query(User).get(id)
42
45
43 def create(self, form_data):
46 def create(self, form_data):
44 try:
47 try:
45 new_user = User()
48 new_user = User()
46 for k, v in form_data.items():
49 for k, v in form_data.items():
47 setattr(new_user, k, v)
50 setattr(new_user, k, v)
48
51
49 self.sa.add(new_user)
52 self.sa.add(new_user)
50 self.sa.commit()
53 self.sa.commit()
51 except Exception as e:
54 except Exception as e:
52 log.error(e)
55 log.error(e)
53 self.sa.rollback()
56 self.sa.rollback()
54 raise
57 raise
55
58
56 def create_registration(self, form_data):
59 def create_registration(self, form_data):
57 try:
60 try:
58 new_user = User()
61 new_user = User()
59 for k, v in form_data.items():
62 for k, v in form_data.items():
60 if k != 'admin' or k != 'active':
63 if k != 'admin':
61 setattr(new_user, k, v)
64 setattr(new_user, k, v)
62 setattr(new_user, 'active', True)
63
65
64 self.sa.add(new_user)
66 self.sa.add(new_user)
65 self.sa.commit()
67 self.sa.commit()
66 except Exception as e:
68 except Exception as e:
67 log.error(e)
69 log.error(e)
68 self.sa.rollback()
70 self.sa.rollback()
69 raise
71 raise
70
72
71 def update(self, uid, form_data):
73 def update(self, uid, form_data):
72 try:
74 try:
73 new_user = self.sa.query(User).get(uid)
75 new_user = self.sa.query(User).get(uid)
74 if new_user.username == 'default':
76 if new_user.username == 'default':
75 raise DefaultUserException(
77 raise DefaultUserException(
76 _("You can't Edit this user since it's"
78 _("You can't Edit this user since it's"
77 " crucial for entire application"))
79 " crucial for entire application"))
78 for k, v in form_data.items():
80 for k, v in form_data.items():
79 if k == 'new_password' and v != '':
81 if k == 'new_password' and v != '':
80 new_user.password = v
82 new_user.password = v
81 else:
83 else:
82 setattr(new_user, k, v)
84 setattr(new_user, k, v)
83
85
84 self.sa.add(new_user)
86 self.sa.add(new_user)
85 self.sa.commit()
87 self.sa.commit()
86 except Exception as e:
88 except Exception as e:
87 log.error(e)
89 log.error(e)
88 self.sa.rollback()
90 self.sa.rollback()
89 raise
91 raise
90
92
91 def update_my_account(self, uid, form_data):
93 def update_my_account(self, uid, form_data):
92 try:
94 try:
93 new_user = self.sa.query(User).get(uid)
95 new_user = self.sa.query(User).get(uid)
94 if new_user.username == 'default':
96 if new_user.username == 'default':
95 raise DefaultUserException(
97 raise DefaultUserException(
96 _("You can't Edit this user since it's"
98 _("You can't Edit this user since it's"
97 " crucial for entire application"))
99 " crucial for entire application"))
98 for k, v in form_data.items():
100 for k, v in form_data.items():
99 if k == 'new_password' and v != '':
101 if k == 'new_password' and v != '':
100 new_user.password = v
102 new_user.password = v
101 else:
103 else:
102 if k not in ['admin', 'active']:
104 if k not in ['admin', 'active']:
103 setattr(new_user, k, v)
105 setattr(new_user, k, v)
104
106
105 self.sa.add(new_user)
107 self.sa.add(new_user)
106 self.sa.commit()
108 self.sa.commit()
107 except Exception as e:
109 except Exception as e:
108 log.error(e)
110 log.error(e)
109 self.sa.rollback()
111 self.sa.rollback()
110 raise
112 raise
111
113
112 def delete(self, id):
114 def delete(self, id):
113
115
114 try:
116 try:
115
117
116 user = self.sa.query(User).get(id)
118 user = self.sa.query(User).get(id)
117 if user.username == 'default':
119 if user.username == 'default':
118 raise DefaultUserException(
120 raise DefaultUserException(
119 _("You can't remove this user since it's"
121 _("You can't remove this user since it's"
120 " crucial for entire application"))
122 " crucial for entire application"))
121 self.sa.delete(user)
123 self.sa.delete(user)
122 self.sa.commit()
124 self.sa.commit()
123 except Exception as e:
125 except Exception as e:
124 log.error(e)
126 log.error(e)
125 self.sa.rollback()
127 self.sa.rollback()
126 raise
128 raise
@@ -1,45 +1,62 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Permissions administration')}
5 ${_('Permissions administration')}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 &raquo;
10 &raquo;
11 ${_('Permissions')}
11 ${_('Permissions')}
12 </%def>
12 </%def>
13
13
14 <%def name="page_nav()">
14 <%def name="page_nav()">
15 ${self.menu('admin')}
15 ${self.menu('admin')}
16 </%def>
16 </%def>
17
17
18 <%def name="main()">
18 <%def name="main()">
19 <div class="box">
19 <div class="box">
20 <!-- box / title -->
20 <!-- box / title -->
21 <div class="title">
21 <div class="title">
22 ${self.breadcrumbs()}
22 ${self.breadcrumbs()}
23 </div>
23 </div>
24 <h3>${_('Repositories permissions')}</h3>
24 <h3>${_('Default permissions')}</h3>
25 ${h.form(url('permission', id='default_perm'),method='put')}
25 ${h.form(url('permission', id='default'),method='put')}
26 <div class="form">
26 <div class="form">
27 <!-- fields -->
27 <!-- fields -->
28 <div class="fields">
28 <div class="fields">
29
29
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="default_perm">${_('default repository permission')}:</label>
32 <label for="default_perm">${_('Default repository permission')}:</label>
33 </div>
34 <div class="select">
35 ${h.select('default_perm','',c.perms_choices)}
36 </div>
37 </div>
38 <div class="field">
39 <div class="label">
40 <label for="default_register">${_('Registration')}:</label>
33 </div>
41 </div>
34 <div class="select">
42 <div class="select">
35 ${h.select('default_perm','repository.read',['repository.none','repository.read','repository.write','repository.admin'])}
43 ${h.select('default_register','',c.register_choices)}
36 </div>
44 </div>
37 </div>
45 </div>
46 <div class="field">
47 <div class="label">
48 <label for="default_create">${_('Allow repository creation')}:</label>
49 </div>
50 <div class="select">
51 ${h.select('default_create','',c.create_choices)}
52 </div>
53 </div>
54
38 <div class="buttons">
55 <div class="buttons">
39 ${h.submit('set','set',class_="ui-button ui-widget ui-state-default ui-corner-all")}
56 ${h.submit('set','set',class_="ui-button ui-widget ui-state-default ui-corner-all")}
40 </div>
57 </div>
41 </div>
58 </div>
42 </div>
59 </div>
43 ${h.end_form()}
60 ${h.end_form()}
44 </div>
61 </div>
45 </%def>
62 </%def>
@@ -1,255 +1,255 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${next.title()}</title>
5 <title>${next.title()}</title>
6 <link rel="icon" href="/images/hgicon.png" type="image/png" />
6 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9 <!-- stylesheets -->
9 <!-- stylesheets -->
10 ${self.css()}
10 ${self.css()}
11 <!-- scripts -->
11 <!-- scripts -->
12 ${self.js()}
12 ${self.js()}
13 </head>
13 </head>
14 <body>
14 <body>
15 <!-- header -->
15 <!-- header -->
16 <div id="header">
16 <div id="header">
17 <!-- user -->
17 <!-- user -->
18 <ul id="logged-user">
18 <ul id="logged-user">
19 <li class="first">
19 <li class="first">
20 <div class="gravatar">
20 <div class="gravatar">
21 <img alt="gravatar" src="${h.gravatar_url(c.hg_app_user.email,24)}" />
21 <img alt="gravatar" src="${h.gravatar_url(c.hg_app_user.email,24)}" />
22 </div>
22 </div>
23 <div class="account">
23 <div class="account">
24 ${h.link_to('%s %s'%(c.hg_app_user.name,c.hg_app_user.lastname),h.url('admin_settings_my_account'))}<br/>
24 ${h.link_to('%s %s'%(c.hg_app_user.name,c.hg_app_user.lastname),h.url('admin_settings_my_account'))}<br/>
25 ${h.link_to(c.hg_app_user.username,h.url('admin_settings_my_account'))}
25 ${h.link_to(c.hg_app_user.username,h.url('admin_settings_my_account'))}
26 </div>
26 </div>
27 </li>
27 </li>
28 <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
28 <li class="last highlight">${h.link_to(u'Logout',h.url('logout_home'))}</li>
29 </ul>
29 </ul>
30 <!-- end user -->
30 <!-- end user -->
31 <div id="header-inner">
31 <div id="header-inner">
32 <div id="home">
32 <div id="home">
33 <a href="${h.url('hg_home')}"></a>
33 <a href="${h.url('hg_home')}"></a>
34 </div>
34 </div>
35 <!-- logo -->
35 <!-- logo -->
36 <div id="logo">
36 <div id="logo">
37 <h1><a href="${h.url('hg_home')}">${c.hg_app_name}</a></h1>
37 <h1><a href="${h.url('hg_home')}">${c.hg_app_name}</a></h1>
38 </div>
38 </div>
39 <!-- end logo -->
39 <!-- end logo -->
40 <!-- quick menu -->
40 <!-- quick menu -->
41 ${self.page_nav()}
41 ${self.page_nav()}
42 <!-- end quick -->
42 <!-- end quick -->
43 <div class="corner tl"></div>
43 <div class="corner tl"></div>
44 <div class="corner tr"></div>
44 <div class="corner tr"></div>
45 </div>
45 </div>
46 </div>
46 </div>
47 <!-- end header -->
47 <!-- end header -->
48
48
49 <!-- CONTENT -->
49 <!-- CONTENT -->
50 <div id="content">
50 <div id="content">
51 <div class="flash_msg">
51 <div class="flash_msg">
52 <% messages = h.flash.pop_messages() %>
52 <% messages = h.flash.pop_messages() %>
53 % if messages:
53 % if messages:
54 <ul id="flash-messages">
54 <ul id="flash-messages">
55 % for message in messages:
55 % for message in messages:
56 <li class="${message.category}_msg">${message}</li>
56 <li class="${message.category}_msg">${message}</li>
57 % endfor
57 % endfor
58 </ul>
58 </ul>
59 % endif
59 % endif
60 </div>
60 </div>
61 <div id="main">
61 <div id="main">
62 ${next.main()}
62 ${next.main()}
63 </div>
63 </div>
64 </div>
64 </div>
65 <!-- END CONTENT -->
65 <!-- END CONTENT -->
66
66
67 <!-- footer -->
67 <!-- footer -->
68 <div id="footer">
68 <div id="footer">
69 <p>Hg App ${c.hg_app_version} &copy; 2010 by Marcin Kuzminski</p>
69 <p>Hg App ${c.hg_app_version} &copy; 2010 by Marcin Kuzminski</p>
70 <script type="text/javascript">${h.tooltip.activate()}</script>
70 <script type="text/javascript">${h.tooltip.activate()}</script>
71 </div>
71 </div>
72 <!-- end footer -->
72 <!-- end footer -->
73 </body>
73 </body>
74
74
75 </html>
75 </html>
76
76
77 ### MAKO DEFS ###
77 ### MAKO DEFS ###
78 <%def name="page_nav()">
78 <%def name="page_nav()">
79 ${self.menu()}
79 ${self.menu()}
80 </%def>
80 </%def>
81
81
82 <%def name="menu(current=None)">
82 <%def name="menu(current=None)">
83 <%
83 <%
84 def is_current(selected):
84 def is_current(selected):
85 if selected == current:
85 if selected == current:
86 return h.literal('class="current"')
86 return h.literal('class="current"')
87 %>
87 %>
88 %if current not in ['home','admin']:
88 %if current not in ['home','admin']:
89 <script type="text/javascript">
89 <script type="text/javascript">
90 YAHOO.util.Event.onDOMReady(function(){
90 YAHOO.util.Event.onDOMReady(function(){
91 YAHOO.util.Event.addListener('repo_switcher','click',function(){
91 YAHOO.util.Event.addListener('repo_switcher','click',function(){
92 if(YAHOO.util.Dom.hasClass('repo_switcher','selected')){
92 if(YAHOO.util.Dom.hasClass('repo_switcher','selected')){
93 YAHOO.util.Dom.setStyle('switch_repos','display','none');
93 YAHOO.util.Dom.setStyle('switch_repos','display','none');
94 YAHOO.util.Dom.setStyle('repo_switcher','background','');
94 YAHOO.util.Dom.setStyle('repo_switcher','background','');
95 YAHOO.util.Dom.removeClass('repo_switcher','selected');
95 YAHOO.util.Dom.removeClass('repo_switcher','selected');
96 YAHOO.util.Dom.get('repo_switcher').removeAttribute('style');
96 YAHOO.util.Dom.get('repo_switcher').removeAttribute('style');
97 }
97 }
98 else{
98 else{
99 YAHOO.util.Dom.setStyle('switch_repos','display','');
99 YAHOO.util.Dom.setStyle('switch_repos','display','');
100 YAHOO.util.Dom.addClass('repo_switcher','selected');
100 YAHOO.util.Dom.addClass('repo_switcher','selected');
101 }
101 }
102 });
102 });
103 YAHOO.util.Event.addListener('repos_list','change',function(e){
103 YAHOO.util.Event.addListener('repos_list','change',function(e){
104 var wa = YAHOO.util.Dom.get('repos_list').value;
104 var wa = YAHOO.util.Dom.get('repos_list').value;
105
105
106 var url = "${h.url('summary_home',repo_name='__REPO__')}".replace('__REPO__',wa);
106 var url = "${h.url('summary_home',repo_name='__REPO__')}".replace('__REPO__',wa);
107 window.location = url;
107 window.location = url;
108 })
108 })
109 });
109 });
110 </script>
110 </script>
111
111
112 ##REGULAR MENU
112 ##REGULAR MENU
113 <ul id="quick">
113 <ul id="quick">
114 <!-- repo switcher -->
114 <!-- repo switcher -->
115 <li>
115 <li>
116 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
116 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
117 <span class="icon">
117 <span class="icon">
118 <img src="/images/icons/database.png" alt="${_('Products')}" />
118 <img src="/images/icons/database.png" alt="${_('Products')}" />
119 </span>
119 </span>
120 <span>&darr;</span>
120 <span>&darr;</span>
121 </a>
121 </a>
122 <div id="switch_repos" style="display:none;">
122 <div id="switch_repos" style="display:none;">
123 <select id="repos_list" size="10">
123 <select id="repos_list" size="10">
124 %for repo in c.repo_switcher_list:
124 %for repo in c.repo_switcher_list:
125 <option value="${repo}">${repo}</option>
125 <option value="${repo}">${repo}</option>
126 %endfor
126 %endfor
127 </select>
127 </select>
128 </div>
128 </div>
129 </li>
129 </li>
130
130
131 <li ${is_current('summary')}>
131 <li ${is_current('summary')}>
132 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
132 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
133 <span class="icon">
133 <span class="icon">
134 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
134 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
135 </span>
135 </span>
136 <span>${_('Summary')}</span>
136 <span>${_('Summary')}</span>
137 </a>
137 </a>
138 </li>
138 </li>
139 <li ${is_current('shortlog')}>
139 <li ${is_current('shortlog')}>
140 <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
140 <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
141 <span class="icon">
141 <span class="icon">
142 <img src="/images/icons/application_double.png" alt="${_('Shortlog')}" />
142 <img src="/images/icons/application_double.png" alt="${_('Shortlog')}" />
143 </span>
143 </span>
144 <span>${_('Shortlog')}</span>
144 <span>${_('Shortlog')}</span>
145 </a>
145 </a>
146 </li>
146 </li>
147 <li ${is_current('changelog')}>
147 <li ${is_current('changelog')}>
148 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
148 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
149 <span class="icon">
149 <span class="icon">
150 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
150 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
151 </span>
151 </span>
152 <span>${_('Changelog')}</span>
152 <span>${_('Changelog')}</span>
153 </a>
153 </a>
154 </li>
154 </li>
155 <li ${is_current('branches')}>
155 <li ${is_current('branches')}>
156 <a title="${_('Branches')}" href="${h.url('branches_home',repo_name=c.repo_name)}">
156 <a title="${_('Branches')}" href="${h.url('branches_home',repo_name=c.repo_name)}">
157 <span class="icon">
157 <span class="icon">
158 <img src="/images/icons/arrow_branch.png" alt="${_('Branches')}" />
158 <img src="/images/icons/arrow_branch.png" alt="${_('Branches')}" />
159 </span>
159 </span>
160 <span>${_('Branches')}</span>
160 <span>${_('Branches')}</span>
161 </a>
161 </a>
162 </li>
162 </li>
163 <li ${is_current('tags')}>
163 <li ${is_current('tags')}>
164 <a title="${_('Tags')}" href="${h.url('tags_home',repo_name=c.repo_name)}">
164 <a title="${_('Tags')}" href="${h.url('tags_home',repo_name=c.repo_name)}">
165 <span class="icon">
165 <span class="icon">
166 <img src="/images/icons/tag_blue.png" alt="${_('Tags')}" />
166 <img src="/images/icons/tag_blue.png" alt="${_('Tags')}" />
167 </span>
167 </span>
168 <span>${_('Tags')}</span>
168 <span>${_('Tags')}</span>
169 </a>
169 </a>
170 </li>
170 </li>
171 <li ${is_current('files')}>
171 <li ${is_current('files')}>
172 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
172 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
173 <span class="icon">
173 <span class="icon">
174 <img src="/images/icons/file.png" alt="${_('Files')}" />
174 <img src="/images/icons/file.png" alt="${_('Files')}" />
175 </span>
175 </span>
176 <span>${_('Files')}</span>
176 <span>${_('Files')}</span>
177 </a>
177 </a>
178 </li>
178 </li>
179 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
179 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
180 <li ${is_current('settings')}>
180 <li ${is_current('settings')}>
181 <a title="${_('Settings')}" href="${h.url('repo_settings_home',repo_name=c.repo_name)}">
181 <a title="${_('Settings')}" href="${h.url('repo_settings_home',repo_name=c.repo_name)}">
182 <span class="icon">
182 <span class="icon">
183 <img src="/images/icons/cog_edit.png" alt="${_('Settings')}" />
183 <img src="/images/icons/cog_edit.png" alt="${_('Settings')}" />
184 </span>
184 </span>
185 <span>${_('Settings')}</span>
185 <span>${_('Settings')}</span>
186 </a>
186 </a>
187 </li>
187 </li>
188 %endif
188 %endif
189 </ul>
189 </ul>
190 %else:
190 %else:
191 ##ROOT MENU
191 ##ROOT MENU
192 <ul id="quick">
192 <ul id="quick">
193 <li>
193 <li>
194 <a title="${_('Home')}" href="${h.url('hg_home')}">
194 <a title="${_('Home')}" href="${h.url('hg_home')}">
195 <span class="icon">
195 <span class="icon">
196 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
196 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
197 </span>
197 </span>
198 <span>${_('Home')}</span>
198 <span>${_('Home')}</span>
199 </a>
199 </a>
200 </li>
200 </li>
201
201
202 <li>
202 <li>
203 <a title="${_('Search')}" href="${h.url('search')}">
203 <a title="${_('Search')}" href="${h.url('search')}">
204 <span class="icon">
204 <span class="icon">
205 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
205 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
206 </span>
206 </span>
207 <span>${_('Search')}</span>
207 <span>${_('Search')}</span>
208 </a>
208 </a>
209 </li>
209 </li>
210
210
211 %if h.HasPermissionAll('hg.admin')('access admin main page'):
211 %if h.HasPermissionAll('hg.admin')('access admin main page'):
212 <li ${is_current('admin')}>
212 <li ${is_current('admin')}>
213 <a title="${_('Admin')}" href="${h.url('admin_home')}">
213 <a title="${_('Admin')}" href="${h.url('admin_home')}">
214 <span class="icon">
214 <span class="icon">
215 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
215 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
216 </span>
216 </span>
217 <span>${_('Admin')}</span>
217 <span>${_('Admin')}</span>
218 </a>
218 </a>
219 <ul>
219 <ul>
220 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
220 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
221 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
221 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
222 <li>${h.link_to(_('permissions'),h.url('permissions'),class_='permissions')}</li>
222 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
223 <li>${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
223 <li>${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
224 </ul>
224 </ul>
225 </li>
225 </li>
226 %endif
226 %endif
227
227
228 </ul>
228 </ul>
229 %endif
229 %endif
230 </%def>
230 </%def>
231
231
232
232
233 <%def name="css()">
233 <%def name="css()">
234 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
234 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
235 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
235 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
236 <link rel="stylesheet" type="text/css" href="/css/style_full.css" />
236 <link rel="stylesheet" type="text/css" href="/css/style_full.css" />
237 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
237 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
238 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
238 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
239 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
239 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
240 </%def>
240 </%def>
241
241
242 <%def name="js()">
242 <%def name="js()">
243 <script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
243 <script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
244 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
244 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
245 <script type="text/javascript" src="/js/yui/container/container-min.js"></script>
245 <script type="text/javascript" src="/js/yui/container/container-min.js"></script>
246 <script type="text/javascript" src="/js/yui/datasource/datasource-min.js"></script>
246 <script type="text/javascript" src="/js/yui/datasource/datasource-min.js"></script>
247 <script type="text/javascript" src="/js/yui/autocomplete/autocomplete-min.js"></script>
247 <script type="text/javascript" src="/js/yui/autocomplete/autocomplete-min.js"></script>
248 <script type="text/javascript" src="/js/yui.flot.js"></script>
248 <script type="text/javascript" src="/js/yui.flot.js"></script>
249 </%def>
249 </%def>
250
250
251 <%def name="breadcrumbs()">
251 <%def name="breadcrumbs()">
252 <div class="breadcrumbs">
252 <div class="breadcrumbs">
253 ${self.breadcrumbs_links()}
253 ${self.breadcrumbs_links()}
254 </div>
254 </div>
255 </%def> No newline at end of file
255 </%def>
@@ -1,84 +1,84 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/base.html"/>
2 <%inherit file="base/base.html"/>
3 <%def name="title()">
3 <%def name="title()">
4 ${c.hg_app_name}
4 ${c.hg_app_name}
5 </%def>
5 </%def>
6 <%def name="breadcrumbs()">
6 <%def name="breadcrumbs()">
7 ${c.hg_app_name}
7 ${c.hg_app_name}
8 </%def>
8 </%def>
9 <%def name="page_nav()">
9 <%def name="page_nav()">
10 ${self.menu('home')}
10 ${self.menu('home')}
11 </%def>
11 </%def>
12 <%def name="main()">
12 <%def name="main()">
13 <%def name="get_sort(name)">
13 <%def name="get_sort(name)">
14 <%name_slug = name.lower().replace(' ','_') %>
14 <%name_slug = name.lower().replace(' ','_') %>
15 %if name_slug == c.cs_slug:
15 %if name_slug == c.cs_slug:
16 <span style="font-weight: bold;text-decoration: underline;">${name}</span>
16 <span style="font-weight: bold;text-decoration: underline;">${name}</span>
17 %else:
17 %else:
18 <span style="font-weight: bold">${name}</span>
18 <span style="font-weight: bold">${name}</span>
19 %endif
19 %endif
20 <a href="?sort=${name_slug}">&darr;</a>
20 <a href="?sort=${name_slug}">&darr;</a>
21 <a href="?sort=-${name_slug}">&uarr;</a>
21 <a href="?sort=-${name_slug}">&uarr;</a>
22 </%def>
22 </%def>
23
23
24
24
25
25
26 <div class="box">
26 <div class="box">
27 <!-- box / title -->
27 <!-- box / title -->
28 <div class="title">
28 <div class="title">
29 <h5>${_('Dashboard')}</h5>
29 <h5>${_('Dashboard')}</h5>
30 %if h.HasPermissionAny('repository.create','hg.admin')():
30 %if h.HasPermissionAny('hg.admin','hg.create.repository')():
31 <ul class="links">
31 <ul class="links">
32 <li>
32 <li>
33 <span>${h.link_to(u'ADD NEW REPOSITORY',h.url('admin_settings_create_repository'),class_="add_icon")}</span>
33 <span>${h.link_to(u'ADD NEW REPOSITORY',h.url('admin_settings_create_repository'),class_="add_icon")}</span>
34 </li>
34 </li>
35 </ul>
35 </ul>
36 %endif
36 %endif
37 </div>
37 </div>
38 <!-- end box / title -->
38 <!-- end box / title -->
39 <div class="table">
39 <div class="table">
40 <table>
40 <table>
41 <thead>
41 <thead>
42 <tr>
42 <tr>
43 <th class="left">${get_sort(_('Name'))}</th>
43 <th class="left">${get_sort(_('Name'))}</th>
44 <th class="left">${get_sort(_('Description'))}</th>
44 <th class="left">${get_sort(_('Description'))}</th>
45 <th class="left">${get_sort(_('Last change'))}</th>
45 <th class="left">${get_sort(_('Last change'))}</th>
46 <th class="left">${get_sort(_('Tip'))}</th>
46 <th class="left">${get_sort(_('Tip'))}</th>
47 <th class="left">${get_sort(_('Contact'))}</th>
47 <th class="left">${get_sort(_('Contact'))}</th>
48 <th class="left">${_('RSS')}</th>
48 <th class="left">${_('RSS')}</th>
49 <th class="left">${_('Atom')}</th>
49 <th class="left">${_('Atom')}</th>
50 </tr>
50 </tr>
51 </thead>
51 </thead>
52 <tbody>
52 <tbody>
53 %for cnt,repo in enumerate(c.repos_list):
53 %for cnt,repo in enumerate(c.repos_list):
54 %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(repo['name'],'main page check'):
54 %if h.HasRepoPermissionAny('repository.write','repository.read','repository.admin')(repo['name'],'main page check'):
55 <tr class="parity${cnt%2}">
55 <tr class="parity${cnt%2}">
56 <td>
56 <td>
57 %if repo['repo'].dbrepo.private:
57 %if repo['repo'].dbrepo.private:
58 <img alt="${_('private')}" src="/images/icons/lock.png"/>
58 <img alt="${_('private')}" src="/images/icons/lock.png"/>
59 %else:
59 %else:
60 <img alt="${_('public')}" src="/images/icons/lock_open.png"/>
60 <img alt="${_('public')}" src="/images/icons/lock_open.png"/>
61 %endif
61 %endif
62 ${h.link_to(repo['name'],
62 ${h.link_to(repo['name'],
63 h.url('summary_home',repo_name=repo['name']))}</td>
63 h.url('summary_home',repo_name=repo['name']))}</td>
64 <td title="${repo['description']}">${h.truncate(repo['description'],60)}</td>
64 <td title="${repo['description']}">${h.truncate(repo['description'],60)}</td>
65 <td>${h.age(repo['last_change'])}</td>
65 <td>${h.age(repo['last_change'])}</td>
66 <td>${h.link_to_if(repo['rev']>=0,'r%s:%s' % (repo['rev'],repo['tip']),
66 <td>${h.link_to_if(repo['rev']>=0,'r%s:%s' % (repo['rev'],repo['tip']),
67 h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
67 h.url('changeset_home',repo_name=repo['name'],revision=repo['tip']),
68 class_="tooltip",
68 class_="tooltip",
69 tooltip_title=h.tooltip(repo['last_msg']))}</td>
69 tooltip_title=h.tooltip(repo['last_msg']))}</td>
70 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
70 <td title="${repo['contact']}">${h.person(repo['contact'])}</td>
71 <td>
71 <td>
72 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
72 <a title="${_('Subscribe to %s rss feed')%repo['name']}" class="rss_icon" href="${h.url('rss_feed_home',repo_name=repo['name'])}"></a>
73 </td>
73 </td>
74 <td>
74 <td>
75 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
75 <a title="${_('Subscribe to %s atom feed')%repo['name']}" class="atom_icon" href="${h.url('atom_feed_home',repo_name=repo['name'])}"></a>
76 </td>
76 </td>
77 </tr>
77 </tr>
78 %endif
78 %endif
79 %endfor
79 %endfor
80 </tbody>
80 </tbody>
81 </table>
81 </table>
82 </div>
82 </div>
83 </div>
83 </div>
84 </%def>
84 </%def>
@@ -1,76 +1,78 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${_('Sign In to hg-app')}</title>
5 <title>${_('Sign In to hg-app')}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
14
14
15 <!-- scripts -->
15 <!-- scripts -->
16
16
17 </head>
17 </head>
18 <body>
18 <body>
19 <div id="login">
19 <div id="login">
20 <!-- login -->
20 <!-- login -->
21 <div class="title">
21 <div class="title">
22 <h5>${_('Sign In to hg-app')}</h5>
22 <h5>${_('Sign In to hg-app')}</h5>
23 <div class="corner tl"></div>
23 <div class="corner tl"></div>
24 <div class="corner tr"></div>
24 <div class="corner tr"></div>
25 </div>
25 </div>
26 <div class="inner">
26 <div class="inner">
27 ${h.form(h.url.current())}
27 ${h.form(h.url.current())}
28 <div class="form">
28 <div class="form">
29 <!-- fields -->
29 <!-- fields -->
30
30
31 <div class="fields">
31 <div class="fields">
32 <div class="field">
32 <div class="field">
33 <div class="label">
33 <div class="label">
34 <label for="username">${_('Username')}:</label>
34 <label for="username">${_('Username')}:</label>
35 </div>
35 </div>
36 <div class="input">
36 <div class="input">
37 ${h.text('username',class_='focus',size=40)}
37 ${h.text('username',class_='focus',size=40)}
38 </div>
38 </div>
39
39
40 </div>
40 </div>
41 <div class="field">
41 <div class="field">
42 <div class="label">
42 <div class="label">
43 <label for="password">${_('Password')}:</label>
43 <label for="password">${_('Password')}:</label>
44 </div>
44 </div>
45 <div class="input">
45 <div class="input">
46 ${h.password('password',class_='focus',size=40)}
46 ${h.password('password',class_='focus',size=40)}
47 </div>
47 </div>
48
48
49 </div>
49 </div>
50 ##<div class="field">
50 ##<div class="field">
51 ## <div class="checkbox">
51 ## <div class="checkbox">
52 ## <input type="checkbox" id="remember" name="remember" />
52 ## <input type="checkbox" id="remember" name="remember" />
53 ## <label for="remember">Remember me</label>
53 ## <label for="remember">Remember me</label>
54 ## </div>
54 ## </div>
55 ##</div>
55 ##</div>
56 <div class="buttons">
56 <div class="buttons">
57 ${h.submit('sign_in','Sign In',class_="ui-button ui-widget ui-state-default ui-corner-all")}
57 ${h.submit('sign_in','Sign In',class_="ui-button ui-widget ui-state-default ui-corner-all")}
58 </div>
58 </div>
59 </div>
59 </div>
60 <!-- end fields -->
60 <!-- end fields -->
61 <!-- links -->
61 <!-- links -->
62 <div class="links">
62 <div class="links">
63 ${h.link_to(_('Forgot your password ?'),h.url('#'))}
63 ${h.link_to(_('Forgot your password ?'),h.url('#'))}
64 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
64 /
65 /
65 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
66 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
67 %endif
66 </div>
68 </div>
67
69
68 <!-- end links -->
70 <!-- end links -->
69 </div>
71 </div>
70 ${h.end_form()}
72 ${h.end_form()}
71 </div>
73 </div>
72 <!-- end login -->
74 <!-- end login -->
73 </div>
75 </div>
74 </body>
76 </body>
75 </html>
77 </html>
76
78
@@ -1,88 +1,93 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
4 <head>
5 <title>${_('Sign Up to hg-app')}</title>
5 <title>${_('Sign Up to hg-app')}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
8 <meta name="robots" content="index, nofollow"/>
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
14
14
15 <!-- scripts -->
15 <!-- scripts -->
16
16
17 </head>
17 </head>
18 <body>
18 <body>
19 <div id="register">
19 <div id="register">
20
20
21 <div class="title">
21 <div class="title">
22 <h5>${_('Sign Up to hg-app')}</h5>
22 <h5>${_('Sign Up to hg-app')}</h5>
23 <div class="corner tl"></div>
23 <div class="corner tl"></div>
24 <div class="corner tr"></div>
24 <div class="corner tr"></div>
25 </div>
25 </div>
26 <div class="inner">
26 <div class="inner">
27 ${h.form(url('register'))}
27 ${h.form(url('register'))}
28 <div class="form">
28 <div class="form">
29 <!-- fields -->
29 <!-- fields -->
30 <div class="fields">
30 <div class="fields">
31 <div class="field">
31 <div class="field">
32 <div class="label">
32 <div class="label">
33 <label for="username">${_('Username')}:</label>
33 <label for="username">${_('Username')}:</label>
34 </div>
34 </div>
35 <div class="input">
35 <div class="input">
36 ${h.text('username')}
36 ${h.text('username')}
37 </div>
37 </div>
38 </div>
38 </div>
39
39
40 <div class="field">
40 <div class="field">
41 <div class="label">
41 <div class="label">
42 <label for="password">${_('New Password')}:</label>
42 <label for="password">${_('New Password')}:</label>
43 </div>
43 </div>
44 <div class="input">
44 <div class="input">
45 ${h.password('password')}
45 ${h.password('password')}
46 </div>
46 </div>
47 </div>
47 </div>
48
48
49 <div class="field">
49 <div class="field">
50 <div class="label">
50 <div class="label">
51 <label for="name">${_('First Name')}:</label>
51 <label for="name">${_('First Name')}:</label>
52 </div>
52 </div>
53 <div class="input">
53 <div class="input">
54 ${h.text('name')}
54 ${h.text('name')}
55 </div>
55 </div>
56 </div>
56 </div>
57
57
58 <div class="field">
58 <div class="field">
59 <div class="label">
59 <div class="label">
60 <label for="lastname">${_('Last Name')}:</label>
60 <label for="lastname">${_('Last Name')}:</label>
61 </div>
61 </div>
62 <div class="input">
62 <div class="input">
63 ${h.text('lastname')}
63 ${h.text('lastname')}
64 </div>
64 </div>
65 </div>
65 </div>
66
66
67 <div class="field">
67 <div class="field">
68 <div class="label">
68 <div class="label">
69 <label for="email">${_('Email')}:</label>
69 <label for="email">${_('Email')}:</label>
70 </div>
70 </div>
71 <div class="input">
71 <div class="input">
72 ${h.text('email')}
72 ${h.text('email')}
73 </div>
73 </div>
74 </div>
74 </div>
75
75
76 <div class="buttons">
76 <div class="buttons">
77 <div class="nohighlight">
77 <div class="nohighlight">
78 ${h.submit('sign_up','Sign Up',class_="ui-button ui-widget ui-state-default ui-corner-all")}
78 ${h.submit('sign_up','Sign Up',class_="ui-button ui-widget ui-state-default ui-corner-all")}
79 %if c.auto_active:
80 <div class="activation_msg">${_('Your account will be activated right after registration')}</div>
81 %else:
82 <div class="activation_msg">${_('Your account must wait for activation by administrator')}</div>
83 %endif
79 </div>
84 </div>
80 </div>
85 </div>
81 </div>
86 </div>
82 </div>
87 </div>
83 ${h.end_form()}
88 ${h.end_form()}
84 </div>
89 </div>
85 </div>
90 </div>
86 </body>
91 </body>
87 </html>
92 </html>
88
93
@@ -1,23 +1,24 b''
1 """Setup the pylons_app application"""
1 """Setup the pylons_app application"""
2
2
3 from os.path import dirname as dn, join as jn
3 from os.path import dirname as dn, join as jn
4 from pylons_app.config.environment import load_environment
4 from pylons_app.config.environment import load_environment
5 from pylons_app.lib.db_manage import DbManage
5 from pylons_app.lib.db_manage import DbManage
6 import logging
6 import logging
7 import os
7 import os
8 import sys
8 import sys
9
9
10 log = logging.getLogger(__name__)
10 log = logging.getLogger(__name__)
11
11
12 ROOT = dn(dn(os.path.realpath(__file__)))
12 ROOT = dn(dn(os.path.realpath(__file__)))
13 sys.path.append(ROOT)
13 sys.path.append(ROOT)
14
14
15 def setup_app(command, conf, vars):
15 def setup_app(command, conf, vars):
16 """Place any commands to setup pylons_app here"""
16 """Place any commands to setup pylons_app here"""
17 dbmanage = DbManage(log_sql=True)
17 dbmanage = DbManage(log_sql=True)
18 dbmanage.create_tables(override=True)
18 dbmanage.create_tables(override=True)
19 dbmanage.config_prompt()
19 dbmanage.config_prompt()
20 dbmanage.admin_prompt()
20 dbmanage.admin_prompt()
21 dbmanage.create_permissions()
21 dbmanage.create_permissions()
22 dbmanage.populate_default_permissions()
22 load_environment(conf.global_conf, conf.local_conf, initial=True)
23 load_environment(conf.global_conf, conf.local_conf, initial=True)
23
24
General Comments 0
You need to be logged in to leave comments. Login now