##// END OF EJS Templates
implemented #89 google analytics code
marcink -
r890:042d3868 beta
parent child Browse files
Show More
@@ -1,340 +1,351 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.settings
3 rhodecode.controllers.admin.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 settings controller for rhodecode admin
6 settings controller for rhodecode admin
7
7
8 :created_on: Jul 14, 2010
8 :created_on: Jul 14, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software; you can redistribute it and/or
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import logging
29 import traceback
30 import formencode
31
32 from operator import itemgetter
28 from formencode import htmlfill
33 from formencode import htmlfill
29 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
34 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
30 config
35 config
31 from pylons.controllers.util import abort, redirect
36 from pylons.controllers.util import abort, redirect
32 from pylons.i18n.translation import _
37 from pylons.i18n.translation import _
38
33 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
34 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
35 HasPermissionAnyDecorator, NotAnonymous
41 HasPermissionAnyDecorator, NotAnonymous
36 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.base import BaseController, render
37 from rhodecode.lib.celerylib import tasks, run_task
43 from rhodecode.lib.celerylib import tasks, run_task
38 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
44 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
39 set_rhodecode_config
45 set_rhodecode_config
40 from rhodecode.model.db import RhodeCodeUi, Repository
46 from rhodecode.model.db import RhodeCodeUi, Repository
41 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
42 ApplicationUiSettingsForm
48 ApplicationUiSettingsForm
43 from rhodecode.model.scm import ScmModel
49 from rhodecode.model.scm import ScmModel
44 from rhodecode.model.settings import SettingsModel
50 from rhodecode.model.settings import SettingsModel
45 from rhodecode.model.user import UserModel
51 from rhodecode.model.user import UserModel
52
46 from sqlalchemy import func
53 from sqlalchemy import func
47 import formencode
54
48 import logging
49 import traceback
50
55
51 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
52
57
53
58
54 class SettingsController(BaseController):
59 class SettingsController(BaseController):
55 """REST Controller styled on the Atom Publishing Protocol"""
60 """REST Controller styled on the Atom Publishing Protocol"""
56 # To properly map this controller, ensure your config/routing.py
61 # To properly map this controller, ensure your config/routing.py
57 # file has a resource setup:
62 # file has a resource setup:
58 # map.resource('setting', 'settings', controller='admin/settings',
63 # map.resource('setting', 'settings', controller='admin/settings',
59 # path_prefix='/admin', name_prefix='admin_')
64 # path_prefix='/admin', name_prefix='admin_')
60
65
61
66
62 @LoginRequired()
67 @LoginRequired()
63 def __before__(self):
68 def __before__(self):
64 c.admin_user = session.get('admin_user')
69 c.admin_user = session.get('admin_user')
65 c.admin_username = session.get('admin_username')
70 c.admin_username = session.get('admin_username')
66 super(SettingsController, self).__before__()
71 super(SettingsController, self).__before__()
67
72
68
73
69 @HasPermissionAllDecorator('hg.admin')
74 @HasPermissionAllDecorator('hg.admin')
70 def index(self, format='html'):
75 def index(self, format='html'):
71 """GET /admin/settings: All items in the collection"""
76 """GET /admin/settings: All items in the collection"""
72 # url('admin_settings')
77 # url('admin_settings')
73
78
74 defaults = SettingsModel().get_app_settings()
79 defaults = SettingsModel().get_app_settings()
75 defaults.update(self.get_hg_ui_settings())
80 defaults.update(self.get_hg_ui_settings())
76 return htmlfill.render(
81 return htmlfill.render(
77 render('admin/settings/settings.html'),
82 render('admin/settings/settings.html'),
78 defaults=defaults,
83 defaults=defaults,
79 encoding="UTF-8",
84 encoding="UTF-8",
80 force_defaults=False
85 force_defaults=False
81 )
86 )
82
87
83 @HasPermissionAllDecorator('hg.admin')
88 @HasPermissionAllDecorator('hg.admin')
84 def create(self):
89 def create(self):
85 """POST /admin/settings: Create a new item"""
90 """POST /admin/settings: Create a new item"""
86 # url('admin_settings')
91 # url('admin_settings')
87
92
88 @HasPermissionAllDecorator('hg.admin')
93 @HasPermissionAllDecorator('hg.admin')
89 def new(self, format='html'):
94 def new(self, format='html'):
90 """GET /admin/settings/new: Form to create a new item"""
95 """GET /admin/settings/new: Form to create a new item"""
91 # url('admin_new_setting')
96 # url('admin_new_setting')
92
97
93 @HasPermissionAllDecorator('hg.admin')
98 @HasPermissionAllDecorator('hg.admin')
94 def update(self, setting_id):
99 def update(self, setting_id):
95 """PUT /admin/settings/setting_id: Update an existing item"""
100 """PUT /admin/settings/setting_id: Update an existing item"""
96 # Forms posted to this method should contain a hidden field:
101 # Forms posted to this method should contain a hidden field:
97 # <input type="hidden" name="_method" value="PUT" />
102 # <input type="hidden" name="_method" value="PUT" />
98 # Or using helpers:
103 # Or using helpers:
99 # h.form(url('admin_setting', setting_id=ID),
104 # h.form(url('admin_setting', setting_id=ID),
100 # method='put')
105 # method='put')
101 # url('admin_setting', setting_id=ID)
106 # url('admin_setting', setting_id=ID)
102 if setting_id == 'mapping':
107 if setting_id == 'mapping':
103 rm_obsolete = request.POST.get('destroy', False)
108 rm_obsolete = request.POST.get('destroy', False)
104 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
109 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
105
110
106 initial = ScmModel().repo_scan(g.paths[0][1], g.baseui)
111 initial = ScmModel().repo_scan(g.paths[0][1], g.baseui)
107 for repo_name in initial.keys():
112 for repo_name in initial.keys():
108 invalidate_cache('get_repo_cached_%s' % repo_name)
113 invalidate_cache('get_repo_cached_%s' % repo_name)
109
114
110 repo2db_mapper(initial, rm_obsolete)
115 repo2db_mapper(initial, rm_obsolete)
111
116
112 h.flash(_('Repositories successfully rescanned'), category='success')
117 h.flash(_('Repositories successfully rescanned'), category='success')
113
118
114 if setting_id == 'whoosh':
119 if setting_id == 'whoosh':
115 repo_location = self.get_hg_ui_settings()['paths_root_path']
120 repo_location = self.get_hg_ui_settings()['paths_root_path']
116 full_index = request.POST.get('full_index', False)
121 full_index = request.POST.get('full_index', False)
117 task = run_task(tasks.whoosh_index, repo_location, full_index)
122 task = run_task(tasks.whoosh_index, repo_location, full_index)
118
123
119 h.flash(_('Whoosh reindex task scheduled'), category='success')
124 h.flash(_('Whoosh reindex task scheduled'), category='success')
120 if setting_id == 'global':
125 if setting_id == 'global':
121
126
122 application_form = ApplicationSettingsForm()()
127 application_form = ApplicationSettingsForm()()
123 try:
128 try:
124 form_result = application_form.to_python(dict(request.POST))
129 form_result = application_form.to_python(dict(request.POST))
125 settings_model = SettingsModel()
130 settings_model = SettingsModel()
131
126 try:
132 try:
127 hgsettings1 = settings_model.get('title')
133 hgsettings1 = settings_model.get('title')
128 hgsettings1.app_settings_value = form_result['rhodecode_title']
134 hgsettings1.app_settings_value = form_result['rhodecode_title']
129
135
130 hgsettings2 = settings_model.get('realm')
136 hgsettings2 = settings_model.get('realm')
131 hgsettings2.app_settings_value = form_result['rhodecode_realm']
137 hgsettings2.app_settings_value = form_result['rhodecode_realm']
132
138
139 hgsettings3 = settings_model.get('ga_code')
140 hgsettings3.app_settings_value = form_result['ga_code']
141
142
133
143
134 self.sa.add(hgsettings1)
144 self.sa.add(hgsettings1)
135 self.sa.add(hgsettings2)
145 self.sa.add(hgsettings2)
146 self.sa.add(hgsettings3)
136 self.sa.commit()
147 self.sa.commit()
137 set_rhodecode_config(config)
148 set_rhodecode_config(config)
138 h.flash(_('Updated application settings'),
149 h.flash(_('Updated application settings'),
139 category='success')
150 category='success')
140
151
141 except:
152 except:
142 log.error(traceback.format_exc())
153 log.error(traceback.format_exc())
143 h.flash(_('error occurred during updating application settings'),
154 h.flash(_('error occurred during updating application settings'),
144 category='error')
155 category='error')
145
156
146 self.sa.rollback()
157 self.sa.rollback()
147
158
148
159
149 except formencode.Invalid, errors:
160 except formencode.Invalid, errors:
150 return htmlfill.render(
161 return htmlfill.render(
151 render('admin/settings/settings.html'),
162 render('admin/settings/settings.html'),
152 defaults=errors.value,
163 defaults=errors.value,
153 errors=errors.error_dict or {},
164 errors=errors.error_dict or {},
154 prefix_error=False,
165 prefix_error=False,
155 encoding="UTF-8")
166 encoding="UTF-8")
156
167
157 if setting_id == 'mercurial':
168 if setting_id == 'mercurial':
158 application_form = ApplicationUiSettingsForm()()
169 application_form = ApplicationUiSettingsForm()()
159 try:
170 try:
160 form_result = application_form.to_python(dict(request.POST))
171 form_result = application_form.to_python(dict(request.POST))
161
172
162 try:
173 try:
163
174
164 hgsettings1 = self.sa.query(RhodeCodeUi)\
175 hgsettings1 = self.sa.query(RhodeCodeUi)\
165 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
176 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
166 hgsettings1.ui_value = form_result['web_push_ssl']
177 hgsettings1.ui_value = form_result['web_push_ssl']
167
178
168 hgsettings2 = self.sa.query(RhodeCodeUi)\
179 hgsettings2 = self.sa.query(RhodeCodeUi)\
169 .filter(RhodeCodeUi.ui_key == '/').one()
180 .filter(RhodeCodeUi.ui_key == '/').one()
170 hgsettings2.ui_value = form_result['paths_root_path']
181 hgsettings2.ui_value = form_result['paths_root_path']
171
182
172
183
173 #HOOKS
184 #HOOKS
174 hgsettings3 = self.sa.query(RhodeCodeUi)\
185 hgsettings3 = self.sa.query(RhodeCodeUi)\
175 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
186 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
176 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
187 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
177
188
178 hgsettings4 = self.sa.query(RhodeCodeUi)\
189 hgsettings4 = self.sa.query(RhodeCodeUi)\
179 .filter(RhodeCodeUi.ui_key == 'changegroup.repo_size').one()
190 .filter(RhodeCodeUi.ui_key == 'changegroup.repo_size').one()
180 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
191 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
181
192
182 hgsettings5 = self.sa.query(RhodeCodeUi)\
193 hgsettings5 = self.sa.query(RhodeCodeUi)\
183 .filter(RhodeCodeUi.ui_key == 'pretxnchangegroup.push_logger').one()
194 .filter(RhodeCodeUi.ui_key == 'pretxnchangegroup.push_logger').one()
184 hgsettings5.ui_active = bool(form_result['hooks_pretxnchangegroup_push_logger'])
195 hgsettings5.ui_active = bool(form_result['hooks_pretxnchangegroup_push_logger'])
185
196
186 hgsettings6 = self.sa.query(RhodeCodeUi)\
197 hgsettings6 = self.sa.query(RhodeCodeUi)\
187 .filter(RhodeCodeUi.ui_key == 'preoutgoing.pull_logger').one()
198 .filter(RhodeCodeUi.ui_key == 'preoutgoing.pull_logger').one()
188 hgsettings6.ui_active = bool(form_result['hooks_preoutgoing_pull_logger'])
199 hgsettings6.ui_active = bool(form_result['hooks_preoutgoing_pull_logger'])
189
200
190
201
191 self.sa.add(hgsettings1)
202 self.sa.add(hgsettings1)
192 self.sa.add(hgsettings2)
203 self.sa.add(hgsettings2)
193 self.sa.add(hgsettings3)
204 self.sa.add(hgsettings3)
194 self.sa.add(hgsettings4)
205 self.sa.add(hgsettings4)
195 self.sa.add(hgsettings5)
206 self.sa.add(hgsettings5)
196 self.sa.add(hgsettings6)
207 self.sa.add(hgsettings6)
197 self.sa.commit()
208 self.sa.commit()
198
209
199 h.flash(_('Updated mercurial settings'),
210 h.flash(_('Updated mercurial settings'),
200 category='success')
211 category='success')
201
212
202 except:
213 except:
203 log.error(traceback.format_exc())
214 log.error(traceback.format_exc())
204 h.flash(_('error occurred during updating application settings'),
215 h.flash(_('error occurred during updating application settings'),
205 category='error')
216 category='error')
206
217
207 self.sa.rollback()
218 self.sa.rollback()
208
219
209
220
210 except formencode.Invalid, errors:
221 except formencode.Invalid, errors:
211 return htmlfill.render(
222 return htmlfill.render(
212 render('admin/settings/settings.html'),
223 render('admin/settings/settings.html'),
213 defaults=errors.value,
224 defaults=errors.value,
214 errors=errors.error_dict or {},
225 errors=errors.error_dict or {},
215 prefix_error=False,
226 prefix_error=False,
216 encoding="UTF-8")
227 encoding="UTF-8")
217
228
218
229
219
230
220 return redirect(url('admin_settings'))
231 return redirect(url('admin_settings'))
221
232
222 @HasPermissionAllDecorator('hg.admin')
233 @HasPermissionAllDecorator('hg.admin')
223 def delete(self, setting_id):
234 def delete(self, setting_id):
224 """DELETE /admin/settings/setting_id: Delete an existing item"""
235 """DELETE /admin/settings/setting_id: Delete an existing item"""
225 # Forms posted to this method should contain a hidden field:
236 # Forms posted to this method should contain a hidden field:
226 # <input type="hidden" name="_method" value="DELETE" />
237 # <input type="hidden" name="_method" value="DELETE" />
227 # Or using helpers:
238 # Or using helpers:
228 # h.form(url('admin_setting', setting_id=ID),
239 # h.form(url('admin_setting', setting_id=ID),
229 # method='delete')
240 # method='delete')
230 # url('admin_setting', setting_id=ID)
241 # url('admin_setting', setting_id=ID)
231
242
232 @HasPermissionAllDecorator('hg.admin')
243 @HasPermissionAllDecorator('hg.admin')
233 def show(self, setting_id, format='html'):
244 def show(self, setting_id, format='html'):
234 """GET /admin/settings/setting_id: Show a specific item"""
245 """GET /admin/settings/setting_id: Show a specific item"""
235 # url('admin_setting', setting_id=ID)
246 # url('admin_setting', setting_id=ID)
236
247
237 @HasPermissionAllDecorator('hg.admin')
248 @HasPermissionAllDecorator('hg.admin')
238 def edit(self, setting_id, format='html'):
249 def edit(self, setting_id, format='html'):
239 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
250 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
240 # url('admin_edit_setting', setting_id=ID)
251 # url('admin_edit_setting', setting_id=ID)
241
252
242 @NotAnonymous()
253 @NotAnonymous()
243 def my_account(self):
254 def my_account(self):
244 """
255 """
245 GET /_admin/my_account Displays info about my account
256 GET /_admin/my_account Displays info about my account
246 """
257 """
247 # url('admin_settings_my_account')
258 # url('admin_settings_my_account')
248
259
249 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
260 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
250 all_repos = self.sa.query(Repository)\
261 all_repos = self.sa.query(Repository)\
251 .filter(Repository.user_id == c.user.user_id)\
262 .filter(Repository.user_id == c.user.user_id)\
252 .order_by(func.lower(Repository.repo_name))\
263 .order_by(func.lower(Repository.repo_name))\
253 .all()
264 .all()
254
265
255 c.user_repos = ScmModel().get_repos(all_repos)
266 c.user_repos = ScmModel().get_repos(all_repos)
256
267
257 if c.user.username == 'default':
268 if c.user.username == 'default':
258 h.flash(_("You can't edit this user since it's"
269 h.flash(_("You can't edit this user since it's"
259 " crucial for entire application"), category='warning')
270 " crucial for entire application"), category='warning')
260 return redirect(url('users'))
271 return redirect(url('users'))
261
272
262 defaults = c.user.get_dict()
273 defaults = c.user.get_dict()
263 return htmlfill.render(
274 return htmlfill.render(
264 render('admin/users/user_edit_my_account.html'),
275 render('admin/users/user_edit_my_account.html'),
265 defaults=defaults,
276 defaults=defaults,
266 encoding="UTF-8",
277 encoding="UTF-8",
267 force_defaults=False
278 force_defaults=False
268 )
279 )
269
280
270 def my_account_update(self):
281 def my_account_update(self):
271 """PUT /_admin/my_account_update: Update an existing item"""
282 """PUT /_admin/my_account_update: Update an existing item"""
272 # Forms posted to this method should contain a hidden field:
283 # Forms posted to this method should contain a hidden field:
273 # <input type="hidden" name="_method" value="PUT" />
284 # <input type="hidden" name="_method" value="PUT" />
274 # Or using helpers:
285 # Or using helpers:
275 # h.form(url('admin_settings_my_account_update'),
286 # h.form(url('admin_settings_my_account_update'),
276 # method='put')
287 # method='put')
277 # url('admin_settings_my_account_update', id=ID)
288 # url('admin_settings_my_account_update', id=ID)
278 user_model = UserModel()
289 user_model = UserModel()
279 uid = c.rhodecode_user.user_id
290 uid = c.rhodecode_user.user_id
280 _form = UserForm(edit=True, old_data={'user_id':uid,
291 _form = UserForm(edit=True, old_data={'user_id':uid,
281 'email':c.rhodecode_user.email})()
292 'email':c.rhodecode_user.email})()
282 form_result = {}
293 form_result = {}
283 try:
294 try:
284 form_result = _form.to_python(dict(request.POST))
295 form_result = _form.to_python(dict(request.POST))
285 user_model.update_my_account(uid, form_result)
296 user_model.update_my_account(uid, form_result)
286 h.flash(_('Your account was updated successfully'),
297 h.flash(_('Your account was updated successfully'),
287 category='success')
298 category='success')
288
299
289 except formencode.Invalid, errors:
300 except formencode.Invalid, errors:
290 c.user = user_model.get(c.rhodecode_user.user_id, cache=False)
301 c.user = user_model.get(c.rhodecode_user.user_id, cache=False)
291 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
302 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
292 all_repos = self.sa.query(Repository)\
303 all_repos = self.sa.query(Repository)\
293 .filter(Repository.user_id == c.user.user_id)\
304 .filter(Repository.user_id == c.user.user_id)\
294 .order_by(func.lower(Repository.repo_name))\
305 .order_by(func.lower(Repository.repo_name))\
295 .all()
306 .all()
296 c.user_repos = ScmModel().get_repos(all_repos)
307 c.user_repos = ScmModel().get_repos(all_repos)
297
308
298 return htmlfill.render(
309 return htmlfill.render(
299 render('admin/users/user_edit_my_account.html'),
310 render('admin/users/user_edit_my_account.html'),
300 defaults=errors.value,
311 defaults=errors.value,
301 errors=errors.error_dict or {},
312 errors=errors.error_dict or {},
302 prefix_error=False,
313 prefix_error=False,
303 encoding="UTF-8")
314 encoding="UTF-8")
304 except Exception:
315 except Exception:
305 log.error(traceback.format_exc())
316 log.error(traceback.format_exc())
306 h.flash(_('error occurred during update of user %s') \
317 h.flash(_('error occurred during update of user %s') \
307 % form_result.get('username'), category='error')
318 % form_result.get('username'), category='error')
308
319
309 return redirect(url('my_account'))
320 return redirect(url('my_account'))
310
321
311 @NotAnonymous()
322 @NotAnonymous()
312 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
323 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
313 def create_repository(self):
324 def create_repository(self):
314 """GET /_admin/create_repository: Form to create a new item"""
325 """GET /_admin/create_repository: Form to create a new item"""
315 new_repo = request.GET.get('repo', '')
326 new_repo = request.GET.get('repo', '')
316 c.new_repo = h.repo_name_slug(new_repo)
327 c.new_repo = h.repo_name_slug(new_repo)
317
328
318 return render('admin/repos/repo_add_create_repository.html')
329 return render('admin/repos/repo_add_create_repository.html')
319
330
320 def get_hg_ui_settings(self):
331 def get_hg_ui_settings(self):
321 ret = self.sa.query(RhodeCodeUi).all()
332 ret = self.sa.query(RhodeCodeUi).all()
322
333
323 if not ret:
334 if not ret:
324 raise Exception('Could not get application ui settings !')
335 raise Exception('Could not get application ui settings !')
325 settings = {}
336 settings = {}
326 for each in ret:
337 for each in ret:
327 k = each.ui_key
338 k = each.ui_key
328 v = each.ui_value
339 v = each.ui_value
329 if k == '/':
340 if k == '/':
330 k = 'root_path'
341 k = 'root_path'
331
342
332 if k.find('.') != -1:
343 if k.find('.') != -1:
333 k = k.replace('.', '_')
344 k = k.replace('.', '_')
334
345
335 if each.ui_section == 'hooks':
346 if each.ui_section == 'hooks':
336 v = each.ui_active
347 v = each.ui_active
337
348
338 settings[each.ui_section + '_' + k] = v
349 settings[each.ui_section + '_' + k] = v
339
350
340 return settings
351 return settings
@@ -1,52 +1,53 b''
1 """The base Controller API
1 """The base Controller API
2
2
3 Provides the BaseController class for subclassing.
3 Provides the BaseController class for subclassing.
4 """
4 """
5 from pylons import config, tmpl_context as c, request, session
5 from pylons import config, tmpl_context as c, request, session
6 from pylons.controllers import WSGIController
6 from pylons.controllers import WSGIController
7 from pylons.templating import render_mako as render
7 from pylons.templating import render_mako as render
8 from rhodecode import __version__
8 from rhodecode import __version__
9 from rhodecode.lib import auth
9 from rhodecode.lib import auth
10 from rhodecode.lib.utils import get_repo_slug
10 from rhodecode.lib.utils import get_repo_slug
11 from rhodecode.model import meta
11 from rhodecode.model import meta
12 from rhodecode.model.scm import ScmModel
12 from rhodecode.model.scm import ScmModel
13 from rhodecode import BACKENDS
13 from rhodecode import BACKENDS
14
14
15 class BaseController(WSGIController):
15 class BaseController(WSGIController):
16
16
17 def __before__(self):
17 def __before__(self):
18 c.rhodecode_version = __version__
18 c.rhodecode_version = __version__
19 c.rhodecode_name = config['rhodecode_title']
19 c.rhodecode_name = config.get('rhodecode_title')
20 c.ga_code = config.get('rhodeocode_ga_code')
20 c.repo_name = get_repo_slug(request)
21 c.repo_name = get_repo_slug(request)
21 c.cached_repo_list = ScmModel().get_repos()
22 c.cached_repo_list = ScmModel().get_repos()
22 c.backends = BACKENDS.keys()
23 c.backends = BACKENDS.keys()
23 self.cut_off_limit = int(config['cut_off_limit'])
24 self.cut_off_limit = int(config.get('cut_off_limit'))
24 self.sa = meta.Session()
25 self.sa = meta.Session()
25 scm_model = ScmModel(self.sa)
26 scm_model = ScmModel(self.sa)
26 #c.unread_journal = scm_model.get_unread_journal()
27 #c.unread_journal = scm_model.get_unread_journal()
27
28
28 if c.repo_name:
29 if c.repo_name:
29 cached_repo = scm_model.get(c.repo_name)
30 cached_repo = scm_model.get(c.repo_name)
30 if cached_repo:
31 if cached_repo:
31 c.repository_tags = cached_repo.tags
32 c.repository_tags = cached_repo.tags
32 c.repository_branches = cached_repo.branches
33 c.repository_branches = cached_repo.branches
33 c.repository_followers = scm_model.get_followers(cached_repo.dbrepo.repo_id)
34 c.repository_followers = scm_model.get_followers(cached_repo.dbrepo.repo_id)
34 c.repository_forks = scm_model.get_forks(cached_repo.dbrepo.repo_id)
35 c.repository_forks = scm_model.get_forks(cached_repo.dbrepo.repo_id)
35 else:
36 else:
36 c.repository_tags = {}
37 c.repository_tags = {}
37 c.repository_branches = {}
38 c.repository_branches = {}
38 c.repository_followers = 0
39 c.repository_followers = 0
39 c.repository_forks = 0
40 c.repository_forks = 0
40
41
41
42
42 def __call__(self, environ, start_response):
43 def __call__(self, environ, start_response):
43 """Invoke the Controller"""
44 """Invoke the Controller"""
44 # WSGIController.__call__ dispatches to the Controller method
45 # WSGIController.__call__ dispatches to the Controller method
45 # the request is routed to. This routing information is
46 # the request is routed to. This routing information is
46 # available in environ['pylons.routes_dict']
47 # available in environ['pylons.routes_dict']
47 try:
48 try:
48 #putting this here makes sure that we update permissions every time
49 #putting this here makes sure that we update permissions every time
49 self.rhodecode_user = c.rhodecode_user = auth.get_user(session)
50 self.rhodecode_user = c.rhodecode_user = auth.get_user(session)
50 return WSGIController.__call__(self, environ, start_response)
51 return WSGIController.__call__(self, environ, start_response)
51 finally:
52 finally:
52 meta.Session.remove()
53 meta.Session.remove()
@@ -1,477 +1,492 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.db_manage
3 rhodecode.lib.db_manage
4 ~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Database creation, and setup module for RhodeCode. Used for creation
6 Database creation, and setup module for RhodeCode. Used for creation
7 of database as well as for migration operations
7 of database as well as for migration operations
8
8
9 :created_on: Apr 10, 2010
9 :created_on: Apr 10, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software; you can redistribute it and/or
14 # This program is free software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; version 2
16 # as published by the Free Software Foundation; version 2
17 # of the License or (at your opinion) any later version of the license.
17 # of the License or (at your opinion) any later version of the license.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27 # MA 02110-1301, USA.
27 # MA 02110-1301, USA.
28
28
29 import os
29 import os
30 import sys
30 import sys
31 import uuid
31 import uuid
32 import logging
32 import logging
33 from os.path import dirname as dn, join as jn
33 from os.path import dirname as dn, join as jn
34
34
35 from rhodecode import __dbversion__
35 from rhodecode import __dbversion__
36 from rhodecode.model import meta
36 from rhodecode.model import meta
37
37
38 from rhodecode.lib.auth import get_crypt_password
38 from rhodecode.lib.auth import get_crypt_password
39 from rhodecode.lib.utils import ask_ok
39 from rhodecode.lib.utils import ask_ok
40 from rhodecode.model import init_model
40 from rhodecode.model import init_model
41 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
41 from rhodecode.model.db import User, Permission, RhodeCodeUi, RhodeCodeSettings, \
42 UserToPerm, DbMigrateVersion
42 UserToPerm, DbMigrateVersion
43
43
44 from sqlalchemy.engine import create_engine
44 from sqlalchemy.engine import create_engine
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48 class DbManage(object):
48 class DbManage(object):
49 def __init__(self, log_sql, dbconf, root, tests=False):
49 def __init__(self, log_sql, dbconf, root, tests=False):
50 self.dbname = dbconf.split('/')[-1]
50 self.dbname = dbconf.split('/')[-1]
51 self.tests = tests
51 self.tests = tests
52 self.root = root
52 self.root = root
53 self.dburi = dbconf
53 self.dburi = dbconf
54 engine = create_engine(self.dburi, echo=log_sql)
54 engine = create_engine(self.dburi, echo=log_sql)
55 init_model(engine)
55 init_model(engine)
56 self.sa = meta.Session()
56 self.sa = meta.Session()
57 self.db_exists = False
57 self.db_exists = False
58
58
59 def check_for_db(self, override):
59 def check_for_db(self, override):
60 db_path = jn(self.root, self.dbname)
60 db_path = jn(self.root, self.dbname)
61 if self.dburi.startswith('sqlite'):
61 if self.dburi.startswith('sqlite'):
62 log.info('checking for existing db in %s', db_path)
62 log.info('checking for existing db in %s', db_path)
63 if os.path.isfile(db_path):
63 if os.path.isfile(db_path):
64
64
65 self.db_exists = True
65 self.db_exists = True
66 if not override:
66 if not override:
67 raise Exception('database already exists')
67 raise Exception('database already exists')
68
68
69 def create_tables(self, override=False):
69 def create_tables(self, override=False):
70 """Create a auth database
70 """Create a auth database
71 """
71 """
72
72
73 self.check_for_db(override)
73 self.check_for_db(override)
74 if self.db_exists:
74 if self.db_exists:
75 log.info("database exist and it's going to be destroyed")
75 log.info("database exist and it's going to be destroyed")
76 if self.tests:
76 if self.tests:
77 destroy = True
77 destroy = True
78 else:
78 else:
79 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
79 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
80 if not destroy:
80 if not destroy:
81 sys.exit()
81 sys.exit()
82 if self.db_exists and destroy:
82 if self.db_exists and destroy:
83 os.remove(jn(self.root, self.dbname))
83 os.remove(jn(self.root, self.dbname))
84 checkfirst = not override
84 checkfirst = not override
85 meta.Base.metadata.create_all(checkfirst=checkfirst)
85 meta.Base.metadata.create_all(checkfirst=checkfirst)
86 log.info('Created tables for %s', self.dbname)
86 log.info('Created tables for %s', self.dbname)
87
87
88
88
89
89
90 def set_db_version(self):
90 def set_db_version(self):
91 try:
91 try:
92 ver = DbMigrateVersion()
92 ver = DbMigrateVersion()
93 ver.version = __dbversion__
93 ver.version = __dbversion__
94 ver.repository_id = 'rhodecode_db_migrations'
94 ver.repository_id = 'rhodecode_db_migrations'
95 ver.repository_path = 'versions'
95 ver.repository_path = 'versions'
96 self.sa.add(ver)
96 self.sa.add(ver)
97 self.sa.commit()
97 self.sa.commit()
98 except:
98 except:
99 self.sa.rollback()
99 self.sa.rollback()
100 raise
100 raise
101 log.info('db version set to: %s', __dbversion__)
101 log.info('db version set to: %s', __dbversion__)
102
102
103
103
104 def upgrade(self):
104 def upgrade(self):
105 """Upgrades given database schema to given revision following
105 """Upgrades given database schema to given revision following
106 all needed steps,
106 all needed steps,
107
107
108 :param revision: revision to upgrade to
108 :param revision: revision to upgrade to
109 """
109 """
110
110
111 from rhodecode.lib.dbmigrate.migrate.versioning import api
111 from rhodecode.lib.dbmigrate.migrate.versioning import api
112 from rhodecode.lib.dbmigrate.migrate.exceptions import \
112 from rhodecode.lib.dbmigrate.migrate.exceptions import \
113 DatabaseNotControlledError
113 DatabaseNotControlledError
114
114
115 upgrade = ask_ok('You are about to perform database upgrade, make '
115 upgrade = ask_ok('You are about to perform database upgrade, make '
116 'sure You backed up your database before. '
116 'sure You backed up your database before. '
117 'Continue ? [y/n]')
117 'Continue ? [y/n]')
118 if not upgrade:
118 if not upgrade:
119 sys.exit('Nothing done')
119 sys.exit('Nothing done')
120
120
121 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
121 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
122 'rhodecode/lib/dbmigrate')
122 'rhodecode/lib/dbmigrate')
123 db_uri = self.dburi
123 db_uri = self.dburi
124
124
125 try:
125 try:
126 curr_version = api.db_version(db_uri, repository_path)
126 curr_version = api.db_version(db_uri, repository_path)
127 msg = ('Found current database under version'
127 msg = ('Found current database under version'
128 ' control with version %s' % curr_version)
128 ' control with version %s' % curr_version)
129
129
130 except (RuntimeError, DatabaseNotControlledError), e:
130 except (RuntimeError, DatabaseNotControlledError), e:
131 curr_version = 1
131 curr_version = 1
132 msg = ('Current database is not under version control. Setting'
132 msg = ('Current database is not under version control. Setting'
133 ' as version %s' % curr_version)
133 ' as version %s' % curr_version)
134 api.version_control(db_uri, repository_path, curr_version)
134 api.version_control(db_uri, repository_path, curr_version)
135
135
136 print (msg)
136 print (msg)
137
137
138 if curr_version == __dbversion__:
138 if curr_version == __dbversion__:
139 sys.exit('This database is already at the newest version')
139 sys.exit('This database is already at the newest version')
140
140
141 #======================================================================
141 #======================================================================
142 # UPGRADE STEPS
142 # UPGRADE STEPS
143 #======================================================================
143 #======================================================================
144 class UpgradeSteps(object):
144 class UpgradeSteps(object):
145
145
146 def __init__(self, klass):
146 def __init__(self, klass):
147 self.klass = klass
147 self.klass = klass
148
148
149 def step_0(self):
149 def step_0(self):
150 #step 0 is the schema upgrade, and than follow proper upgrades
150 #step 0 is the schema upgrade, and than follow proper upgrades
151 print ('attempting to do database upgrade to version %s' \
151 print ('attempting to do database upgrade to version %s' \
152 % __dbversion__)
152 % __dbversion__)
153 api.upgrade(db_uri, repository_path, __dbversion__)
153 api.upgrade(db_uri, repository_path, __dbversion__)
154 print ('Schema upgrade completed')
154 print ('Schema upgrade completed')
155
155
156 def step_1(self):
156 def step_1(self):
157 pass
157 pass
158
158
159 def step_2(self):
159 def step_2(self):
160 print ('Patching repo paths for newer version of RhodeCode')
160 print ('Patching repo paths for newer version of RhodeCode')
161 self.klass.fix_repo_paths()
161 self.klass.fix_repo_paths()
162
162
163 print ('Patching default user of RhodeCode')
163 print ('Patching default user of RhodeCode')
164 self.klass.fix_default_user()
164 self.klass.fix_default_user()
165
165
166 log.info('Changing ui settings')
166 log.info('Changing ui settings')
167 self.klass.create_ui_settings()
167 self.klass.create_ui_settings()
168
168
169 def step_3(self):
170 print ('Adding additional settings into RhodeCode db')
171 self.klass.fix_settings()
169
172
170 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
173 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
171
174
172 #CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
175 #CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
173 for step in upgrade_steps:
176 for step in upgrade_steps:
174 print ('performing upgrade step %s' % step)
177 print ('performing upgrade step %s' % step)
175 callable = getattr(UpgradeSteps(self), 'step_%s' % step)()
178 callable = getattr(UpgradeSteps(self), 'step_%s' % step)()
176
179
177
180
178
181
179 def fix_repo_paths(self):
182 def fix_repo_paths(self):
180 """Fixes a old rhodecode version path into new one without a '*'
183 """Fixes a old rhodecode version path into new one without a '*'
181 """
184 """
182
185
183 paths = self.sa.query(RhodeCodeUi)\
186 paths = self.sa.query(RhodeCodeUi)\
184 .filter(RhodeCodeUi.ui_key == '/')\
187 .filter(RhodeCodeUi.ui_key == '/')\
185 .scalar()
188 .scalar()
186
189
187 paths.ui_value = paths.ui_value.replace('*', '')
190 paths.ui_value = paths.ui_value.replace('*', '')
188
191
189 try:
192 try:
190 self.sa.add(paths)
193 self.sa.add(paths)
191 self.sa.commit()
194 self.sa.commit()
192 except:
195 except:
193 self.sa.rollback()
196 self.sa.rollback()
194 raise
197 raise
195
198
196 def fix_default_user(self):
199 def fix_default_user(self):
197 """Fixes a old default user with some 'nicer' default values,
200 """Fixes a old default user with some 'nicer' default values,
198 used mostly for anonymous access
201 used mostly for anonymous access
199 """
202 """
200 def_user = self.sa.query(User)\
203 def_user = self.sa.query(User)\
201 .filter(User.username == 'default')\
204 .filter(User.username == 'default')\
202 .one()
205 .one()
203
206
204 def_user.name = 'Anonymous'
207 def_user.name = 'Anonymous'
205 def_user.lastname = 'User'
208 def_user.lastname = 'User'
206 def_user.email = 'anonymous@rhodecode.org'
209 def_user.email = 'anonymous@rhodecode.org'
207
210
208 try:
211 try:
209 self.sa.add(def_user)
212 self.sa.add(def_user)
210 self.sa.commit()
213 self.sa.commit()
211 except:
214 except:
212 self.sa.rollback()
215 self.sa.rollback()
213 raise
216 raise
214
217
218 def fix_settings(self):
219 """Fixes rhodecode settings adds ga_code key for google analytics
220 """
215
221
222 hgsettings3 = RhodeCodeSettings('ga_code', '')
223 try:
224 self.sa.add(hgsettings3)
225 self.sa.commit()
226 except:
227 self.sa.rollback()
228 raise
216
229
217 def admin_prompt(self, second=False):
230 def admin_prompt(self, second=False):
218 if not self.tests:
231 if not self.tests:
219 import getpass
232 import getpass
220
233
221
234
222 def get_password():
235 def get_password():
223 password = getpass.getpass('Specify admin password (min 6 chars):')
236 password = getpass.getpass('Specify admin password (min 6 chars):')
224 confirm = getpass.getpass('Confirm password:')
237 confirm = getpass.getpass('Confirm password:')
225
238
226 if password != confirm:
239 if password != confirm:
227 log.error('passwords mismatch')
240 log.error('passwords mismatch')
228 return False
241 return False
229 if len(password) < 6:
242 if len(password) < 6:
230 log.error('password is to short use at least 6 characters')
243 log.error('password is to short use at least 6 characters')
231 return False
244 return False
232
245
233 return password
246 return password
234
247
235 username = raw_input('Specify admin username:')
248 username = raw_input('Specify admin username:')
236
249
237 password = get_password()
250 password = get_password()
238 if not password:
251 if not password:
239 #second try
252 #second try
240 password = get_password()
253 password = get_password()
241 if not password:
254 if not password:
242 sys.exit()
255 sys.exit()
243
256
244 email = raw_input('Specify admin email:')
257 email = raw_input('Specify admin email:')
245 self.create_user(username, password, email, True)
258 self.create_user(username, password, email, True)
246 else:
259 else:
247 log.info('creating admin and regular test users')
260 log.info('creating admin and regular test users')
248 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
261 self.create_user('test_admin', 'test12', 'test_admin@mail.com', True)
249 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
262 self.create_user('test_regular', 'test12', 'test_regular@mail.com', False)
250 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
263 self.create_user('test_regular2', 'test12', 'test_regular2@mail.com', False)
251
264
252 def create_ui_settings(self):
265 def create_ui_settings(self):
253 """Creates ui settings, fills out hooks
266 """Creates ui settings, fills out hooks
254 and disables dotencode
267 and disables dotencode
255
268
256 """
269 """
257 #HOOKS
270 #HOOKS
258 hooks1_key = 'changegroup.update'
271 hooks1_key = 'changegroup.update'
259 hooks1_ = self.sa.query(RhodeCodeUi)\
272 hooks1_ = self.sa.query(RhodeCodeUi)\
260 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
273 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
261
274
262 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
275 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
263 hooks1.ui_section = 'hooks'
276 hooks1.ui_section = 'hooks'
264 hooks1.ui_key = hooks1_key
277 hooks1.ui_key = hooks1_key
265 hooks1.ui_value = 'hg update >&2'
278 hooks1.ui_value = 'hg update >&2'
266 hooks1.ui_active = False
279 hooks1.ui_active = False
267
280
268 hooks2_key = 'changegroup.repo_size'
281 hooks2_key = 'changegroup.repo_size'
269 hooks2_ = self.sa.query(RhodeCodeUi)\
282 hooks2_ = self.sa.query(RhodeCodeUi)\
270 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
283 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
271
284
272 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
285 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
273 hooks2.ui_section = 'hooks'
286 hooks2.ui_section = 'hooks'
274 hooks2.ui_key = hooks2_key
287 hooks2.ui_key = hooks2_key
275 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
288 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
276
289
277 hooks3 = RhodeCodeUi()
290 hooks3 = RhodeCodeUi()
278 hooks3.ui_section = 'hooks'
291 hooks3.ui_section = 'hooks'
279 hooks3.ui_key = 'pretxnchangegroup.push_logger'
292 hooks3.ui_key = 'pretxnchangegroup.push_logger'
280 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
293 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
281
294
282 hooks4 = RhodeCodeUi()
295 hooks4 = RhodeCodeUi()
283 hooks4.ui_section = 'hooks'
296 hooks4.ui_section = 'hooks'
284 hooks4.ui_key = 'preoutgoing.pull_logger'
297 hooks4.ui_key = 'preoutgoing.pull_logger'
285 hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
298 hooks4.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
286
299
287 #For mercurial 1.7 set backward comapatibility with format
300 #For mercurial 1.7 set backward comapatibility with format
288 dotencode_disable = RhodeCodeUi()
301 dotencode_disable = RhodeCodeUi()
289 dotencode_disable.ui_section = 'format'
302 dotencode_disable.ui_section = 'format'
290 dotencode_disable.ui_key = 'dotencode'
303 dotencode_disable.ui_key = 'dotencode'
291 dotencode_disable.ui_value = 'false'
304 dotencode_disable.ui_value = 'false'
292
305
293 try:
306 try:
294 self.sa.add(hooks1)
307 self.sa.add(hooks1)
295 self.sa.add(hooks2)
308 self.sa.add(hooks2)
296 self.sa.add(hooks3)
309 self.sa.add(hooks3)
297 self.sa.add(hooks4)
310 self.sa.add(hooks4)
298 self.sa.add(dotencode_disable)
311 self.sa.add(dotencode_disable)
299 self.sa.commit()
312 self.sa.commit()
300 except:
313 except:
301 self.sa.rollback()
314 self.sa.rollback()
302 raise
315 raise
303
316
304
317
305 def create_ldap_options(self):
318 def create_ldap_options(self):
306 """Creates ldap settings"""
319 """Creates ldap settings"""
307
320
308 try:
321 try:
309 for k in ['ldap_active', 'ldap_host', 'ldap_port', 'ldap_ldaps',
322 for k in ['ldap_active', 'ldap_host', 'ldap_port', 'ldap_ldaps',
310 'ldap_dn_user', 'ldap_dn_pass', 'ldap_base_dn']:
323 'ldap_dn_user', 'ldap_dn_pass', 'ldap_base_dn']:
311
324
312 setting = RhodeCodeSettings(k, '')
325 setting = RhodeCodeSettings(k, '')
313 self.sa.add(setting)
326 self.sa.add(setting)
314 self.sa.commit()
327 self.sa.commit()
315 except:
328 except:
316 self.sa.rollback()
329 self.sa.rollback()
317 raise
330 raise
318
331
319 def config_prompt(self, test_repo_path=''):
332 def config_prompt(self, test_repo_path=''):
320 log.info('Setting up repositories config')
333 log.info('Setting up repositories config')
321
334
322 if not self.tests and not test_repo_path:
335 if not self.tests and not test_repo_path:
323 path = raw_input('Specify valid full path to your repositories'
336 path = raw_input('Specify valid full path to your repositories'
324 ' you can change this later in application settings:')
337 ' you can change this later in application settings:')
325 else:
338 else:
326 path = test_repo_path
339 path = test_repo_path
327
340
328 if not os.path.isdir(path):
341 if not os.path.isdir(path):
329 log.error('You entered wrong path: %s', path)
342 log.error('You entered wrong path: %s', path)
330 sys.exit()
343 sys.exit()
331
344
332 self.create_ui_settings()
345 self.create_ui_settings()
333
346
334 #HG UI OPTIONS
347 #HG UI OPTIONS
335 web1 = RhodeCodeUi()
348 web1 = RhodeCodeUi()
336 web1.ui_section = 'web'
349 web1.ui_section = 'web'
337 web1.ui_key = 'push_ssl'
350 web1.ui_key = 'push_ssl'
338 web1.ui_value = 'false'
351 web1.ui_value = 'false'
339
352
340 web2 = RhodeCodeUi()
353 web2 = RhodeCodeUi()
341 web2.ui_section = 'web'
354 web2.ui_section = 'web'
342 web2.ui_key = 'allow_archive'
355 web2.ui_key = 'allow_archive'
343 web2.ui_value = 'gz zip bz2'
356 web2.ui_value = 'gz zip bz2'
344
357
345 web3 = RhodeCodeUi()
358 web3 = RhodeCodeUi()
346 web3.ui_section = 'web'
359 web3.ui_section = 'web'
347 web3.ui_key = 'allow_push'
360 web3.ui_key = 'allow_push'
348 web3.ui_value = '*'
361 web3.ui_value = '*'
349
362
350 web4 = RhodeCodeUi()
363 web4 = RhodeCodeUi()
351 web4.ui_section = 'web'
364 web4.ui_section = 'web'
352 web4.ui_key = 'baseurl'
365 web4.ui_key = 'baseurl'
353 web4.ui_value = '/'
366 web4.ui_value = '/'
354
367
355 paths = RhodeCodeUi()
368 paths = RhodeCodeUi()
356 paths.ui_section = 'paths'
369 paths.ui_section = 'paths'
357 paths.ui_key = '/'
370 paths.ui_key = '/'
358 paths.ui_value = path
371 paths.ui_value = path
359
372
360
373
361 hgsettings1 = RhodeCodeSettings('realm', 'RhodeCode authentication')
374 hgsettings1 = RhodeCodeSettings('realm', 'RhodeCode authentication')
362 hgsettings2 = RhodeCodeSettings('title', 'RhodeCode')
375 hgsettings2 = RhodeCodeSettings('title', 'RhodeCode')
376 hgsettings3 = RhodeCodeSettings('ga_code', '')
363
377
364
378
365 try:
379 try:
366 self.sa.add(web1)
380 self.sa.add(web1)
367 self.sa.add(web2)
381 self.sa.add(web2)
368 self.sa.add(web3)
382 self.sa.add(web3)
369 self.sa.add(web4)
383 self.sa.add(web4)
370 self.sa.add(paths)
384 self.sa.add(paths)
371 self.sa.add(hgsettings1)
385 self.sa.add(hgsettings1)
372 self.sa.add(hgsettings2)
386 self.sa.add(hgsettings2)
387 self.sa.add(hgsettings3)
373
388
374 self.sa.commit()
389 self.sa.commit()
375 except:
390 except:
376 self.sa.rollback()
391 self.sa.rollback()
377 raise
392 raise
378
393
379 self.create_ldap_options()
394 self.create_ldap_options()
380
395
381 log.info('created ui config')
396 log.info('created ui config')
382
397
383 def create_user(self, username, password, email='', admin=False):
398 def create_user(self, username, password, email='', admin=False):
384 log.info('creating administrator user %s', username)
399 log.info('creating administrator user %s', username)
385 new_user = User()
400 new_user = User()
386 new_user.username = username
401 new_user.username = username
387 new_user.password = get_crypt_password(password)
402 new_user.password = get_crypt_password(password)
388 new_user.name = 'RhodeCode'
403 new_user.name = 'RhodeCode'
389 new_user.lastname = 'Admin'
404 new_user.lastname = 'Admin'
390 new_user.email = email
405 new_user.email = email
391 new_user.admin = admin
406 new_user.admin = admin
392 new_user.active = True
407 new_user.active = True
393
408
394 try:
409 try:
395 self.sa.add(new_user)
410 self.sa.add(new_user)
396 self.sa.commit()
411 self.sa.commit()
397 except:
412 except:
398 self.sa.rollback()
413 self.sa.rollback()
399 raise
414 raise
400
415
401 def create_default_user(self):
416 def create_default_user(self):
402 log.info('creating default user')
417 log.info('creating default user')
403 #create default user for handling default permissions.
418 #create default user for handling default permissions.
404 def_user = User()
419 def_user = User()
405 def_user.username = 'default'
420 def_user.username = 'default'
406 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
421 def_user.password = get_crypt_password(str(uuid.uuid1())[:8])
407 def_user.name = 'Anonymous'
422 def_user.name = 'Anonymous'
408 def_user.lastname = 'User'
423 def_user.lastname = 'User'
409 def_user.email = 'anonymous@rhodecode.org'
424 def_user.email = 'anonymous@rhodecode.org'
410 def_user.admin = False
425 def_user.admin = False
411 def_user.active = False
426 def_user.active = False
412 try:
427 try:
413 self.sa.add(def_user)
428 self.sa.add(def_user)
414 self.sa.commit()
429 self.sa.commit()
415 except:
430 except:
416 self.sa.rollback()
431 self.sa.rollback()
417 raise
432 raise
418
433
419 def create_permissions(self):
434 def create_permissions(self):
420 #module.(access|create|change|delete)_[name]
435 #module.(access|create|change|delete)_[name]
421 #module.(read|write|owner)
436 #module.(read|write|owner)
422 perms = [('repository.none', 'Repository no access'),
437 perms = [('repository.none', 'Repository no access'),
423 ('repository.read', 'Repository read access'),
438 ('repository.read', 'Repository read access'),
424 ('repository.write', 'Repository write access'),
439 ('repository.write', 'Repository write access'),
425 ('repository.admin', 'Repository admin access'),
440 ('repository.admin', 'Repository admin access'),
426 ('hg.admin', 'Hg Administrator'),
441 ('hg.admin', 'Hg Administrator'),
427 ('hg.create.repository', 'Repository create'),
442 ('hg.create.repository', 'Repository create'),
428 ('hg.create.none', 'Repository creation disabled'),
443 ('hg.create.none', 'Repository creation disabled'),
429 ('hg.register.none', 'Register disabled'),
444 ('hg.register.none', 'Register disabled'),
430 ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
445 ('hg.register.manual_activate', 'Register new user with rhodecode without manual activation'),
431 ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
446 ('hg.register.auto_activate', 'Register new user with rhodecode without auto activation'),
432 ]
447 ]
433
448
434 for p in perms:
449 for p in perms:
435 new_perm = Permission()
450 new_perm = Permission()
436 new_perm.permission_name = p[0]
451 new_perm.permission_name = p[0]
437 new_perm.permission_longname = p[1]
452 new_perm.permission_longname = p[1]
438 try:
453 try:
439 self.sa.add(new_perm)
454 self.sa.add(new_perm)
440 self.sa.commit()
455 self.sa.commit()
441 except:
456 except:
442 self.sa.rollback()
457 self.sa.rollback()
443 raise
458 raise
444
459
445 def populate_default_permissions(self):
460 def populate_default_permissions(self):
446 log.info('creating default user permissions')
461 log.info('creating default user permissions')
447
462
448 default_user = self.sa.query(User)\
463 default_user = self.sa.query(User)\
449 .filter(User.username == 'default').scalar()
464 .filter(User.username == 'default').scalar()
450
465
451 reg_perm = UserToPerm()
466 reg_perm = UserToPerm()
452 reg_perm.user = default_user
467 reg_perm.user = default_user
453 reg_perm.permission = self.sa.query(Permission)\
468 reg_perm.permission = self.sa.query(Permission)\
454 .filter(Permission.permission_name == 'hg.register.manual_activate')\
469 .filter(Permission.permission_name == 'hg.register.manual_activate')\
455 .scalar()
470 .scalar()
456
471
457 create_repo_perm = UserToPerm()
472 create_repo_perm = UserToPerm()
458 create_repo_perm.user = default_user
473 create_repo_perm.user = default_user
459 create_repo_perm.permission = self.sa.query(Permission)\
474 create_repo_perm.permission = self.sa.query(Permission)\
460 .filter(Permission.permission_name == 'hg.create.repository')\
475 .filter(Permission.permission_name == 'hg.create.repository')\
461 .scalar()
476 .scalar()
462
477
463 default_repo_perm = UserToPerm()
478 default_repo_perm = UserToPerm()
464 default_repo_perm.user = default_user
479 default_repo_perm.user = default_user
465 default_repo_perm.permission = self.sa.query(Permission)\
480 default_repo_perm.permission = self.sa.query(Permission)\
466 .filter(Permission.permission_name == 'repository.read')\
481 .filter(Permission.permission_name == 'repository.read')\
467 .scalar()
482 .scalar()
468
483
469 try:
484 try:
470 self.sa.add(reg_perm)
485 self.sa.add(reg_perm)
471 self.sa.add(create_repo_perm)
486 self.sa.add(create_repo_perm)
472 self.sa.add(default_repo_perm)
487 self.sa.add(default_repo_perm)
473 self.sa.commit()
488 self.sa.commit()
474 except:
489 except:
475 self.sa.rollback()
490 self.sa.rollback()
476 raise
491 raise
477
492
@@ -1,483 +1,484 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import os
22 import os
23 import re
23 import re
24 import logging
24 import logging
25
25
26 import formencode
26 import formencode
27 from formencode import All
27 from formencode import All
28 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
28 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 Email, Bool, StringBoolean
29 Email, Bool, StringBoolean
30
30
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32
32
33 import rhodecode.lib.helpers as h
33 import rhodecode.lib.helpers as h
34 from rhodecode.lib.auth import authenticate, get_crypt_password
34 from rhodecode.lib.auth import authenticate, get_crypt_password
35 from rhodecode.lib.exceptions import LdapImportError
35 from rhodecode.lib.exceptions import LdapImportError
36 from rhodecode.model import meta
36 from rhodecode.model import meta
37 from rhodecode.model.user import UserModel
37 from rhodecode.model.user import UserModel
38 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.db import User
39 from rhodecode.model.db import User
40 from rhodecode import BACKENDS
40 from rhodecode import BACKENDS
41
41
42 from webhelpers.pylonslib.secure_form import authentication_token
42 from webhelpers.pylonslib.secure_form import authentication_token
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46 #this is needed to translate the messages using _() in validators
46 #this is needed to translate the messages using _() in validators
47 class State_obj(object):
47 class State_obj(object):
48 _ = staticmethod(_)
48 _ = staticmethod(_)
49
49
50 #===============================================================================
50 #===============================================================================
51 # VALIDATORS
51 # VALIDATORS
52 #===============================================================================
52 #===============================================================================
53 class ValidAuthToken(formencode.validators.FancyValidator):
53 class ValidAuthToken(formencode.validators.FancyValidator):
54 messages = {'invalid_token':_('Token mismatch')}
54 messages = {'invalid_token':_('Token mismatch')}
55
55
56 def validate_python(self, value, state):
56 def validate_python(self, value, state):
57
57
58 if value != authentication_token():
58 if value != authentication_token():
59 raise formencode.Invalid(self.message('invalid_token', state,
59 raise formencode.Invalid(self.message('invalid_token', state,
60 search_number=value), value, state)
60 search_number=value), value, state)
61
61
62 def ValidUsername(edit, old_data):
62 def ValidUsername(edit, old_data):
63 class _ValidUsername(formencode.validators.FancyValidator):
63 class _ValidUsername(formencode.validators.FancyValidator):
64
64
65 def validate_python(self, value, state):
65 def validate_python(self, value, state):
66 if value in ['default', 'new_user']:
66 if value in ['default', 'new_user']:
67 raise formencode.Invalid(_('Invalid username'), value, state)
67 raise formencode.Invalid(_('Invalid username'), value, state)
68 #check if user is unique
68 #check if user is unique
69 old_un = None
69 old_un = None
70 if edit:
70 if edit:
71 old_un = UserModel().get(old_data.get('user_id')).username
71 old_un = UserModel().get(old_data.get('user_id')).username
72
72
73 if old_un != value or not edit:
73 if old_un != value or not edit:
74 if UserModel().get_by_username(value, cache=False,
74 if UserModel().get_by_username(value, cache=False,
75 case_insensitive=True):
75 case_insensitive=True):
76 raise formencode.Invalid(_('This username already exists') ,
76 raise formencode.Invalid(_('This username already exists') ,
77 value, state)
77 value, state)
78
78
79
79
80 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_]+$', value) is None:
80 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_]+$', value) is None:
81 raise formencode.Invalid(_('Username may only contain '
81 raise formencode.Invalid(_('Username may only contain '
82 'alphanumeric characters underscores '
82 'alphanumeric characters underscores '
83 'or dashes and must begin with '
83 'or dashes and must begin with '
84 'alphanumeric character'),
84 'alphanumeric character'),
85 value, state)
85 value, state)
86
86
87
87
88
88
89 return _ValidUsername
89 return _ValidUsername
90
90
91 class ValidPassword(formencode.validators.FancyValidator):
91 class ValidPassword(formencode.validators.FancyValidator):
92
92
93 def to_python(self, value, state):
93 def to_python(self, value, state):
94
94
95 if value:
95 if value:
96
96
97 if value.get('password'):
97 if value.get('password'):
98 try:
98 try:
99 value['password'] = get_crypt_password(value['password'])
99 value['password'] = get_crypt_password(value['password'])
100 except UnicodeEncodeError:
100 except UnicodeEncodeError:
101 e_dict = {'password':_('Invalid characters in password')}
101 e_dict = {'password':_('Invalid characters in password')}
102 raise formencode.Invalid('', value, state, error_dict=e_dict)
102 raise formencode.Invalid('', value, state, error_dict=e_dict)
103
103
104 if value.get('password_confirmation'):
104 if value.get('password_confirmation'):
105 try:
105 try:
106 value['password_confirmation'] = \
106 value['password_confirmation'] = \
107 get_crypt_password(value['password_confirmation'])
107 get_crypt_password(value['password_confirmation'])
108 except UnicodeEncodeError:
108 except UnicodeEncodeError:
109 e_dict = {'password_confirmation':_('Invalid characters in password')}
109 e_dict = {'password_confirmation':_('Invalid characters in password')}
110 raise formencode.Invalid('', value, state, error_dict=e_dict)
110 raise formencode.Invalid('', value, state, error_dict=e_dict)
111
111
112 if value.get('new_password'):
112 if value.get('new_password'):
113 try:
113 try:
114 value['new_password'] = \
114 value['new_password'] = \
115 get_crypt_password(value['new_password'])
115 get_crypt_password(value['new_password'])
116 except UnicodeEncodeError:
116 except UnicodeEncodeError:
117 e_dict = {'new_password':_('Invalid characters in password')}
117 e_dict = {'new_password':_('Invalid characters in password')}
118 raise formencode.Invalid('', value, state, error_dict=e_dict)
118 raise formencode.Invalid('', value, state, error_dict=e_dict)
119
119
120 return value
120 return value
121
121
122 class ValidPasswordsMatch(formencode.validators.FancyValidator):
122 class ValidPasswordsMatch(formencode.validators.FancyValidator):
123
123
124 def validate_python(self, value, state):
124 def validate_python(self, value, state):
125
125
126 if value['password'] != value['password_confirmation']:
126 if value['password'] != value['password_confirmation']:
127 e_dict = {'password_confirmation':
127 e_dict = {'password_confirmation':
128 _('Password do not match')}
128 _('Password do not match')}
129 raise formencode.Invalid('', value, state, error_dict=e_dict)
129 raise formencode.Invalid('', value, state, error_dict=e_dict)
130
130
131 class ValidAuth(formencode.validators.FancyValidator):
131 class ValidAuth(formencode.validators.FancyValidator):
132 messages = {
132 messages = {
133 'invalid_password':_('invalid password'),
133 'invalid_password':_('invalid password'),
134 'invalid_login':_('invalid user name'),
134 'invalid_login':_('invalid user name'),
135 'disabled_account':_('Your account is disabled')
135 'disabled_account':_('Your account is disabled')
136
136
137 }
137 }
138 #error mapping
138 #error mapping
139 e_dict = {'username':messages['invalid_login'],
139 e_dict = {'username':messages['invalid_login'],
140 'password':messages['invalid_password']}
140 'password':messages['invalid_password']}
141 e_dict_disable = {'username':messages['disabled_account']}
141 e_dict_disable = {'username':messages['disabled_account']}
142
142
143 def validate_python(self, value, state):
143 def validate_python(self, value, state):
144 password = value['password']
144 password = value['password']
145 username = value['username']
145 username = value['username']
146 user = UserModel().get_by_username(username)
146 user = UserModel().get_by_username(username)
147
147
148 if authenticate(username, password):
148 if authenticate(username, password):
149 return value
149 return value
150 else:
150 else:
151 if user and user.active is False:
151 if user and user.active is False:
152 log.warning('user %s is disabled', username)
152 log.warning('user %s is disabled', username)
153 raise formencode.Invalid(self.message('disabled_account',
153 raise formencode.Invalid(self.message('disabled_account',
154 state=State_obj),
154 state=State_obj),
155 value, state,
155 value, state,
156 error_dict=self.e_dict_disable)
156 error_dict=self.e_dict_disable)
157 else:
157 else:
158 log.warning('user %s not authenticated', username)
158 log.warning('user %s not authenticated', username)
159 raise formencode.Invalid(self.message('invalid_password',
159 raise formencode.Invalid(self.message('invalid_password',
160 state=State_obj), value, state,
160 state=State_obj), value, state,
161 error_dict=self.e_dict)
161 error_dict=self.e_dict)
162
162
163 class ValidRepoUser(formencode.validators.FancyValidator):
163 class ValidRepoUser(formencode.validators.FancyValidator):
164
164
165 def to_python(self, value, state):
165 def to_python(self, value, state):
166 sa = meta.Session()
166 sa = meta.Session()
167 try:
167 try:
168 self.user_db = sa.query(User)\
168 self.user_db = sa.query(User)\
169 .filter(User.active == True)\
169 .filter(User.active == True)\
170 .filter(User.username == value).one()
170 .filter(User.username == value).one()
171 except Exception:
171 except Exception:
172 raise formencode.Invalid(_('This username is not valid'),
172 raise formencode.Invalid(_('This username is not valid'),
173 value, state)
173 value, state)
174 finally:
174 finally:
175 meta.Session.remove()
175 meta.Session.remove()
176
176
177 return self.user_db.user_id
177 return self.user_db.user_id
178
178
179 def ValidRepoName(edit, old_data):
179 def ValidRepoName(edit, old_data):
180 class _ValidRepoName(formencode.validators.FancyValidator):
180 class _ValidRepoName(formencode.validators.FancyValidator):
181
181
182 def to_python(self, value, state):
182 def to_python(self, value, state):
183 slug = h.repo_name_slug(value)
183 slug = h.repo_name_slug(value)
184 if slug in ['_admin']:
184 if slug in ['_admin']:
185 raise formencode.Invalid(_('This repository name is disallowed'),
185 raise formencode.Invalid(_('This repository name is disallowed'),
186 value, state)
186 value, state)
187 if old_data.get('repo_name') != value or not edit:
187 if old_data.get('repo_name') != value or not edit:
188 if RepoModel().get_by_repo_name(slug, cache=False):
188 if RepoModel().get_by_repo_name(slug, cache=False):
189 raise formencode.Invalid(_('This repository already exists') ,
189 raise formencode.Invalid(_('This repository already exists') ,
190 value, state)
190 value, state)
191 return slug
191 return slug
192
192
193
193
194 return _ValidRepoName
194 return _ValidRepoName
195
195
196 def ValidForkType(old_data):
196 def ValidForkType(old_data):
197 class _ValidForkType(formencode.validators.FancyValidator):
197 class _ValidForkType(formencode.validators.FancyValidator):
198
198
199 def to_python(self, value, state):
199 def to_python(self, value, state):
200 if old_data['repo_type'] != value:
200 if old_data['repo_type'] != value:
201 raise formencode.Invalid(_('Fork have to be the same type as original'),
201 raise formencode.Invalid(_('Fork have to be the same type as original'),
202 value, state)
202 value, state)
203 return value
203 return value
204 return _ValidForkType
204 return _ValidForkType
205
205
206 class ValidPerms(formencode.validators.FancyValidator):
206 class ValidPerms(formencode.validators.FancyValidator):
207 messages = {'perm_new_user_name':_('This username is not valid')}
207 messages = {'perm_new_user_name':_('This username is not valid')}
208
208
209 def to_python(self, value, state):
209 def to_python(self, value, state):
210 perms_update = []
210 perms_update = []
211 perms_new = []
211 perms_new = []
212 #build a list of permission to update and new permission to create
212 #build a list of permission to update and new permission to create
213 for k, v in value.items():
213 for k, v in value.items():
214 if k.startswith('perm_'):
214 if k.startswith('perm_'):
215 if k.startswith('perm_new_user'):
215 if k.startswith('perm_new_user'):
216 new_perm = value.get('perm_new_user', False)
216 new_perm = value.get('perm_new_user', False)
217 new_user = value.get('perm_new_user_name', False)
217 new_user = value.get('perm_new_user_name', False)
218 if new_user and new_perm:
218 if new_user and new_perm:
219 if (new_user, new_perm) not in perms_new:
219 if (new_user, new_perm) not in perms_new:
220 perms_new.append((new_user, new_perm))
220 perms_new.append((new_user, new_perm))
221 else:
221 else:
222 usr = k[5:]
222 usr = k[5:]
223 if usr == 'default':
223 if usr == 'default':
224 if value['private']:
224 if value['private']:
225 #set none for default when updating to private repo
225 #set none for default when updating to private repo
226 v = 'repository.none'
226 v = 'repository.none'
227 perms_update.append((usr, v))
227 perms_update.append((usr, v))
228 value['perms_updates'] = perms_update
228 value['perms_updates'] = perms_update
229 value['perms_new'] = perms_new
229 value['perms_new'] = perms_new
230 sa = meta.Session
230 sa = meta.Session
231 for k, v in perms_new:
231 for k, v in perms_new:
232 try:
232 try:
233 self.user_db = sa.query(User)\
233 self.user_db = sa.query(User)\
234 .filter(User.active == True)\
234 .filter(User.active == True)\
235 .filter(User.username == k).one()
235 .filter(User.username == k).one()
236 except Exception:
236 except Exception:
237 msg = self.message('perm_new_user_name',
237 msg = self.message('perm_new_user_name',
238 state=State_obj)
238 state=State_obj)
239 raise formencode.Invalid(msg, value, state,
239 raise formencode.Invalid(msg, value, state,
240 error_dict={'perm_new_user_name':msg})
240 error_dict={'perm_new_user_name':msg})
241 return value
241 return value
242
242
243 class ValidSettings(formencode.validators.FancyValidator):
243 class ValidSettings(formencode.validators.FancyValidator):
244
244
245 def to_python(self, value, state):
245 def to_python(self, value, state):
246 #settings form can't edit user
246 #settings form can't edit user
247 if value.has_key('user'):
247 if value.has_key('user'):
248 del['value']['user']
248 del['value']['user']
249
249
250 return value
250 return value
251
251
252 class ValidPath(formencode.validators.FancyValidator):
252 class ValidPath(formencode.validators.FancyValidator):
253 def to_python(self, value, state):
253 def to_python(self, value, state):
254
254
255 if not os.path.isdir(value):
255 if not os.path.isdir(value):
256 msg = _('This is not a valid path')
256 msg = _('This is not a valid path')
257 raise formencode.Invalid(msg, value, state,
257 raise formencode.Invalid(msg, value, state,
258 error_dict={'paths_root_path':msg})
258 error_dict={'paths_root_path':msg})
259 return value
259 return value
260
260
261 def UniqSystemEmail(old_data):
261 def UniqSystemEmail(old_data):
262 class _UniqSystemEmail(formencode.validators.FancyValidator):
262 class _UniqSystemEmail(formencode.validators.FancyValidator):
263 def to_python(self, value, state):
263 def to_python(self, value, state):
264 value = value.lower()
264 value = value.lower()
265 if old_data.get('email') != value:
265 if old_data.get('email') != value:
266 sa = meta.Session()
266 sa = meta.Session()
267 try:
267 try:
268 user = sa.query(User).filter(User.email == value).scalar()
268 user = sa.query(User).filter(User.email == value).scalar()
269 if user:
269 if user:
270 raise formencode.Invalid(_("This e-mail address is already taken") ,
270 raise formencode.Invalid(_("This e-mail address is already taken") ,
271 value, state)
271 value, state)
272 finally:
272 finally:
273 meta.Session.remove()
273 meta.Session.remove()
274
274
275 return value
275 return value
276
276
277 return _UniqSystemEmail
277 return _UniqSystemEmail
278
278
279 class ValidSystemEmail(formencode.validators.FancyValidator):
279 class ValidSystemEmail(formencode.validators.FancyValidator):
280 def to_python(self, value, state):
280 def to_python(self, value, state):
281 value = value.lower()
281 value = value.lower()
282 sa = meta.Session
282 sa = meta.Session
283 try:
283 try:
284 user = sa.query(User).filter(User.email == value).scalar()
284 user = sa.query(User).filter(User.email == value).scalar()
285 if user is None:
285 if user is None:
286 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
286 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
287 value, state)
287 value, state)
288 finally:
288 finally:
289 meta.Session.remove()
289 meta.Session.remove()
290
290
291 return value
291 return value
292
292
293 class LdapLibValidator(formencode.validators.FancyValidator):
293 class LdapLibValidator(formencode.validators.FancyValidator):
294
294
295 def to_python(self, value, state):
295 def to_python(self, value, state):
296
296
297 try:
297 try:
298 import ldap
298 import ldap
299 except ImportError:
299 except ImportError:
300 raise LdapImportError
300 raise LdapImportError
301 return value
301 return value
302
302
303 class BaseDnValidator(formencode.validators.FancyValidator):
303 class BaseDnValidator(formencode.validators.FancyValidator):
304
304
305 def to_python(self, value, state):
305 def to_python(self, value, state):
306
306
307 try:
307 try:
308 value % {'user':'valid'}
308 value % {'user':'valid'}
309
309
310 if value.find('%(user)s') == -1:
310 if value.find('%(user)s') == -1:
311 raise formencode.Invalid(_("You need to specify %(user)s in "
311 raise formencode.Invalid(_("You need to specify %(user)s in "
312 "template for example uid=%(user)s "
312 "template for example uid=%(user)s "
313 ",dc=company...") ,
313 ",dc=company...") ,
314 value, state)
314 value, state)
315
315
316 except KeyError:
316 except KeyError:
317 raise formencode.Invalid(_("Wrong template used, only %(user)s "
317 raise formencode.Invalid(_("Wrong template used, only %(user)s "
318 "is an valid entry") ,
318 "is an valid entry") ,
319 value, state)
319 value, state)
320
320
321 return value
321 return value
322
322
323 #===============================================================================
323 #===============================================================================
324 # FORMS
324 # FORMS
325 #===============================================================================
325 #===============================================================================
326 class LoginForm(formencode.Schema):
326 class LoginForm(formencode.Schema):
327 allow_extra_fields = True
327 allow_extra_fields = True
328 filter_extra_fields = True
328 filter_extra_fields = True
329 username = UnicodeString(
329 username = UnicodeString(
330 strip=True,
330 strip=True,
331 min=1,
331 min=1,
332 not_empty=True,
332 not_empty=True,
333 messages={
333 messages={
334 'empty':_('Please enter a login'),
334 'empty':_('Please enter a login'),
335 'tooShort':_('Enter a value %(min)i characters long or more')}
335 'tooShort':_('Enter a value %(min)i characters long or more')}
336 )
336 )
337
337
338 password = UnicodeString(
338 password = UnicodeString(
339 strip=True,
339 strip=True,
340 min=6,
340 min=6,
341 not_empty=True,
341 not_empty=True,
342 messages={
342 messages={
343 'empty':_('Please enter a password'),
343 'empty':_('Please enter a password'),
344 'tooShort':_('Enter %(min)i characters or more')}
344 'tooShort':_('Enter %(min)i characters or more')}
345 )
345 )
346
346
347
347
348 #chained validators have access to all data
348 #chained validators have access to all data
349 chained_validators = [ValidAuth]
349 chained_validators = [ValidAuth]
350
350
351 def UserForm(edit=False, old_data={}):
351 def UserForm(edit=False, old_data={}):
352 class _UserForm(formencode.Schema):
352 class _UserForm(formencode.Schema):
353 allow_extra_fields = True
353 allow_extra_fields = True
354 filter_extra_fields = True
354 filter_extra_fields = True
355 username = All(UnicodeString(strip=True, min=1, not_empty=True),
355 username = All(UnicodeString(strip=True, min=1, not_empty=True),
356 ValidUsername(edit, old_data))
356 ValidUsername(edit, old_data))
357 if edit:
357 if edit:
358 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
358 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
359 admin = StringBoolean(if_missing=False)
359 admin = StringBoolean(if_missing=False)
360 else:
360 else:
361 password = All(UnicodeString(strip=True, min=6, not_empty=True))
361 password = All(UnicodeString(strip=True, min=6, not_empty=True))
362 active = StringBoolean(if_missing=False)
362 active = StringBoolean(if_missing=False)
363 name = UnicodeString(strip=True, min=1, not_empty=True)
363 name = UnicodeString(strip=True, min=1, not_empty=True)
364 lastname = UnicodeString(strip=True, min=1, not_empty=True)
364 lastname = UnicodeString(strip=True, min=1, not_empty=True)
365 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
365 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
366
366
367 chained_validators = [ValidPassword]
367 chained_validators = [ValidPassword]
368
368
369 return _UserForm
369 return _UserForm
370
370
371 def RegisterForm(edit=False, old_data={}):
371 def RegisterForm(edit=False, old_data={}):
372 class _RegisterForm(formencode.Schema):
372 class _RegisterForm(formencode.Schema):
373 allow_extra_fields = True
373 allow_extra_fields = True
374 filter_extra_fields = True
374 filter_extra_fields = True
375 username = All(ValidUsername(edit, old_data),
375 username = All(ValidUsername(edit, old_data),
376 UnicodeString(strip=True, min=1, not_empty=True))
376 UnicodeString(strip=True, min=1, not_empty=True))
377 password = All(UnicodeString(strip=True, min=6, not_empty=True))
377 password = All(UnicodeString(strip=True, min=6, not_empty=True))
378 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
378 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
379 active = StringBoolean(if_missing=False)
379 active = StringBoolean(if_missing=False)
380 name = UnicodeString(strip=True, min=1, not_empty=True)
380 name = UnicodeString(strip=True, min=1, not_empty=True)
381 lastname = UnicodeString(strip=True, min=1, not_empty=True)
381 lastname = UnicodeString(strip=True, min=1, not_empty=True)
382 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
382 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
383
383
384 chained_validators = [ValidPasswordsMatch, ValidPassword]
384 chained_validators = [ValidPasswordsMatch, ValidPassword]
385
385
386 return _RegisterForm
386 return _RegisterForm
387
387
388 def PasswordResetForm():
388 def PasswordResetForm():
389 class _PasswordResetForm(formencode.Schema):
389 class _PasswordResetForm(formencode.Schema):
390 allow_extra_fields = True
390 allow_extra_fields = True
391 filter_extra_fields = True
391 filter_extra_fields = True
392 email = All(ValidSystemEmail(), Email(not_empty=True))
392 email = All(ValidSystemEmail(), Email(not_empty=True))
393 return _PasswordResetForm
393 return _PasswordResetForm
394
394
395 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
395 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
396 class _RepoForm(formencode.Schema):
396 class _RepoForm(formencode.Schema):
397 allow_extra_fields = True
397 allow_extra_fields = True
398 filter_extra_fields = False
398 filter_extra_fields = False
399 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
399 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
400 ValidRepoName(edit, old_data))
400 ValidRepoName(edit, old_data))
401 description = UnicodeString(strip=True, min=1, not_empty=True)
401 description = UnicodeString(strip=True, min=1, not_empty=True)
402 private = StringBoolean(if_missing=False)
402 private = StringBoolean(if_missing=False)
403 enable_statistics = StringBoolean(if_missing=False)
403 enable_statistics = StringBoolean(if_missing=False)
404 repo_type = OneOf(supported_backends)
404 repo_type = OneOf(supported_backends)
405 if edit:
405 if edit:
406 user = All(Int(not_empty=True), ValidRepoUser)
406 user = All(Int(not_empty=True), ValidRepoUser)
407
407
408 chained_validators = [ValidPerms]
408 chained_validators = [ValidPerms]
409 return _RepoForm
409 return _RepoForm
410
410
411 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
411 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
412 class _RepoForkForm(formencode.Schema):
412 class _RepoForkForm(formencode.Schema):
413 allow_extra_fields = True
413 allow_extra_fields = True
414 filter_extra_fields = False
414 filter_extra_fields = False
415 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
415 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
416 ValidRepoName(edit, old_data))
416 ValidRepoName(edit, old_data))
417 description = UnicodeString(strip=True, min=1, not_empty=True)
417 description = UnicodeString(strip=True, min=1, not_empty=True)
418 private = StringBoolean(if_missing=False)
418 private = StringBoolean(if_missing=False)
419 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
419 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
420 return _RepoForkForm
420 return _RepoForkForm
421
421
422 def RepoSettingsForm(edit=False, old_data={}):
422 def RepoSettingsForm(edit=False, old_data={}):
423 class _RepoForm(formencode.Schema):
423 class _RepoForm(formencode.Schema):
424 allow_extra_fields = True
424 allow_extra_fields = True
425 filter_extra_fields = False
425 filter_extra_fields = False
426 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
426 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
427 ValidRepoName(edit, old_data))
427 ValidRepoName(edit, old_data))
428 description = UnicodeString(strip=True, min=1, not_empty=True)
428 description = UnicodeString(strip=True, min=1, not_empty=True)
429 private = StringBoolean(if_missing=False)
429 private = StringBoolean(if_missing=False)
430
430
431 chained_validators = [ValidPerms, ValidSettings]
431 chained_validators = [ValidPerms, ValidSettings]
432 return _RepoForm
432 return _RepoForm
433
433
434
434
435 def ApplicationSettingsForm():
435 def ApplicationSettingsForm():
436 class _ApplicationSettingsForm(formencode.Schema):
436 class _ApplicationSettingsForm(formencode.Schema):
437 allow_extra_fields = True
437 allow_extra_fields = True
438 filter_extra_fields = False
438 filter_extra_fields = False
439 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
439 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
440 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
440 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
441 ga_code = UnicodeString(strip=True, min=1, not_empty=False)
441
442
442 return _ApplicationSettingsForm
443 return _ApplicationSettingsForm
443
444
444 def ApplicationUiSettingsForm():
445 def ApplicationUiSettingsForm():
445 class _ApplicationUiSettingsForm(formencode.Schema):
446 class _ApplicationUiSettingsForm(formencode.Schema):
446 allow_extra_fields = True
447 allow_extra_fields = True
447 filter_extra_fields = False
448 filter_extra_fields = False
448 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
449 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
449 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
450 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
450 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
451 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
451 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
452 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
452 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
453 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
453 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
454 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
454
455
455 return _ApplicationUiSettingsForm
456 return _ApplicationUiSettingsForm
456
457
457 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
458 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
458 class _DefaultPermissionsForm(formencode.Schema):
459 class _DefaultPermissionsForm(formencode.Schema):
459 allow_extra_fields = True
460 allow_extra_fields = True
460 filter_extra_fields = True
461 filter_extra_fields = True
461 overwrite_default = StringBoolean(if_missing=False)
462 overwrite_default = StringBoolean(if_missing=False)
462 anonymous = OneOf(['True', 'False'], if_missing=False)
463 anonymous = OneOf(['True', 'False'], if_missing=False)
463 default_perm = OneOf(perms_choices)
464 default_perm = OneOf(perms_choices)
464 default_register = OneOf(register_choices)
465 default_register = OneOf(register_choices)
465 default_create = OneOf(create_choices)
466 default_create = OneOf(create_choices)
466
467
467 return _DefaultPermissionsForm
468 return _DefaultPermissionsForm
468
469
469
470
470 def LdapSettingsForm():
471 def LdapSettingsForm():
471 class _LdapSettingsForm(formencode.Schema):
472 class _LdapSettingsForm(formencode.Schema):
472 allow_extra_fields = True
473 allow_extra_fields = True
473 filter_extra_fields = True
474 filter_extra_fields = True
474 pre_validators = [LdapLibValidator]
475 pre_validators = [LdapLibValidator]
475 ldap_active = StringBoolean(if_missing=False)
476 ldap_active = StringBoolean(if_missing=False)
476 ldap_host = UnicodeString(strip=True,)
477 ldap_host = UnicodeString(strip=True,)
477 ldap_port = Number(strip=True,)
478 ldap_port = Number(strip=True,)
478 ldap_ldaps = StringBoolean(if_missing=False)
479 ldap_ldaps = StringBoolean(if_missing=False)
479 ldap_dn_user = UnicodeString(strip=True,)
480 ldap_dn_user = UnicodeString(strip=True,)
480 ldap_dn_pass = UnicodeString(strip=True,)
481 ldap_dn_pass = UnicodeString(strip=True,)
481 ldap_base_dn = All(BaseDnValidator, UnicodeString(strip=True,))
482 ldap_base_dn = All(BaseDnValidator, UnicodeString(strip=True,))
482
483
483 return _LdapSettingsForm
484 return _LdapSettingsForm
@@ -1,87 +1,92 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for RhodeCode settings
3 # Model for RhodeCode settings
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 Nov 17, 2010
21 Created on Nov 17, 2010
22 Model for RhodeCode
22 Model for RhodeCode
23 :author: marcink
23 :author: marcink
24 """
24 """
25
25
26 from rhodecode.lib import helpers as h
26 from rhodecode.lib import helpers as h
27 from rhodecode.model import BaseModel
27 from rhodecode.model import BaseModel
28 from rhodecode.model.caching_query import FromCache
28 from rhodecode.model.caching_query import FromCache
29 from rhodecode.model.db import RhodeCodeSettings
29 from rhodecode.model.db import RhodeCodeSettings
30 from sqlalchemy.orm import joinedload
30 from sqlalchemy.orm import joinedload
31 import logging
31 import logging
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
35 class SettingsModel(BaseModel):
35 class SettingsModel(BaseModel):
36 """
36 """
37 Settings model
37 Settings model
38 """
38 """
39
39
40 def get(self, settings_key, cache=False):
40 def get(self, settings_key, cache=False):
41 r = self.sa.query(RhodeCodeSettings)\
41 r = self.sa.query(RhodeCodeSettings)\
42 .filter(RhodeCodeSettings.app_settings_name == settings_key).scalar()
42 .filter(RhodeCodeSettings.app_settings_name == settings_key).scalar()
43 if cache:
43 if cache:
44 r = r.options(FromCache("sql_cache_short",
44 r = r.options(FromCache("sql_cache_short",
45 "get_setting_%s" % settings_key))
45 "get_setting_%s" % settings_key))
46 return r
46 return r
47
47
48 def get_app_settings(self):
48 def get_app_settings(self):
49 """Get's config from database, each config key is prefixed with
50 'rhodecode_' prefix, than global pylons config is updated with such
51 keys
52 """
53
49 ret = self.sa.query(RhodeCodeSettings)\
54 ret = self.sa.query(RhodeCodeSettings)\
50 .options(FromCache("sql_cache_short",
55 .options(FromCache("sql_cache_short",
51 "get_hg_settings")).all()
56 "get_hg_settings")).all()
52
57
53 if not ret:
58 if not ret:
54 raise Exception('Could not get application settings !')
59 raise Exception('Could not get application settings !')
55 settings = {}
60 settings = {}
56 for each in ret:
61 for each in ret:
57 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
62 settings['rhodecode_' + each.app_settings_name] = each.app_settings_value
58
63
59 return settings
64 return settings
60
65
61 def get_ldap_settings(self):
66 def get_ldap_settings(self):
62 """
67 """
63 Returns ldap settings from database
68 Returns ldap settings from database
64 :returns:
69 :returns:
65 ldap_active
70 ldap_active
66 ldap_host
71 ldap_host
67 ldap_port
72 ldap_port
68 ldap_ldaps
73 ldap_ldaps
69 ldap_dn_user
74 ldap_dn_user
70 ldap_dn_pass
75 ldap_dn_pass
71 ldap_base_dn
76 ldap_base_dn
72 """
77 """
73
78
74 r = self.sa.query(RhodeCodeSettings)\
79 r = self.sa.query(RhodeCodeSettings)\
75 .filter(RhodeCodeSettings.app_settings_name\
80 .filter(RhodeCodeSettings.app_settings_name\
76 .startswith('ldap_'))\
81 .startswith('ldap_'))\
77 .all()
82 .all()
78
83
79 fd = {}
84 fd = {}
80
85
81 for row in r:
86 for row in r:
82 v = row.app_settings_value
87 v = row.app_settings_value
83 if v in ['0', '1']:
88 if v in ['0', '1']:
84 v = v == '1'
89 v = v == '1'
85 fd.update({row.app_settings_name:v})
90 fd.update({row.app_settings_name:v})
86
91
87 return fd
92 return fd
@@ -1,180 +1,189 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 ${_('Settings administration')} - ${c.rhodecode_name}
5 ${_('Settings administration')} - ${c.rhodecode_name}
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'))} &raquo; ${_('Settings')}
9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Settings')}
10 </%def>
10 </%def>
11
11
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 ${self.menu('admin')}
13 ${self.menu('admin')}
14 </%def>
14 </%def>
15
15
16 <%def name="main()">
16 <%def name="main()">
17 <div class="box">
17 <div class="box">
18 <!-- box / title -->
18 <!-- box / title -->
19 <div class="title">
19 <div class="title">
20 ${self.breadcrumbs()}
20 ${self.breadcrumbs()}
21 </div>
21 </div>
22 <!-- end box / title -->
22 <!-- end box / title -->
23
23
24 <h3>${_('Remap and rescan repositories')}</h3>
24 <h3>${_('Remap and rescan repositories')}</h3>
25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
26 <div class="form">
26 <div class="form">
27 <!-- fields -->
27 <!-- fields -->
28
28
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label label-checkbox">
31 <div class="label label-checkbox">
32 <label for="destroy">${_('rescan option')}:</label>
32 <label for="destroy">${_('rescan option')}:</label>
33 </div>
33 </div>
34 <div class="checkboxes">
34 <div class="checkboxes">
35 <div class="checkbox">
35 <div class="checkbox">
36 ${h.checkbox('destroy',True)}
36 ${h.checkbox('destroy',True)}
37 <label for="checkbox-1">
37 <label for="checkbox-1">
38 <span class="tooltip" tooltip_title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
38 <span class="tooltip" tooltip_title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
39 ${_('destroy old data')}</span> </label>
39 ${_('destroy old data')}</span> </label>
40 </div>
40 </div>
41 </div>
41 </div>
42 </div>
42 </div>
43
43
44 <div class="buttons">
44 <div class="buttons">
45 ${h.submit('rescan','Rescan repositories',class_="ui-button")}
45 ${h.submit('rescan','Rescan repositories',class_="ui-button")}
46 </div>
46 </div>
47 </div>
47 </div>
48 </div>
48 </div>
49 ${h.end_form()}
49 ${h.end_form()}
50
50
51 <h3>${_('Whoosh indexing')}</h3>
51 <h3>${_('Whoosh indexing')}</h3>
52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
53 <div class="form">
53 <div class="form">
54 <!-- fields -->
54 <!-- fields -->
55
55
56 <div class="fields">
56 <div class="fields">
57 <div class="field">
57 <div class="field">
58 <div class="label label-checkbox">
58 <div class="label label-checkbox">
59 <label for="destroy">${_('index build option')}:</label>
59 <label for="destroy">${_('index build option')}:</label>
60 </div>
60 </div>
61 <div class="checkboxes">
61 <div class="checkboxes">
62 <div class="checkbox">
62 <div class="checkbox">
63 ${h.checkbox('full_index',True)}
63 ${h.checkbox('full_index',True)}
64 <label for="checkbox-1">${_('build from scratch')}</label>
64 <label for="checkbox-1">${_('build from scratch')}</label>
65 </div>
65 </div>
66 </div>
66 </div>
67 </div>
67 </div>
68
68
69 <div class="buttons">
69 <div class="buttons">
70 ${h.submit('reindex','Reindex',class_="ui-button")}
70 ${h.submit('reindex','Reindex',class_="ui-button")}
71 </div>
71 </div>
72 </div>
72 </div>
73 </div>
73 </div>
74 ${h.end_form()}
74 ${h.end_form()}
75
75
76 <h3>${_('Global application settings')}</h3>
76 <h3>${_('Global application settings')}</h3>
77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
78 <div class="form">
78 <div class="form">
79 <!-- fields -->
79 <!-- fields -->
80
80
81 <div class="fields">
81 <div class="fields">
82
82
83 <div class="field">
83 <div class="field">
84 <div class="label">
84 <div class="label">
85 <label for="rhodecode_title">${_('Application name')}:</label>
85 <label for="rhodecode_title">${_('Application name')}:</label>
86 </div>
86 </div>
87 <div class="input">
87 <div class="input">
88 ${h.text('rhodecode_title',size=30)}
88 ${h.text('rhodecode_title',size=30)}
89 </div>
89 </div>
90 </div>
90 </div>
91
91
92 <div class="field">
92 <div class="field">
93 <div class="label">
93 <div class="label">
94 <label for="rhodecode_realm">${_('Realm text')}:</label>
94 <label for="rhodecode_realm">${_('Realm text')}:</label>
95 </div>
95 </div>
96 <div class="input">
96 <div class="input">
97 ${h.text('rhodecode_realm',size=30)}
97 ${h.text('rhodecode_realm',size=30)}
98 </div>
98 </div>
99 </div>
99 </div>
100
100
101 <div class="field">
102 <div class="label">
103 <label for="ga_code">${_('Google analytics code')}:</label>
104 </div>
105 <div class="input">
106 ${h.text('ga_code',size=30)}
107 </div>
108 </div>
109
101 <div class="buttons">
110 <div class="buttons">
102 ${h.submit('save','Save settings',class_="ui-button")}
111 ${h.submit('save','Save settings',class_="ui-button")}
103 ${h.reset('reset','Reset',class_="ui-button")}
112 ${h.reset('reset','Reset',class_="ui-button")}
104 </div>
113 </div>
105 </div>
114 </div>
106 </div>
115 </div>
107 ${h.end_form()}
116 ${h.end_form()}
108
117
109 <h3>${_('Mercurial settings')}</h3>
118 <h3>${_('Mercurial settings')}</h3>
110 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
119 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
111 <div class="form">
120 <div class="form">
112 <!-- fields -->
121 <!-- fields -->
113
122
114 <div class="fields">
123 <div class="fields">
115
124
116 <div class="field">
125 <div class="field">
117 <div class="label label-checkbox">
126 <div class="label label-checkbox">
118 <label for="web_push_ssl">${_('Web')}:</label>
127 <label for="web_push_ssl">${_('Web')}:</label>
119 </div>
128 </div>
120 <div class="checkboxes">
129 <div class="checkboxes">
121 <div class="checkbox">
130 <div class="checkbox">
122 ${h.checkbox('web_push_ssl','true')}
131 ${h.checkbox('web_push_ssl','true')}
123 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
132 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
124 </div>
133 </div>
125 </div>
134 </div>
126 </div>
135 </div>
127
136
128 <div class="field">
137 <div class="field">
129 <div class="label label-checkbox">
138 <div class="label label-checkbox">
130 <label for="web_push_ssl">${_('Hooks')}:</label>
139 <label for="web_push_ssl">${_('Hooks')}:</label>
131 </div>
140 </div>
132 <div class="checkboxes">
141 <div class="checkboxes">
133 <div class="checkbox">
142 <div class="checkbox">
134 ${h.checkbox('hooks_changegroup_update','True')}
143 ${h.checkbox('hooks_changegroup_update','True')}
135 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
144 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
136 </div>
145 </div>
137 <div class="checkbox">
146 <div class="checkbox">
138 ${h.checkbox('hooks_changegroup_repo_size','True')}
147 ${h.checkbox('hooks_changegroup_repo_size','True')}
139 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
148 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
140 </div>
149 </div>
141 <div class="checkbox">
150 <div class="checkbox">
142 ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
151 ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
143 <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
152 <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
144 </div>
153 </div>
145 <div class="checkbox">
154 <div class="checkbox">
146 ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
155 ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
147 <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
156 <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
148 </div>
157 </div>
149 </div>
158 </div>
150 </div>
159 </div>
151
160
152 <div class="field">
161 <div class="field">
153 <div class="label">
162 <div class="label">
154 <label for="paths_root_path">${_('Repositories location')}:</label>
163 <label for="paths_root_path">${_('Repositories location')}:</label>
155 </div>
164 </div>
156 <div class="input">
165 <div class="input">
157 ${h.text('paths_root_path',size=30,readonly="readonly")}
166 ${h.text('paths_root_path',size=30,readonly="readonly")}
158 <span id="path_unlock" class="tooltip"
167 <span id="path_unlock" class="tooltip"
159 tooltip_title="${h.tooltip(_('This a crucial application setting. If You really sure you need to change this, you must restart application in order to make this settings take effect. Click this label to unlock.'))}">
168 tooltip_title="${h.tooltip(_('This a crucial application setting. If You really sure you need to change this, you must restart application in order to make this settings take effect. Click this label to unlock.'))}">
160 ${_('unlock')}</span>
169 ${_('unlock')}</span>
161 </div>
170 </div>
162 </div>
171 </div>
163
172
164 <div class="buttons">
173 <div class="buttons">
165 ${h.submit('save','Save settings',class_="ui-button")}
174 ${h.submit('save','Save settings',class_="ui-button")}
166 ${h.reset('reset','Reset',class_="ui-button")}
175 ${h.reset('reset','Reset',class_="ui-button")}
167 </div>
176 </div>
168 </div>
177 </div>
169 </div>
178 </div>
170 ${h.end_form()}
179 ${h.end_form()}
171
180
172 <script type="text/javascript">
181 <script type="text/javascript">
173 YAHOO.util.Event.onDOMReady(function(){
182 YAHOO.util.Event.onDOMReady(function(){
174 YAHOO.util.Event.addListener('path_unlock','click',function(){
183 YAHOO.util.Event.addListener('path_unlock','click',function(){
175 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
184 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
176 });
185 });
177 });
186 });
178 </script>
187 </script>
179 </div>
188 </div>
180 </%def>
189 </%def>
@@ -1,365 +1,381 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/icons/database_gear.png" type="image/png" />
6 <link rel="icon" href="/images/icons/database_gear.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 %if c.ga_code:
14 <script type="text/javascript">
15
16 var _gaq = _gaq || [];
17 _gaq.push(['_setAccount', '${c.ga_code}']);
18 _gaq.push(['_trackPageview']);
19
20 (function() {
21 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
22 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
23 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
24 })();
25
26
27 </script>
28 %endif
13 </head>
29 </head>
14 <body>
30 <body>
15 <!-- header -->
31 <!-- header -->
16 <div id="header">
32 <div id="header">
17 <!-- user -->
33 <!-- user -->
18 <ul id="logged-user">
34 <ul id="logged-user">
19 <li class="first">
35 <li class="first">
20 <div class="gravatar">
36 <div class="gravatar">
21 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
37 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
22 </div>
38 </div>
23 <div class="account">
39 <div class="account">
24 %if c.rhodecode_user.username == 'default':
40 %if c.rhodecode_user.username == 'default':
25 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
41 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
26 ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
42 ${h.link_to('anonymous',h.url('register'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
27 %else:
43 %else:
28 ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
44 ${h.link_to('anonymous',h.url('#'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
29 %endif
45 %endif
30
46
31 %else:
47 %else:
32 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
48 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
33 %endif
49 %endif
34 </div>
50 </div>
35 </li>
51 </li>
36 <li>
52 <li>
37 <a href="${h.url('home')}">${_('Home')}</a>
53 <a href="${h.url('home')}">${_('Home')}</a>
38 </li>
54 </li>
39 %if c.rhodecode_user.username != 'default':
55 %if c.rhodecode_user.username != 'default':
40 <li>
56 <li>
41 <a href="${h.url('journal')}">${_('Journal')}</a>
57 <a href="${h.url('journal')}">${_('Journal')}</a>
42 ##(${c.unread_journal})</a>
58 ##(${c.unread_journal})</a>
43 </li>
59 </li>
44 %endif
60 %endif
45 %if c.rhodecode_user.username == 'default':
61 %if c.rhodecode_user.username == 'default':
46 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
62 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
47 %else:
63 %else:
48 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
64 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
49 %endif
65 %endif
50 </ul>
66 </ul>
51 <!-- end user -->
67 <!-- end user -->
52 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
68 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
53 <!-- logo -->
69 <!-- logo -->
54 <div id="logo">
70 <div id="logo">
55 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
71 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
56 </div>
72 </div>
57 <!-- end logo -->
73 <!-- end logo -->
58 <!-- menu -->
74 <!-- menu -->
59 ${self.page_nav()}
75 ${self.page_nav()}
60 <!-- quick -->
76 <!-- quick -->
61 </div>
77 </div>
62 </div>
78 </div>
63 <!-- end header -->
79 <!-- end header -->
64
80
65 <!-- CONTENT -->
81 <!-- CONTENT -->
66 <div id="content">
82 <div id="content">
67 <div class="flash_msg">
83 <div class="flash_msg">
68 <% messages = h.flash.pop_messages() %>
84 <% messages = h.flash.pop_messages() %>
69 % if messages:
85 % if messages:
70 <ul id="flash-messages">
86 <ul id="flash-messages">
71 % for message in messages:
87 % for message in messages:
72 <li class="${message.category}_msg">${message}</li>
88 <li class="${message.category}_msg">${message}</li>
73 % endfor
89 % endfor
74 </ul>
90 </ul>
75 % endif
91 % endif
76 </div>
92 </div>
77 <div id="main">
93 <div id="main">
78 ${next.main()}
94 ${next.main()}
79 </div>
95 </div>
80 </div>
96 </div>
81 <!-- END CONTENT -->
97 <!-- END CONTENT -->
82
98
83 <!-- footer -->
99 <!-- footer -->
84 <div id="footer">
100 <div id="footer">
85 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
101 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
86 <div>
102 <div>
87 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
103 <p class="footer-link">${h.link_to(_('Submit a bug'),h.url('bugtracker'))}</p>
88 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
104 <p class="footer-link">${h.link_to(_('GPL license'),h.url('gpl_license'))}</p>
89 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
105 <p>RhodeCode ${c.rhodecode_version} &copy; 2010 by Marcin Kuzminski</p>
90 </div>
106 </div>
91 </div>
107 </div>
92 <script type="text/javascript">${h.tooltip.activate()}</script>
108 <script type="text/javascript">${h.tooltip.activate()}</script>
93 </div>
109 </div>
94 <!-- end footer -->
110 <!-- end footer -->
95 </body>
111 </body>
96
112
97 </html>
113 </html>
98
114
99 ### MAKO DEFS ###
115 ### MAKO DEFS ###
100 <%def name="page_nav()">
116 <%def name="page_nav()">
101 ${self.menu()}
117 ${self.menu()}
102 </%def>
118 </%def>
103
119
104 <%def name="menu(current=None)">
120 <%def name="menu(current=None)">
105 <%
121 <%
106 def is_current(selected):
122 def is_current(selected):
107 if selected == current:
123 if selected == current:
108 return h.literal('class="current"')
124 return h.literal('class="current"')
109 %>
125 %>
110 %if current not in ['home','admin']:
126 %if current not in ['home','admin']:
111 ##REGULAR MENU
127 ##REGULAR MENU
112 <ul id="quick">
128 <ul id="quick">
113 <!-- repo switcher -->
129 <!-- repo switcher -->
114 <li>
130 <li>
115 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
131 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
116 <span class="icon">
132 <span class="icon">
117 <img src="/images/icons/database.png" alt="${_('Products')}" />
133 <img src="/images/icons/database.png" alt="${_('Products')}" />
118 </span>
134 </span>
119 <span>&darr;</span>
135 <span>&darr;</span>
120 </a>
136 </a>
121 <ul class="repo_switcher">
137 <ul class="repo_switcher">
122 %for repo in c.cached_repo_list:
138 %for repo in c.cached_repo_list:
123
139
124 %if repo['repo'].dbrepo.private:
140 %if repo['repo'].dbrepo.private:
125 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
141 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
126 %else:
142 %else:
127 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
143 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
128 %endif
144 %endif
129 %endfor
145 %endfor
130 </ul>
146 </ul>
131 </li>
147 </li>
132
148
133 <li ${is_current('summary')}>
149 <li ${is_current('summary')}>
134 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
150 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
135 <span class="icon">
151 <span class="icon">
136 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
152 <img src="/images/icons/clipboard_16.png" alt="${_('Summary')}" />
137 </span>
153 </span>
138 <span>${_('Summary')}</span>
154 <span>${_('Summary')}</span>
139 </a>
155 </a>
140 </li>
156 </li>
141 ##<li ${is_current('shortlog')}>
157 ##<li ${is_current('shortlog')}>
142 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
158 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
143 ## <span class="icon">
159 ## <span class="icon">
144 ## <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
160 ## <img src="/images/icons/application_view_list.png" alt="${_('Shortlog')}" />
145 ## </span>
161 ## </span>
146 ## <span>${_('Shortlog')}</span>
162 ## <span>${_('Shortlog')}</span>
147 ## </a>
163 ## </a>
148 ##</li>
164 ##</li>
149 <li ${is_current('changelog')}>
165 <li ${is_current('changelog')}>
150 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
166 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
151 <span class="icon">
167 <span class="icon">
152 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
168 <img src="/images/icons/time.png" alt="${_('Changelog')}" />
153 </span>
169 </span>
154 <span>${_('Changelog')}</span>
170 <span>${_('Changelog')}</span>
155 </a>
171 </a>
156 </li>
172 </li>
157
173
158 <li ${is_current('switch_to')}>
174 <li ${is_current('switch_to')}>
159 <a title="${_('Switch to')}" href="#">
175 <a title="${_('Switch to')}" href="#">
160 <span class="icon">
176 <span class="icon">
161 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
177 <img src="/images/icons/arrow_switch.png" alt="${_('Switch to')}" />
162 </span>
178 </span>
163 <span>${_('Switch to')}</span>
179 <span>${_('Switch to')}</span>
164 </a>
180 </a>
165 <ul>
181 <ul>
166 <li>
182 <li>
167 ${h.link_to('%s (%s)' % (_('branches'),len(c.repository_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
183 ${h.link_to('%s (%s)' % (_('branches'),len(c.repository_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
168 <ul>
184 <ul>
169 %if c.repository_branches.values():
185 %if c.repository_branches.values():
170 %for cnt,branch in enumerate(c.repository_branches.items()):
186 %for cnt,branch in enumerate(c.repository_branches.items()):
171 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
187 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
172 %endfor
188 %endfor
173 %else:
189 %else:
174 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
190 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
175 %endif
191 %endif
176 </ul>
192 </ul>
177 </li>
193 </li>
178 <li>
194 <li>
179 ${h.link_to('%s (%s)' % (_('tags'),len(c.repository_tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
195 ${h.link_to('%s (%s)' % (_('tags'),len(c.repository_tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
180 <ul>
196 <ul>
181 %if c.repository_tags.values():
197 %if c.repository_tags.values():
182 %for cnt,tag in enumerate(c.repository_tags.items()):
198 %for cnt,tag in enumerate(c.repository_tags.items()):
183 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
199 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
184 %endfor
200 %endfor
185 %else:
201 %else:
186 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
202 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
187 %endif
203 %endif
188 </ul>
204 </ul>
189 </li>
205 </li>
190 </ul>
206 </ul>
191 </li>
207 </li>
192 <li ${is_current('files')}>
208 <li ${is_current('files')}>
193 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
209 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
194 <span class="icon">
210 <span class="icon">
195 <img src="/images/icons/file.png" alt="${_('Files')}" />
211 <img src="/images/icons/file.png" alt="${_('Files')}" />
196 </span>
212 </span>
197 <span>${_('Files')}</span>
213 <span>${_('Files')}</span>
198 </a>
214 </a>
199 </li>
215 </li>
200
216
201 <li ${is_current('options')}>
217 <li ${is_current('options')}>
202 <a title="${_('Options')}" href="#">
218 <a title="${_('Options')}" href="#">
203 <span class="icon">
219 <span class="icon">
204 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
220 <img src="/images/icons/table_gear.png" alt="${_('Admin')}" />
205 </span>
221 </span>
206 <span>${_('Options')}</span>
222 <span>${_('Options')}</span>
207 </a>
223 </a>
208 <ul>
224 <ul>
209 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
225 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
210 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
226 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
211 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
227 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
212 %endif
228 %endif
213 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
229 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
214
230
215 %if h.HasPermissionAll('hg.admin')('access admin main page'):
231 %if h.HasPermissionAll('hg.admin')('access admin main page'):
216 <li>
232 <li>
217 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
233 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
218 <%def name="admin_menu()">
234 <%def name="admin_menu()">
219 <ul>
235 <ul>
220 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
236 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
221 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
237 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
222 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
238 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
223 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
239 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
224 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
240 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
225 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
241 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
226 </ul>
242 </ul>
227 </%def>
243 </%def>
228
244
229 ${admin_menu()}
245 ${admin_menu()}
230 </li>
246 </li>
231 %endif
247 %endif
232
248
233 </ul>
249 </ul>
234 </li>
250 </li>
235
251
236 <li>
252 <li>
237 <a title="${_('Followers')}" href="#">
253 <a title="${_('Followers')}" href="#">
238 <span class="icon_short">
254 <span class="icon_short">
239 <img src="/images/icons/heart.png" alt="${_('Followers')}" />
255 <img src="/images/icons/heart.png" alt="${_('Followers')}" />
240 </span>
256 </span>
241 <span class="short">${c.repository_followers}</span>
257 <span class="short">${c.repository_followers}</span>
242 </a>
258 </a>
243 </li>
259 </li>
244 <li>
260 <li>
245 <a title="${_('Forks')}" href="#">
261 <a title="${_('Forks')}" href="#">
246 <span class="icon_short">
262 <span class="icon_short">
247 <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
263 <img src="/images/icons/arrow_divide.png" alt="${_('Forks')}" />
248 </span>
264 </span>
249 <span class="short">${c.repository_forks}</span>
265 <span class="short">${c.repository_forks}</span>
250 </a>
266 </a>
251 </li>
267 </li>
252
268
253
269
254
270
255 </ul>
271 </ul>
256 %else:
272 %else:
257 ##ROOT MENU
273 ##ROOT MENU
258 <ul id="quick">
274 <ul id="quick">
259 <li>
275 <li>
260 <a title="${_('Home')}" href="${h.url('home')}">
276 <a title="${_('Home')}" href="${h.url('home')}">
261 <span class="icon">
277 <span class="icon">
262 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
278 <img src="/images/icons/home_16.png" alt="${_('Home')}" />
263 </span>
279 </span>
264 <span>${_('Home')}</span>
280 <span>${_('Home')}</span>
265 </a>
281 </a>
266 </li>
282 </li>
267 %if c.rhodecode_user.username != 'default':
283 %if c.rhodecode_user.username != 'default':
268 <li>
284 <li>
269 <a title="${_('Journal')}" href="${h.url('journal')}">
285 <a title="${_('Journal')}" href="${h.url('journal')}">
270 <span class="icon">
286 <span class="icon">
271 <img src="/images/icons/book.png" alt="${_('Journal')}" />
287 <img src="/images/icons/book.png" alt="${_('Journal')}" />
272 </span>
288 </span>
273 <span>${_('Journal')}</span>
289 <span>${_('Journal')}</span>
274 </a>
290 </a>
275 </li>
291 </li>
276 %endif
292 %endif
277 <li>
293 <li>
278 <a title="${_('Search')}" href="${h.url('search')}">
294 <a title="${_('Search')}" href="${h.url('search')}">
279 <span class="icon">
295 <span class="icon">
280 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
296 <img src="/images/icons/search_16.png" alt="${_('Search')}" />
281 </span>
297 </span>
282 <span>${_('Search')}</span>
298 <span>${_('Search')}</span>
283 </a>
299 </a>
284 </li>
300 </li>
285
301
286 %if h.HasPermissionAll('hg.admin')('access admin main page'):
302 %if h.HasPermissionAll('hg.admin')('access admin main page'):
287 <li ${is_current('admin')}>
303 <li ${is_current('admin')}>
288 <a title="${_('Admin')}" href="${h.url('admin_home')}">
304 <a title="${_('Admin')}" href="${h.url('admin_home')}">
289 <span class="icon">
305 <span class="icon">
290 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
306 <img src="/images/icons/cog_edit.png" alt="${_('Admin')}" />
291 </span>
307 </span>
292 <span>${_('Admin')}</span>
308 <span>${_('Admin')}</span>
293 </a>
309 </a>
294 ${admin_menu()}
310 ${admin_menu()}
295 </li>
311 </li>
296 %endif
312 %endif
297 </ul>
313 </ul>
298 %endif
314 %endif
299 </%def>
315 </%def>
300
316
301
317
302 <%def name="css()">
318 <%def name="css()">
303 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
319 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
304 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
320 <link rel="stylesheet" type="text/css" href="/css/pygments.css" />
305 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
321 <link rel="stylesheet" type="text/css" href="/css/diff.css" />
306 </%def>
322 </%def>
307
323
308 <%def name="js()">
324 <%def name="js()">
309 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
325 ##<script type="text/javascript" src="/js/yui/utilities/utilities.js"></script>
310 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
326 ##<script type="text/javascript" src="/js/yui/container/container.js"></script>
311 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
327 ##<script type="text/javascript" src="/js/yui/datasource/datasource.js"></script>
312 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
328 ##<script type="text/javascript" src="/js/yui/autocomplete/autocomplete.js"></script>
313 ##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
329 ##<script type="text/javascript" src="/js/yui/selector/selector-min.js"></script>
314
330
315 <script type="text/javascript" src="/js/yui2a.js"></script>
331 <script type="text/javascript" src="/js/yui2a.js"></script>
316 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
332 <!--[if IE]><script language="javascript" type="text/javascript" src="/js/excanvas.min.js"></script><![endif]-->
317 <script type="text/javascript" src="/js/yui.flot.js"></script>
333 <script type="text/javascript" src="/js/yui.flot.js"></script>
318
334
319 <script type="text/javascript">
335 <script type="text/javascript">
320 var base_url ='/_admin/toggle_following';
336 var base_url ='/_admin/toggle_following';
321 var YUC = YAHOO.util.Connect;
337 var YUC = YAHOO.util.Connect;
322 var YUD = YAHOO.util.Dom;
338 var YUD = YAHOO.util.Dom;
323 var YUE = YAHOO.util.Event;
339 var YUE = YAHOO.util.Event;
324
340
325 function onSuccess(){
341 function onSuccess(){
326
342
327 var f = YUD.get('follow_toggle');
343 var f = YUD.get('follow_toggle');
328 if(f.getAttribute('class')=='follow'){
344 if(f.getAttribute('class')=='follow'){
329 f.setAttribute('class','following');
345 f.setAttribute('class','following');
330 f.setAttribute('title',"${_('Stop following this repository')}");
346 f.setAttribute('title',"${_('Stop following this repository')}");
331 }
347 }
332 else{
348 else{
333 f.setAttribute('class','follow');
349 f.setAttribute('class','follow');
334 f.setAttribute('title',"${_('Start following this repository')}");
350 f.setAttribute('title',"${_('Start following this repository')}");
335 }
351 }
336 }
352 }
337
353
338 function toggleFollowingUser(fallows_user_id,token){
354 function toggleFollowingUser(fallows_user_id,token){
339 args = 'follows_user_id='+fallows_user_id;
355 args = 'follows_user_id='+fallows_user_id;
340 args+= '&auth_token='+token;
356 args+= '&auth_token='+token;
341 YUC.asyncRequest('POST',base_url,{
357 YUC.asyncRequest('POST',base_url,{
342 success:function(o){
358 success:function(o){
343 onSuccess();
359 onSuccess();
344 }
360 }
345 },args); return false;
361 },args); return false;
346 }
362 }
347
363
348 function toggleFollowingRepo(fallows_repo_id,token){
364 function toggleFollowingRepo(fallows_repo_id,token){
349 args = 'follows_repo_id='+fallows_repo_id;
365 args = 'follows_repo_id='+fallows_repo_id;
350 args+= '&auth_token='+token;
366 args+= '&auth_token='+token;
351 YUC.asyncRequest('POST',base_url,{
367 YUC.asyncRequest('POST',base_url,{
352 success:function(o){
368 success:function(o){
353 onSuccess();
369 onSuccess();
354 }
370 }
355 },args); return false;
371 },args); return false;
356 }
372 }
357 </script>
373 </script>
358
374
359 </%def>
375 </%def>
360
376
361 <%def name="breadcrumbs()">
377 <%def name="breadcrumbs()">
362 <div class="breadcrumbs">
378 <div class="breadcrumbs">
363 ${self.breadcrumbs_links()}
379 ${self.breadcrumbs_links()}
364 </div>
380 </div>
365 </%def> No newline at end of file
381 </%def>
General Comments 0
You need to be logged in to leave comments. Login now