##// END OF EJS Templates
fixed spelling mistakes, and some minor docs bugs
marcink -
r860:5f7731e3 beta
parent child Browse files
Show More
@@ -1,106 +1,104 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 package.rhodecode.controllers.admin.ldap_settings
4 4 ~~~~~~~~~~~~~~
5 5
6 6 ldap controller for RhodeCode
7 7 :created_on: Nov 26, 2010
8 8 :author: marcink
9 9 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 10 :license: GPLv3, see COPYING for more details.
11 11 """
12 12 # This program is free software; you can redistribute it and/or
13 13 # modify it under the terms of the GNU General Public License
14 14 # as published by the Free Software Foundation; version 2
15 15 # of the License or (at your opinion) any later version of the license.
16 16 #
17 17 # This program is distributed in the hope that it will be useful,
18 18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 20 # GNU General Public License for more details.
21 21 #
22 22 # You should have received a copy of the GNU General Public License
23 23 # along with this program; if not, write to the Free Software
24 24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 25 # MA 02110-1301, USA.
26 26 import logging
27 27 import formencode
28 28 import traceback
29 29
30 30 from formencode import htmlfill
31 31
32 32 from pylons import request, response, session, tmpl_context as c, url
33 33 from pylons.controllers.util import abort, redirect
34 34 from pylons.i18n.translation import _
35 35
36 36 from rhodecode.lib.base import BaseController, render
37 37 from rhodecode.lib import helpers as h
38 38 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
39 39 from rhodecode.lib.auth_ldap import LdapImportError
40 40 from rhodecode.model.settings import SettingsModel
41 41 from rhodecode.model.forms import LdapSettingsForm
42 42 from sqlalchemy.exc import DatabaseError
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46
47 47
48 48 class LdapSettingsController(BaseController):
49 49
50 50 @LoginRequired()
51 51 @HasPermissionAllDecorator('hg.admin')
52 52 def __before__(self):
53 53 c.admin_user = session.get('admin_user')
54 54 c.admin_username = session.get('admin_username')
55 55 super(LdapSettingsController, self).__before__()
56 56
57 57 def index(self):
58 58 defaults = SettingsModel().get_ldap_settings()
59 59
60 60 return htmlfill.render(
61 61 render('admin/ldap/ldap.html'),
62 62 defaults=defaults,
63 63 encoding="UTF-8",
64 64 force_defaults=True,)
65 65
66 66 def ldap_settings(self):
67 """
68 POST ldap create and store ldap settings
69 """
67 """POST ldap create and store ldap settings"""
70 68
71 69 settings_model = SettingsModel()
72 70 _form = LdapSettingsForm()()
73 71
74 72 try:
75 73 form_result = _form.to_python(dict(request.POST))
76 74 try:
77 75
78 76 for k, v in form_result.items():
79 77 if k.startswith('ldap_'):
80 78 setting = settings_model.get(k)
81 79 setting.app_settings_value = v
82 80 self.sa.add(setting)
83 81
84 82 self.sa.commit()
85 83 h.flash(_('Ldap settings updated successfully'),
86 84 category='success')
87 85 except (DatabaseError,):
88 86 raise
89 87 except LdapImportError:
90 88 h.flash(_('Unable to activate ldap. The "python-ldap" library '
91 89 'is missing.'), category='warning')
92 90
93 91 except formencode.Invalid, errors:
94 92
95 93 return htmlfill.render(
96 94 render('admin/ldap/ldap.html'),
97 95 defaults=errors.value,
98 96 errors=errors.error_dict or {},
99 97 prefix_error=False,
100 98 encoding="UTF-8")
101 99 except Exception:
102 100 log.error(traceback.format_exc())
103 h.flash(_('error occured during update of ldap settings'),
101 h.flash(_('error occurred during update of ldap settings'),
104 102 category='error')
105 103
106 104 return redirect(url('ldap_home'))
@@ -1,171 +1,171 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.permissions
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 permissions controller for Rhodecode
7 7
8 8 :created_on: Apr 27, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 from formencode import htmlfill
29 29 from pylons import request, session, tmpl_context as c, url
30 30 from pylons.controllers.util import abort, redirect
31 31 from pylons.i18n.translation import _
32 32 from rhodecode.lib import helpers as h
33 33 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
34 34 from rhodecode.lib.auth_ldap import LdapImportError
35 35 from rhodecode.lib.base import BaseController, render
36 36 from rhodecode.model.forms import LdapSettingsForm, DefaultPermissionsForm
37 37 from rhodecode.model.permission import PermissionModel
38 38 from rhodecode.model.settings import SettingsModel
39 39 from rhodecode.model.user import UserModel
40 40 import formencode
41 41 import logging
42 42 import traceback
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46 class PermissionsController(BaseController):
47 47 """REST Controller styled on the Atom Publishing Protocol"""
48 48 # To properly map this controller, ensure your config/routing.py
49 49 # file has a resource setup:
50 50 # map.resource('permission', 'permissions')
51 51
52 52 @LoginRequired()
53 53 @HasPermissionAllDecorator('hg.admin')
54 54 def __before__(self):
55 55 c.admin_user = session.get('admin_user')
56 56 c.admin_username = session.get('admin_username')
57 57 super(PermissionsController, self).__before__()
58 58
59 59 self.perms_choices = [('repository.none', _('None'),),
60 60 ('repository.read', _('Read'),),
61 61 ('repository.write', _('Write'),),
62 62 ('repository.admin', _('Admin'),)]
63 63 self.register_choices = [
64 64 ('hg.register.none',
65 65 _('disabled')),
66 66 ('hg.register.manual_activate',
67 67 _('allowed with manual account activation')),
68 68 ('hg.register.auto_activate',
69 69 _('allowed with automatic account activation')), ]
70 70
71 71 self.create_choices = [('hg.create.none', _('Disabled')),
72 72 ('hg.create.repository', _('Enabled'))]
73 73
74 74
75 75 def index(self, format='html'):
76 76 """GET /permissions: All items in the collection"""
77 77 # url('permissions')
78 78
79 79 def create(self):
80 80 """POST /permissions: Create a new item"""
81 81 # url('permissions')
82 82
83 83 def new(self, format='html'):
84 84 """GET /permissions/new: Form to create a new item"""
85 85 # url('new_permission')
86 86
87 87 def update(self, id):
88 88 """PUT /permissions/id: Update an existing item"""
89 89 # Forms posted to this method should contain a hidden field:
90 90 # <input type="hidden" name="_method" value="PUT" />
91 91 # Or using helpers:
92 92 # h.form(url('permission', id=ID),
93 93 # method='put')
94 94 # url('permission', id=ID)
95 95
96 96 permission_model = PermissionModel()
97 97
98 98 _form = DefaultPermissionsForm([x[0] for x in self.perms_choices],
99 99 [x[0] for x in self.register_choices],
100 100 [x[0] for x in self.create_choices])()
101 101
102 102 try:
103 103 form_result = _form.to_python(dict(request.POST))
104 104 form_result.update({'perm_user_name':id})
105 105 permission_model.update(form_result)
106 106 h.flash(_('Default permissions updated successfully'),
107 107 category='success')
108 108
109 109 except formencode.Invalid, errors:
110 110 c.perms_choices = self.perms_choices
111 111 c.register_choices = self.register_choices
112 112 c.create_choices = self.create_choices
113 113 defaults = errors.value
114 114
115 115 return htmlfill.render(
116 116 render('admin/permissions/permissions.html'),
117 117 defaults=defaults,
118 118 errors=errors.error_dict or {},
119 119 prefix_error=False,
120 120 encoding="UTF-8")
121 121 except Exception:
122 122 log.error(traceback.format_exc())
123 h.flash(_('error occured during update of permissions'),
123 h.flash(_('error occurred during update of permissions'),
124 124 category='error')
125 125
126 126 return redirect(url('edit_permission', id=id))
127 127
128 128
129 129
130 130 def delete(self, id):
131 131 """DELETE /permissions/id: Delete an existing item"""
132 132 # Forms posted to this method should contain a hidden field:
133 133 # <input type="hidden" name="_method" value="DELETE" />
134 134 # Or using helpers:
135 135 # h.form(url('permission', id=ID),
136 136 # method='delete')
137 137 # url('permission', id=ID)
138 138
139 139 def show(self, id, format='html'):
140 140 """GET /permissions/id: Show a specific item"""
141 141 # url('permission', id=ID)
142 142
143 143 def edit(self, id, format='html'):
144 144 """GET /permissions/id/edit: Form to edit an existing item"""
145 145 #url('edit_permission', id=ID)
146 146 c.perms_choices = self.perms_choices
147 147 c.register_choices = self.register_choices
148 148 c.create_choices = self.create_choices
149 149
150 150 if id == 'default':
151 151 default_user = UserModel().get_by_username('default')
152 152 defaults = {'_method':'put',
153 153 'anonymous':default_user.active}
154 154
155 155 for p in default_user.user_perms:
156 156 if p.permission.permission_name.startswith('repository.'):
157 157 defaults['default_perm'] = p.permission.permission_name
158 158
159 159 if p.permission.permission_name.startswith('hg.register.'):
160 160 defaults['default_register'] = p.permission.permission_name
161 161
162 162 if p.permission.permission_name.startswith('hg.create.'):
163 163 defaults['default_create'] = p.permission.permission_name
164 164
165 165 return htmlfill.render(
166 166 render('admin/permissions/permissions.html'),
167 167 defaults=defaults,
168 168 encoding="UTF-8",
169 169 force_defaults=True,)
170 170 else:
171 171 return redirect(url('admin_home'))
@@ -1,313 +1,313 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Admin controller for RhodeCode
7 7
8 8 :created_on: Apr 7, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import logging
29 29 import traceback
30 30 import formencode
31 31 from operator import itemgetter
32 32 from formencode import htmlfill
33 33
34 34 from paste.httpexceptions import HTTPInternalServerError
35 35 from pylons import request, response, session, tmpl_context as c, url
36 36 from pylons.controllers.util import abort, redirect
37 37 from pylons.i18n.translation import _
38 38
39 39 from rhodecode.lib import helpers as h
40 40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
41 41 HasPermissionAnyDecorator
42 42 from rhodecode.lib.base import BaseController, render
43 43 from rhodecode.lib.utils import invalidate_cache, action_logger
44 44 from rhodecode.model.db import User
45 45 from rhodecode.model.forms import RepoForm
46 46 from rhodecode.model.scm import ScmModel
47 47 from rhodecode.model.repo import RepoModel
48 48
49 49
50 50 log = logging.getLogger(__name__)
51 51
52 52 class ReposController(BaseController):
53 53 """REST Controller styled on the Atom Publishing Protocol"""
54 54 # To properly map this controller, ensure your config/routing.py
55 55 # file has a resource setup:
56 56 # map.resource('repo', 'repos')
57 57
58 58 @LoginRequired()
59 59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
60 60 def __before__(self):
61 61 c.admin_user = session.get('admin_user')
62 62 c.admin_username = session.get('admin_username')
63 63 super(ReposController, self).__before__()
64 64
65 65 @HasPermissionAllDecorator('hg.admin')
66 66 def index(self, format='html'):
67 67 """GET /repos: All items in the collection"""
68 68 # url('repos')
69 69 cached_repo_list = ScmModel().get_repos()
70 70 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
71 71 return render('admin/repos/repos.html')
72 72
73 73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
74 74 def create(self):
75 75 """POST /repos: Create a new item"""
76 76 # url('repos')
77 77 repo_model = RepoModel()
78 78 _form = RepoForm()()
79 79 form_result = {}
80 80 try:
81 81 form_result = _form.to_python(dict(request.POST))
82 82 repo_model.create(form_result, c.rhodecode_user)
83 83 h.flash(_('created repository %s') % form_result['repo_name'],
84 84 category='success')
85 85
86 86 if request.POST.get('user_created'):
87 87 action_logger(self.rhodecode_user, 'user_created_repo',
88 88 form_result['repo_name'], '', self.sa)
89 89 else:
90 90 action_logger(self.rhodecode_user, 'admin_created_repo',
91 91 form_result['repo_name'], '', self.sa)
92 92
93 93 except formencode.Invalid, errors:
94 94 c.new_repo = errors.value['repo_name']
95 95
96 96 if request.POST.get('user_created'):
97 97 r = render('admin/repos/repo_add_create_repository.html')
98 98 else:
99 99 r = render('admin/repos/repo_add.html')
100 100
101 101 return htmlfill.render(
102 102 r,
103 103 defaults=errors.value,
104 104 errors=errors.error_dict or {},
105 105 prefix_error=False,
106 106 encoding="UTF-8")
107 107
108 108 except Exception:
109 109 log.error(traceback.format_exc())
110 msg = _('error occured during creation of repository %s') \
110 msg = _('error occurred during creation of repository %s') \
111 111 % form_result.get('repo_name')
112 112 h.flash(msg, category='error')
113 113 if request.POST.get('user_created'):
114 114 return redirect(url('home'))
115 115 return redirect(url('repos'))
116 116
117 117 @HasPermissionAllDecorator('hg.admin')
118 118 def new(self, format='html'):
119 119 """GET /repos/new: Form to create a new item"""
120 120 new_repo = request.GET.get('repo', '')
121 121 c.new_repo = h.repo_name_slug(new_repo)
122 122
123 123 return render('admin/repos/repo_add.html')
124 124
125 125 @HasPermissionAllDecorator('hg.admin')
126 126 def update(self, repo_name):
127 127 """PUT /repos/repo_name: Update an existing item"""
128 128 # Forms posted to this method should contain a hidden field:
129 129 # <input type="hidden" name="_method" value="PUT" />
130 130 # Or using helpers:
131 131 # h.form(url('repo', repo_name=ID),
132 132 # method='put')
133 133 # url('repo', repo_name=ID)
134 134 repo_model = RepoModel()
135 135 changed_name = repo_name
136 136 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
137 137
138 138 try:
139 139 form_result = _form.to_python(dict(request.POST))
140 140 repo_model.update(repo_name, form_result)
141 141 invalidate_cache('get_repo_cached_%s' % repo_name)
142 142 h.flash(_('Repository %s updated successfully' % repo_name),
143 143 category='success')
144 144 changed_name = form_result['repo_name']
145 145 action_logger(self.rhodecode_user, 'admin_updated_repo',
146 146 changed_name, '', self.sa)
147 147
148 148 except formencode.Invalid, errors:
149 149 c.repo_info = repo_model.get_by_repo_name(repo_name)
150 150 if c.repo_info.stats:
151 151 last_rev = c.repo_info.stats.stat_on_revision
152 152 else:
153 153 last_rev = 0
154 154 c.stats_revision = last_rev
155 155 r = ScmModel().get(repo_name)
156 156 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
157 157
158 158 if last_rev == 0:
159 159 c.stats_percentage = 0
160 160 else:
161 161 c.stats_percentage = '%.2f' % ((float((last_rev)) /
162 162 c.repo_last_rev) * 100)
163 163
164 164 c.users_array = repo_model.get_users_js()
165 165 errors.value.update({'user':c.repo_info.user.username})
166 166 return htmlfill.render(
167 167 render('admin/repos/repo_edit.html'),
168 168 defaults=errors.value,
169 169 errors=errors.error_dict or {},
170 170 prefix_error=False,
171 171 encoding="UTF-8")
172 172
173 173 except Exception:
174 174 log.error(traceback.format_exc())
175 175 h.flash(_('error occurred during update of repository %s') \
176 176 % repo_name, category='error')
177 177
178 178 return redirect(url('edit_repo', repo_name=changed_name))
179 179
180 180 @HasPermissionAllDecorator('hg.admin')
181 181 def delete(self, repo_name):
182 182 """DELETE /repos/repo_name: Delete an existing item"""
183 183 # Forms posted to this method should contain a hidden field:
184 184 # <input type="hidden" name="_method" value="DELETE" />
185 185 # Or using helpers:
186 186 # h.form(url('repo', repo_name=ID),
187 187 # method='delete')
188 188 # url('repo', repo_name=ID)
189 189
190 190 repo_model = RepoModel()
191 191 repo = repo_model.get_by_repo_name(repo_name)
192 192 if not repo:
193 193 h.flash(_('%s repository is not mapped to db perhaps'
194 194 ' it was moved or renamed from the filesystem'
195 195 ' please run the application again'
196 196 ' in order to rescan repositories') % repo_name,
197 197 category='error')
198 198
199 199 return redirect(url('repos'))
200 200 try:
201 201 action_logger(self.rhodecode_user, 'admin_deleted_repo',
202 202 repo_name, '', self.sa)
203 203 repo_model.delete(repo)
204 204 invalidate_cache('get_repo_cached_%s' % repo_name)
205 205 h.flash(_('deleted repository %s') % repo_name, category='success')
206 206
207 207 except Exception, e:
208 208 log.error(traceback.format_exc())
209 h.flash(_('An error occured during deletion of %s') % repo_name,
209 h.flash(_('An error occurred during deletion of %s') % repo_name,
210 210 category='error')
211 211
212 212 return redirect(url('repos'))
213 213
214 214 @HasPermissionAllDecorator('hg.admin')
215 215 def delete_perm_user(self, repo_name):
216 216 """
217 217 DELETE an existing repository permission user
218 218 :param repo_name:
219 219 """
220 220
221 221 try:
222 222 repo_model = RepoModel()
223 223 repo_model.delete_perm_user(request.POST, repo_name)
224 224 except Exception, e:
225 h.flash(_('An error occured during deletion of repository user'),
225 h.flash(_('An error occurred during deletion of repository user'),
226 226 category='error')
227 227 raise HTTPInternalServerError()
228 228
229 229 @HasPermissionAllDecorator('hg.admin')
230 230 def repo_stats(self, repo_name):
231 231 """
232 232 DELETE an existing repository statistics
233 233 :param repo_name:
234 234 """
235 235
236 236 try:
237 237 repo_model = RepoModel()
238 238 repo_model.delete_stats(repo_name)
239 239 except Exception, e:
240 h.flash(_('An error occured during deletion of repository stats'),
240 h.flash(_('An error occurred during deletion of repository stats'),
241 241 category='error')
242 242 return redirect(url('edit_repo', repo_name=repo_name))
243 243
244 244 @HasPermissionAllDecorator('hg.admin')
245 245 def repo_cache(self, repo_name):
246 246 """
247 INVALIDATE exisitings repository cache
247 INVALIDATE existing repository cache
248 248 :param repo_name:
249 249 """
250 250
251 251 try:
252 252 ScmModel().mark_for_invalidation(repo_name)
253 253 except Exception, e:
254 254 h.flash(_('An error occurred during cache invalidation'),
255 255 category='error')
256 256 return redirect(url('edit_repo', repo_name=repo_name))
257 257
258 258 @HasPermissionAllDecorator('hg.admin')
259 259 def show(self, repo_name, format='html'):
260 260 """GET /repos/repo_name: Show a specific item"""
261 261 # url('repo', repo_name=ID)
262 262
263 263 @HasPermissionAllDecorator('hg.admin')
264 264 def edit(self, repo_name, format='html'):
265 265 """GET /repos/repo_name/edit: Form to edit an existing item"""
266 266 # url('edit_repo', repo_name=ID)
267 267 repo_model = RepoModel()
268 268 r = ScmModel().get(repo_name)
269 269 c.repo_info = repo_model.get_by_repo_name(repo_name)
270 270
271 271 if c.repo_info is None:
272 272 h.flash(_('%s repository is not mapped to db perhaps'
273 273 ' it was created or renamed from the filesystem'
274 274 ' please run the application again'
275 275 ' in order to rescan repositories') % repo_name,
276 276 category='error')
277 277
278 278 return redirect(url('repos'))
279 279
280 280 if c.repo_info.stats:
281 281 last_rev = c.repo_info.stats.stat_on_revision
282 282 else:
283 283 last_rev = 0
284 284 c.stats_revision = last_rev
285 285
286 286 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
287 287
288 288 if last_rev == 0:
289 289 c.stats_percentage = 0
290 290 else:
291 291 c.stats_percentage = '%.2f' % ((float((last_rev)) /
292 292 c.repo_last_rev) * 100)
293 293
294 294 defaults = c.repo_info.get_dict()
295 295 if c.repo_info.user:
296 296 defaults.update({'user':c.repo_info.user.username})
297 297 else:
298 298 replacement_user = self.sa.query(User)\
299 299 .filter(User.admin == True).first().username
300 300 defaults.update({'user':replacement_user})
301 301
302 302 c.users_array = repo_model.get_users_js()
303 303
304 304 for p in c.repo_info.repo_to_perm:
305 305 defaults.update({'perm_%s' % p.user.username:
306 306 p.permission.permission_name})
307 307
308 308 return htmlfill.render(
309 309 render('admin/repos/repo_edit.html'),
310 310 defaults=defaults,
311 311 encoding="UTF-8",
312 312 force_defaults=False
313 313 )
@@ -1,339 +1,340 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 package.rhodecode.controllers.admin.settings
4 ~~~~~~~~~~~~~~
3 rhodecode.controllers.admin.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5 6 settings controller for rhodecode admin
6 7
7 8 :created_on: Jul 14, 2010
8 9 :author: marcink
9 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 11 :license: GPLv3, see COPYING for more details.
11 12 """
12 13 # This program is free software; you can redistribute it and/or
13 14 # modify it under the terms of the GNU General Public License
14 15 # as published by the Free Software Foundation; version 2
15 16 # of the License or (at your opinion) any later version of the license.
16 17 #
17 18 # This program is distributed in the hope that it will be useful,
18 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 21 # GNU General Public License for more details.
21 22 #
22 23 # You should have received a copy of the GNU General Public License
23 24 # along with this program; if not, write to the Free Software
24 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 26 # MA 02110-1301, USA.
26 27
27 28 from formencode import htmlfill
28 29 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
29 30 config
30 31 from pylons.controllers.util import abort, redirect
31 32 from pylons.i18n.translation import _
32 33 from rhodecode.lib import helpers as h
33 34 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
34 35 HasPermissionAnyDecorator, NotAnonymous
35 36 from rhodecode.lib.base import BaseController, render
36 37 from rhodecode.lib.celerylib import tasks, run_task
37 38 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
38 39 set_rhodecode_config
39 40 from rhodecode.model.db import RhodeCodeUi, Repository
40 41 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
41 42 ApplicationUiSettingsForm
42 43 from rhodecode.model.scm import ScmModel
43 44 from rhodecode.model.settings import SettingsModel
44 45 from rhodecode.model.user import UserModel
45 46 from sqlalchemy import func
46 47 import formencode
47 48 import logging
48 49 import traceback
49 50
50 51 log = logging.getLogger(__name__)
51 52
52 53
53 54 class SettingsController(BaseController):
54 55 """REST Controller styled on the Atom Publishing Protocol"""
55 56 # To properly map this controller, ensure your config/routing.py
56 57 # file has a resource setup:
57 58 # map.resource('setting', 'settings', controller='admin/settings',
58 59 # path_prefix='/admin', name_prefix='admin_')
59 60
60 61
61 62 @LoginRequired()
62 63 def __before__(self):
63 64 c.admin_user = session.get('admin_user')
64 65 c.admin_username = session.get('admin_username')
65 66 super(SettingsController, self).__before__()
66 67
67 68
68 69 @HasPermissionAllDecorator('hg.admin')
69 70 def index(self, format='html'):
70 71 """GET /admin/settings: All items in the collection"""
71 72 # url('admin_settings')
72 73
73 74 defaults = SettingsModel().get_app_settings()
74 75 defaults.update(self.get_hg_ui_settings())
75 76 return htmlfill.render(
76 77 render('admin/settings/settings.html'),
77 78 defaults=defaults,
78 79 encoding="UTF-8",
79 80 force_defaults=False
80 81 )
81 82
82 83 @HasPermissionAllDecorator('hg.admin')
83 84 def create(self):
84 85 """POST /admin/settings: Create a new item"""
85 86 # url('admin_settings')
86 87
87 88 @HasPermissionAllDecorator('hg.admin')
88 89 def new(self, format='html'):
89 90 """GET /admin/settings/new: Form to create a new item"""
90 91 # url('admin_new_setting')
91 92
92 93 @HasPermissionAllDecorator('hg.admin')
93 94 def update(self, setting_id):
94 95 """PUT /admin/settings/setting_id: Update an existing item"""
95 96 # Forms posted to this method should contain a hidden field:
96 97 # <input type="hidden" name="_method" value="PUT" />
97 98 # Or using helpers:
98 99 # h.form(url('admin_setting', setting_id=ID),
99 100 # method='put')
100 101 # url('admin_setting', setting_id=ID)
101 102 if setting_id == 'mapping':
102 103 rm_obsolete = request.POST.get('destroy', False)
103 104 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
104 105
105 106 initial = ScmModel().repo_scan(g.paths[0][1], g.baseui)
106 107 for repo_name in initial.keys():
107 108 invalidate_cache('get_repo_cached_%s' % repo_name)
108 109
109 110 repo2db_mapper(initial, rm_obsolete)
110 111
111 112 h.flash(_('Repositories successfully rescanned'), category='success')
112 113
113 114 if setting_id == 'whoosh':
114 115 repo_location = self.get_hg_ui_settings()['paths_root_path']
115 116 full_index = request.POST.get('full_index', False)
116 117 task = run_task(tasks.whoosh_index, repo_location, full_index)
117 118
118 119 h.flash(_('Whoosh reindex task scheduled'), category='success')
119 120 if setting_id == 'global':
120 121
121 122 application_form = ApplicationSettingsForm()()
122 123 try:
123 124 form_result = application_form.to_python(dict(request.POST))
124 125 settings_model = SettingsModel()
125 126 try:
126 127 hgsettings1 = settings_model.get('title')
127 128 hgsettings1.app_settings_value = form_result['rhodecode_title']
128 129
129 130 hgsettings2 = settings_model.get('realm')
130 131 hgsettings2.app_settings_value = form_result['rhodecode_realm']
131 132
132 133
133 134 self.sa.add(hgsettings1)
134 135 self.sa.add(hgsettings2)
135 136 self.sa.commit()
136 137 set_rhodecode_config(config)
137 138 h.flash(_('Updated application settings'),
138 139 category='success')
139 140
140 141 except:
141 142 log.error(traceback.format_exc())
142 143 h.flash(_('error occurred during updating application settings'),
143 144 category='error')
144 145
145 146 self.sa.rollback()
146 147
147 148
148 149 except formencode.Invalid, errors:
149 150 return htmlfill.render(
150 151 render('admin/settings/settings.html'),
151 152 defaults=errors.value,
152 153 errors=errors.error_dict or {},
153 154 prefix_error=False,
154 155 encoding="UTF-8")
155 156
156 157 if setting_id == 'mercurial':
157 158 application_form = ApplicationUiSettingsForm()()
158 159 try:
159 160 form_result = application_form.to_python(dict(request.POST))
160 161
161 162 try:
162 163
163 164 hgsettings1 = self.sa.query(RhodeCodeUi)\
164 165 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
165 166 hgsettings1.ui_value = form_result['web_push_ssl']
166 167
167 168 hgsettings2 = self.sa.query(RhodeCodeUi)\
168 169 .filter(RhodeCodeUi.ui_key == '/').one()
169 170 hgsettings2.ui_value = form_result['paths_root_path']
170 171
171 172
172 173 #HOOKS
173 174 hgsettings3 = self.sa.query(RhodeCodeUi)\
174 175 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
175 176 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
176 177
177 178 hgsettings4 = self.sa.query(RhodeCodeUi)\
178 179 .filter(RhodeCodeUi.ui_key == 'changegroup.repo_size').one()
179 180 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
180 181
181 182 hgsettings5 = self.sa.query(RhodeCodeUi)\
182 183 .filter(RhodeCodeUi.ui_key == 'pretxnchangegroup.push_logger').one()
183 184 hgsettings5.ui_active = bool(form_result['hooks_pretxnchangegroup_push_logger'])
184 185
185 186 hgsettings6 = self.sa.query(RhodeCodeUi)\
186 187 .filter(RhodeCodeUi.ui_key == 'preoutgoing.pull_logger').one()
187 188 hgsettings6.ui_active = bool(form_result['hooks_preoutgoing_pull_logger'])
188 189
189 190
190 191 self.sa.add(hgsettings1)
191 192 self.sa.add(hgsettings2)
192 193 self.sa.add(hgsettings3)
193 194 self.sa.add(hgsettings4)
194 195 self.sa.add(hgsettings5)
195 196 self.sa.add(hgsettings6)
196 197 self.sa.commit()
197 198
198 199 h.flash(_('Updated mercurial settings'),
199 200 category='success')
200 201
201 202 except:
202 203 log.error(traceback.format_exc())
203 204 h.flash(_('error occurred during updating application settings'),
204 205 category='error')
205 206
206 207 self.sa.rollback()
207 208
208 209
209 210 except formencode.Invalid, errors:
210 211 return htmlfill.render(
211 212 render('admin/settings/settings.html'),
212 213 defaults=errors.value,
213 214 errors=errors.error_dict or {},
214 215 prefix_error=False,
215 216 encoding="UTF-8")
216 217
217 218
218 219
219 220 return redirect(url('admin_settings'))
220 221
221 222 @HasPermissionAllDecorator('hg.admin')
222 223 def delete(self, setting_id):
223 224 """DELETE /admin/settings/setting_id: Delete an existing item"""
224 225 # Forms posted to this method should contain a hidden field:
225 226 # <input type="hidden" name="_method" value="DELETE" />
226 227 # Or using helpers:
227 228 # h.form(url('admin_setting', setting_id=ID),
228 229 # method='delete')
229 230 # url('admin_setting', setting_id=ID)
230 231
231 232 @HasPermissionAllDecorator('hg.admin')
232 233 def show(self, setting_id, format='html'):
233 234 """GET /admin/settings/setting_id: Show a specific item"""
234 235 # url('admin_setting', setting_id=ID)
235 236
236 237 @HasPermissionAllDecorator('hg.admin')
237 238 def edit(self, setting_id, format='html'):
238 239 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
239 240 # url('admin_edit_setting', setting_id=ID)
240 241
241 242 @NotAnonymous()
242 243 def my_account(self):
243 244 """
244 245 GET /_admin/my_account Displays info about my account
245 246 """
246 247 # url('admin_settings_my_account')
247 248
248 249 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
249 250 all_repos = self.sa.query(Repository)\
250 251 .filter(Repository.user_id == c.user.user_id)\
251 252 .order_by(func.lower(Repository.repo_name))\
252 253 .all()
253 254
254 255 c.user_repos = ScmModel().get_repos(all_repos)
255 256
256 257 if c.user.username == 'default':
257 258 h.flash(_("You can't edit this user since it's"
258 259 " crucial for entire application"), category='warning')
259 260 return redirect(url('users'))
260 261
261 262 defaults = c.user.get_dict()
262 263 return htmlfill.render(
263 264 render('admin/users/user_edit_my_account.html'),
264 265 defaults=defaults,
265 266 encoding="UTF-8",
266 267 force_defaults=False
267 268 )
268 269
269 270 def my_account_update(self):
270 271 """PUT /_admin/my_account_update: Update an existing item"""
271 272 # Forms posted to this method should contain a hidden field:
272 273 # <input type="hidden" name="_method" value="PUT" />
273 274 # Or using helpers:
274 275 # h.form(url('admin_settings_my_account_update'),
275 276 # method='put')
276 277 # url('admin_settings_my_account_update', id=ID)
277 278 user_model = UserModel()
278 279 uid = c.rhodecode_user.user_id
279 280 _form = UserForm(edit=True, old_data={'user_id':uid,
280 281 'email':c.rhodecode_user.email})()
281 282 form_result = {}
282 283 try:
283 284 form_result = _form.to_python(dict(request.POST))
284 285 user_model.update_my_account(uid, form_result)
285 286 h.flash(_('Your account was updated successfully'),
286 287 category='success')
287 288
288 289 except formencode.Invalid, errors:
289 290 c.user = user_model.get(c.rhodecode_user.user_id, cache=False)
290 291 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
291 292 all_repos = self.sa.query(Repository)\
292 293 .filter(Repository.user_id == c.user.user_id)\
293 294 .order_by(func.lower(Repository.repo_name))\
294 295 .all()
295 296 c.user_repos = ScmModel().get_repos(all_repos)
296 297
297 298 return htmlfill.render(
298 299 render('admin/users/user_edit_my_account.html'),
299 300 defaults=errors.value,
300 301 errors=errors.error_dict or {},
301 302 prefix_error=False,
302 303 encoding="UTF-8")
303 304 except Exception:
304 305 log.error(traceback.format_exc())
305 306 h.flash(_('error occurred during update of user %s') \
306 307 % form_result.get('username'), category='error')
307 308
308 309 return redirect(url('my_account'))
309 310
310 311 @NotAnonymous()
311 312 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
312 313 def create_repository(self):
313 314 """GET /_admin/create_repository: Form to create a new item"""
314 315 new_repo = request.GET.get('repo', '')
315 316 c.new_repo = h.repo_name_slug(new_repo)
316 317
317 318 return render('admin/repos/repo_add_create_repository.html')
318 319
319 320 def get_hg_ui_settings(self):
320 321 ret = self.sa.query(RhodeCodeUi).all()
321 322
322 323 if not ret:
323 324 raise Exception('Could not get application ui settings !')
324 325 settings = {}
325 326 for each in ret:
326 327 k = each.ui_key
327 328 v = each.ui_value
328 329 if k == '/':
329 330 k = 'root_path'
330 331
331 332 if k.find('.') != -1:
332 333 k = k.replace('.', '_')
333 334
334 335 if each.ui_section == 'hooks':
335 336 v = each.ui_active
336 337
337 338 settings[each.ui_section + '_' + k] = v
338 339
339 340 return settings
@@ -1,172 +1,172 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.users
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Users crud controller for pylons
7 7
8 8 :created_on: Apr 4, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import logging
29 29 import traceback
30 30 import formencode
31 31
32 32 from formencode import htmlfill
33 33 from pylons import request, session, tmpl_context as c, url
34 34 from pylons.controllers.util import abort, redirect
35 35 from pylons.i18n.translation import _
36 36
37 37 from rhodecode.lib.exceptions import *
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
40 40 from rhodecode.lib.base import BaseController, render
41 41
42 42 from rhodecode.model.db import User
43 43 from rhodecode.model.forms import UserForm
44 44 from rhodecode.model.user import UserModel
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48 class UsersController(BaseController):
49 49 """REST Controller styled on the Atom Publishing Protocol"""
50 50 # To properly map this controller, ensure your config/routing.py
51 51 # file has a resource setup:
52 52 # map.resource('user', 'users')
53 53
54 54 @LoginRequired()
55 55 @HasPermissionAllDecorator('hg.admin')
56 56 def __before__(self):
57 57 c.admin_user = session.get('admin_user')
58 58 c.admin_username = session.get('admin_username')
59 59 super(UsersController, self).__before__()
60 60
61 61
62 62 def index(self, format='html'):
63 63 """GET /users: All items in the collection"""
64 64 # url('users')
65 65
66 66 c.users_list = self.sa.query(User).all()
67 67 return render('admin/users/users.html')
68 68
69 69 def create(self):
70 70 """POST /users: Create a new item"""
71 71 # url('users')
72 72
73 73 user_model = UserModel()
74 74 login_form = UserForm()()
75 75 try:
76 76 form_result = login_form.to_python(dict(request.POST))
77 77 user_model.create(form_result)
78 78 h.flash(_('created user %s') % form_result['username'],
79 79 category='success')
80 80 #action_logger(self.rhodecode_user, 'new_user', '', '', self.sa)
81 81 except formencode.Invalid, errors:
82 82 return htmlfill.render(
83 83 render('admin/users/user_add.html'),
84 84 defaults=errors.value,
85 85 errors=errors.error_dict or {},
86 86 prefix_error=False,
87 87 encoding="UTF-8")
88 88 except Exception:
89 89 log.error(traceback.format_exc())
90 h.flash(_('error occured during creation of user %s') \
90 h.flash(_('error occurred during creation of user %s') \
91 91 % request.POST.get('username'), category='error')
92 92 return redirect(url('users'))
93 93
94 94 def new(self, format='html'):
95 95 """GET /users/new: Form to create a new item"""
96 96 # url('new_user')
97 97 return render('admin/users/user_add.html')
98 98
99 99 def update(self, id):
100 100 """PUT /users/id: Update an existing item"""
101 101 # Forms posted to this method should contain a hidden field:
102 102 # <input type="hidden" name="_method" value="PUT" />
103 103 # Or using helpers:
104 104 # h.form(url('user', id=ID),
105 105 # method='put')
106 106 # url('user', id=ID)
107 107 user_model = UserModel()
108 108 c.user = user_model.get(id)
109 109
110 110 _form = UserForm(edit=True, old_data={'user_id':id,
111 111 'email':c.user.email})()
112 112 form_result = {}
113 113 try:
114 114 form_result = _form.to_python(dict(request.POST))
115 115 user_model.update(id, form_result)
116 116 h.flash(_('User updated succesfully'), category='success')
117 117
118 118 except formencode.Invalid, errors:
119 119 return htmlfill.render(
120 120 render('admin/users/user_edit.html'),
121 121 defaults=errors.value,
122 122 errors=errors.error_dict or {},
123 123 prefix_error=False,
124 124 encoding="UTF-8")
125 125 except Exception:
126 126 log.error(traceback.format_exc())
127 127 h.flash(_('error occurred during update of user %s') \
128 128 % form_result.get('username'), category='error')
129 129
130 130 return redirect(url('users'))
131 131
132 132 def delete(self, id):
133 133 """DELETE /users/id: Delete an existing item"""
134 134 # Forms posted to this method should contain a hidden field:
135 135 # <input type="hidden" name="_method" value="DELETE" />
136 136 # Or using helpers:
137 137 # h.form(url('user', id=ID),
138 138 # method='delete')
139 139 # url('user', id=ID)
140 140 user_model = UserModel()
141 141 try:
142 142 user_model.delete(id)
143 143 h.flash(_('sucessfully deleted user'), category='success')
144 144 except (UserOwnsReposException, DefaultUserException), e:
145 145 h.flash(str(e), category='warning')
146 146 except Exception:
147 h.flash(_('An error occured during deletion of user'),
147 h.flash(_('An error occurred during deletion of user'),
148 148 category='error')
149 149 return redirect(url('users'))
150 150
151 151 def show(self, id, format='html'):
152 152 """GET /users/id: Show a specific item"""
153 153 # url('user', id=ID)
154 154
155 155
156 156 def edit(self, id, format='html'):
157 157 """GET /users/id/edit: Form to edit an existing item"""
158 158 # url('edit_user', id=ID)
159 159 c.user = self.sa.query(User).get(id)
160 160 if not c.user:
161 161 return redirect(url('users'))
162 162 if c.user.username == 'default':
163 163 h.flash(_("You can't edit this user"), category='warning')
164 164 return redirect(url('users'))
165 165
166 166 defaults = c.user.get_dict()
167 167 return htmlfill.render(
168 168 render('admin/users/user_edit.html'),
169 169 defaults=defaults,
170 170 encoding="UTF-8",
171 171 force_defaults=False
172 172 )
@@ -1,110 +1,110 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 package.rhodecode.controllers.error
4 ~~~~~~~~~~~~~~
3 rhodecode.controllers.error
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 RhodeCode error controller
7 7
8 8 :created_on: Dec 8, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27 import os
28 28 import cgi
29 29 import logging
30 30 import paste.fileapp
31 31
32 32 from pylons import tmpl_context as c, request
33 33 from pylons.i18n.translation import _
34 34 from pylons.middleware import media_path
35 35
36 36 from rhodecode.lib.base import BaseController, render
37 37
38 38 log = logging.getLogger(__name__)
39 39
40 40 class ErrorController(BaseController):
41 41 """Generates error documents as and when they are required.
42 42
43 43 The ErrorDocuments middleware forwards to ErrorController when error
44 44 related status codes are returned from the application.
45 45
46 46 This behavior can be altered by changing the parameters to the
47 47 ErrorDocuments middleware in your config/middleware.py file.
48 48 """
49 49
50 50 def __before__(self):
51 51 pass#disable all base actions since we don't need them here
52 52
53 53 def document(self):
54 54 resp = request.environ.get('pylons.original_response')
55 55
56 56 log.debug('### %s ###', resp.status)
57 57
58 58 e = request.environ
59 59 c.serv_p = r'%(protocol)s://%(host)s/' % {
60 60 'protocol': e.get('wsgi.url_scheme'),
61 61 'host':e.get('HTTP_HOST'),
62 62 }
63 63
64 64
65 65 c.error_message = cgi.escape(request.GET.get('code', str(resp.status)))
66 66 c.error_explanation = self.get_error_explanation(resp.status_int)
67 67
68 68 #redirect to when error with given seconds
69 69 c.redirect_time = 0
70 70 c.redirect_module = _('Home page')# name to what your going to be redirected
71 71 c.url_redirect = "/"
72 72
73 73 return render('/errors/error_document.html')
74 74
75 75
76 76 def img(self, id):
77 77 """Serve Pylons' stock images"""
78 78 return self._serve_file(os.path.join(media_path, 'img', id))
79 79
80 80 def style(self, id):
81 81 """Serve Pylons' stock stylesheets"""
82 82 return self._serve_file(os.path.join(media_path, 'style', id))
83 83
84 84 def _serve_file(self, path):
85 85 """Call Paste's FileApp (a WSGI application) to serve the file
86 86 at the specified path
87 87 """
88 88 fapp = paste.fileapp.FileApp(path)
89 89 return fapp(request.environ, self.start_response)
90 90
91 91 def get_error_explanation(self, code):
92 92 ''' get the error explanations of int codes
93 93 [400, 401, 403, 404, 500]'''
94 94 try:
95 95 code = int(code)
96 96 except:
97 97 code = 500
98 98
99 99 if code == 400:
100 100 return _('The request could not be understood by the server due to malformed syntax.')
101 101 if code == 401:
102 102 return _('Unauthorized access to resource')
103 103 if code == 403:
104 104 return _("You don't have permission to view this page")
105 105 if code == 404:
106 106 return _('The resource could not be found')
107 107 if code == 500:
108 108 return _('The server encountered an unexpected condition which prevented it from fulfilling the request.')
109 109
110 110
@@ -1,178 +1,178 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 # settings controller for pylons
4 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; version 2
9 9 # of the License or (at your opinion) any later version of the license.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 19 # MA 02110-1301, USA.
20 20 """
21 21 Created on June 30, 2010
22 22 settings controller for pylons
23 23 @author: marcink
24 24 """
25 25 from formencode import htmlfill
26 26 from pylons import tmpl_context as c, request, url
27 27 from pylons.controllers.util import redirect
28 28 from pylons.i18n.translation import _
29 29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAllDecorator
30 30 from rhodecode.lib.base import BaseController, render
31 31 from rhodecode.lib.utils import invalidate_cache, action_logger
32 32 from rhodecode.model.forms import RepoSettingsForm, RepoForkForm
33 33 from rhodecode.model.repo import RepoModel
34 34 import formencode
35 35 import logging
36 36 import rhodecode.lib.helpers as h
37 37 import traceback
38 38
39 39 log = logging.getLogger(__name__)
40 40
41 41 class SettingsController(BaseController):
42 42
43 43 @LoginRequired()
44 44 @HasRepoPermissionAllDecorator('repository.admin')
45 45 def __before__(self):
46 46 super(SettingsController, self).__before__()
47 47
48 48 def index(self, repo_name):
49 49 repo_model = RepoModel()
50 50 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
51 51 if not repo:
52 52 h.flash(_('%s repository is not mapped to db perhaps'
53 ' it was created or renamed from the filesystem'
53 ' it was created or renamed from the file system'
54 54 ' please run the application again'
55 55 ' in order to rescan repositories') % repo_name,
56 56 category='error')
57 57
58 58 return redirect(url('home'))
59 59 defaults = c.repo_info.get_dict()
60 60 defaults.update({'user':c.repo_info.user.username})
61 61 c.users_array = repo_model.get_users_js()
62 62
63 63 for p in c.repo_info.repo_to_perm:
64 64 defaults.update({'perm_%s' % p.user.username:
65 65 p.permission.permission_name})
66 66
67 67 return htmlfill.render(
68 68 render('settings/repo_settings.html'),
69 69 defaults=defaults,
70 70 encoding="UTF-8",
71 71 force_defaults=False
72 72 )
73 73
74 74 def update(self, repo_name):
75 75 repo_model = RepoModel()
76 76 changed_name = repo_name
77 77 _form = RepoSettingsForm(edit=True, old_data={'repo_name':repo_name})()
78 78 try:
79 79 form_result = _form.to_python(dict(request.POST))
80 80 repo_model.update(repo_name, form_result)
81 81 invalidate_cache('get_repo_cached_%s' % repo_name)
82 82 h.flash(_('Repository %s updated successfully' % repo_name),
83 83 category='success')
84 84 changed_name = form_result['repo_name']
85 85 action_logger(self.rhodecode_user, 'user_updated_repo',
86 86 changed_name, '', self.sa)
87 87 except formencode.Invalid, errors:
88 88 c.repo_info = repo_model.get_by_repo_name(repo_name)
89 89 c.users_array = repo_model.get_users_js()
90 90 errors.value.update({'user':c.repo_info.user.username})
91 91 return htmlfill.render(
92 92 render('settings/repo_settings.html'),
93 93 defaults=errors.value,
94 94 errors=errors.error_dict or {},
95 95 prefix_error=False,
96 96 encoding="UTF-8")
97 97 except Exception:
98 98 log.error(traceback.format_exc())
99 99 h.flash(_('error occurred during update of repository %s') \
100 100 % repo_name, category='error')
101 101
102 102 return redirect(url('repo_settings_home', repo_name=changed_name))
103 103
104 104
105 105
106 106 def delete(self, repo_name):
107 107 """DELETE /repos/repo_name: Delete an existing item"""
108 108 # Forms posted to this method should contain a hidden field:
109 109 # <input type="hidden" name="_method" value="DELETE" />
110 110 # Or using helpers:
111 111 # h.form(url('repo_settings_delete', repo_name=ID),
112 112 # method='delete')
113 113 # url('repo_settings_delete', repo_name=ID)
114 114
115 115 repo_model = RepoModel()
116 116 repo = repo_model.get_by_repo_name(repo_name)
117 117 if not repo:
118 118 h.flash(_('%s repository is not mapped to db perhaps'
119 119 ' it was moved or renamed from the filesystem'
120 120 ' please run the application again'
121 121 ' in order to rescan repositories') % repo_name,
122 122 category='error')
123 123
124 124 return redirect(url('home'))
125 125 try:
126 126 action_logger(self.rhodecode_user, 'user_deleted_repo',
127 127 repo_name, '', self.sa)
128 128 repo_model.delete(repo)
129 129 invalidate_cache('get_repo_cached_%s' % repo_name)
130 130 h.flash(_('deleted repository %s') % repo_name, category='success')
131 131 except Exception:
132 132 h.flash(_('An error occurred during deletion of %s') % repo_name,
133 133 category='error')
134 134
135 135 return redirect(url('home'))
136 136
137 137 def fork(self, repo_name):
138 138 repo_model = RepoModel()
139 139 c.repo_info = repo = repo_model.get_by_repo_name(repo_name)
140 140 if not repo:
141 141 h.flash(_('%s repository is not mapped to db perhaps'
142 ' it was created or renamed from the filesystem'
142 ' it was created or renamed from the file system'
143 143 ' please run the application again'
144 144 ' in order to rescan repositories') % repo_name,
145 145 category='error')
146 146
147 147 return redirect(url('home'))
148 148
149 149 return render('settings/repo_fork.html')
150 150
151 151
152 152
153 153 def fork_create(self, repo_name):
154 154 repo_model = RepoModel()
155 155 c.repo_info = repo_model.get_by_repo_name(repo_name)
156 156 _form = RepoForkForm(old_data={'repo_type':c.repo_info.repo_type})()
157 157 form_result = {}
158 158 try:
159 159 form_result = _form.to_python(dict(request.POST))
160 160 form_result.update({'repo_name':repo_name})
161 161 repo_model.create_fork(form_result, c.rhodecode_user)
162 162 h.flash(_('forked %s repository as %s') \
163 163 % (repo_name, form_result['fork_name']),
164 164 category='success')
165 165 action_logger(self.rhodecode_user,
166 166 'user_forked_repo:%s' % form_result['fork_name'],
167 167 repo_name, '', self.sa)
168 168 except formencode.Invalid, errors:
169 169 c.new_repo = errors.value['fork_name']
170 170 r = render('settings/repo_fork.html')
171 171
172 172 return htmlfill.render(
173 173 r,
174 174 defaults=errors.value,
175 175 errors=errors.error_dict or {},
176 176 prefix_error=False,
177 177 encoding="UTF-8")
178 178 return redirect(url('home'))
@@ -1,144 +1,144 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 package.rhodecode.controllers.summary
4 ~~~~~~~~~~~~~~
3 rhodecode.controllers.summary
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Summary controller for Rhodecode
7 7
8 8 :created_on: Apr 18, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import calendar
29 29 import logging
30 30 from time import mktime
31 31 from datetime import datetime, timedelta
32 32
33 33 from vcs.exceptions import ChangesetError
34 34
35 35 from pylons import tmpl_context as c, request, url
36 36 from pylons.i18n.translation import _
37 37
38 38 from rhodecode.model.scm import ScmModel
39 39 from rhodecode.model.db import Statistics
40 40
41 41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 42 from rhodecode.lib.base import BaseController, render
43 43 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
44 44
45 45 from rhodecode.lib.celerylib import run_task
46 46 from rhodecode.lib.celerylib.tasks import get_commits_stats
47 47
48 48 from webhelpers.paginate import Page
49 49
50 50 try:
51 51 import json
52 52 except ImportError:
53 53 #python 2.5 compatibility
54 54 import simplejson as json
55 55 log = logging.getLogger(__name__)
56 56
57 57 class SummaryController(BaseController):
58 58
59 59 @LoginRequired()
60 60 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
61 61 'repository.admin')
62 62 def __before__(self):
63 63 super(SummaryController, self).__before__()
64 64
65 65 def index(self):
66 66 scm_model = ScmModel()
67 67 c.repo_info = scm_model.get_repo(c.repo_name)
68 68 c.following = scm_model.is_following_repo(c.repo_name,
69 69 c.rhodecode_user.user_id)
70 70 def url_generator(**kw):
71 71 return url('shortlog_home', repo_name=c.repo_name, **kw)
72 72
73 73 c.repo_changesets = Page(c.repo_info, page=1, items_per_page=10,
74 74 url=url_generator)
75 75
76 76 e = request.environ
77 77
78 78 if self.rhodecode_user.username == 'default':
79 79 password = ':default'
80 80 else:
81 81 password = ''
82 82
83 83 uri = u'%(protocol)s://%(user)s%(password)s@%(host)s%(prefix)s/%(repo_name)s' % {
84 84 'protocol': e.get('wsgi.url_scheme'),
85 85 'user':str(c.rhodecode_user.username),
86 86 'password':password,
87 87 'host':e.get('HTTP_HOST'),
88 88 'prefix':e.get('SCRIPT_NAME'),
89 89 'repo_name':c.repo_name, }
90 90 c.clone_repo_url = uri
91 91 c.repo_tags = OrderedDict()
92 92 for name, hash in c.repo_info.tags.items()[:10]:
93 93 try:
94 94 c.repo_tags[name] = c.repo_info.get_changeset(hash)
95 95 except ChangesetError:
96 96 c.repo_tags[name] = EmptyChangeset(hash)
97 97
98 98 c.repo_branches = OrderedDict()
99 99 for name, hash in c.repo_info.branches.items()[:10]:
100 100 try:
101 101 c.repo_branches[name] = c.repo_info.get_changeset(hash)
102 102 except ChangesetError:
103 103 c.repo_branches[name] = EmptyChangeset(hash)
104 104
105 105 td = datetime.today() + timedelta(days=1)
106 106 y, m, d = td.year, td.month, td.day
107 107
108 108 ts_min_y = mktime((y - 1, (td - timedelta(days=calendar.mdays[m])).month,
109 109 d, 0, 0, 0, 0, 0, 0,))
110 110 ts_min_m = mktime((y, (td - timedelta(days=calendar.mdays[m])).month,
111 111 d, 0, 0, 0, 0, 0, 0,))
112 112
113 113 ts_max_y = mktime((y, m, d, 0, 0, 0, 0, 0, 0,))
114 114 if c.repo_info.dbrepo.enable_statistics:
115 115 c.no_data_msg = _('No data loaded yet')
116 116 run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
117 117 else:
118 118 c.no_data_msg = _('Statistics update are disabled for this repository')
119 119 c.ts_min = ts_min_m
120 120 c.ts_max = ts_max_y
121 121
122 122 stats = self.sa.query(Statistics)\
123 123 .filter(Statistics.repository == c.repo_info.dbrepo)\
124 124 .scalar()
125 125
126 126
127 127 if stats and stats.languages:
128 128 c.no_data = False is c.repo_info.dbrepo.enable_statistics
129 129 lang_stats = json.loads(stats.languages)
130 130 c.commit_data = stats.commit_activity
131 131 c.overview_data = stats.commit_activity_combined
132 132 c.trending_languages = json.dumps(OrderedDict(
133 133 sorted(lang_stats.items(), reverse=True,
134 134 key=lambda k: k[1])[:10]
135 135 )
136 136 )
137 137 else:
138 138 c.commit_data = json.dumps({})
139 139 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10] ])
140 140 c.trending_languages = json.dumps({})
141 141 c.no_data = True
142 142
143 143 return render('summary/summary.html')
144 144
@@ -1,614 +1,614 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.utils
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Utilities library for RhodeCode
7 7
8 8 :created_on: Apr 18, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software; you can redistribute it and/or
14 14 # modify it under the terms of the GNU General Public License
15 15 # as published by the Free Software Foundation; version 2
16 16 # of the License or (at your opinion) any later version of the license.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program; if not, write to the Free Software
25 25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 26 # MA 02110-1301, USA.
27 27
28 28 import os
29 29 import logging
30 30 import datetime
31 31 import traceback
32 32
33 33 from UserDict import DictMixin
34 34
35 35 from mercurial import ui, config, hg
36 36 from mercurial.error import RepoError
37 37
38 38 import paste
39 39 import beaker
40 40 from paste.script.command import Command, BadCommand
41 41
42 42 from vcs.backends.base import BaseChangeset
43 43 from vcs.utils.lazy import LazyProperty
44 44
45 45 from rhodecode.model import meta
46 46 from rhodecode.model.caching_query import FromCache
47 47 from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog
48 48 from rhodecode.model.repo import RepoModel
49 49 from rhodecode.model.user import UserModel
50 50
51 51 log = logging.getLogger(__name__)
52 52
53 53
54 54 def get_repo_slug(request):
55 55 return request.environ['pylons.routes_dict'].get('repo_name')
56 56
57 57 def action_logger(user, action, repo, ipaddr='', sa=None):
58 58 """
59 59 Action logger for various actions made by users
60 60
61 61 :param user: user that made this action, can be a unique username string or
62 62 object containing user_id attribute
63 63 :param action: action to log, should be on of predefined unique actions for
64 64 easy translations
65 65 :param repo: string name of repository or object containing repo_id,
66 66 that action was made on
67 67 :param ipaddr: optional ip address from what the action was made
68 68 :param sa: optional sqlalchemy session
69 69
70 70 """
71 71
72 72 if not sa:
73 73 sa = meta.Session()
74 74
75 75 try:
76 76 um = UserModel()
77 77 if hasattr(user, 'user_id'):
78 78 user_obj = user
79 79 elif isinstance(user, basestring):
80 80 user_obj = um.get_by_username(user, cache=False)
81 81 else:
82 82 raise Exception('You have to provide user object or username')
83 83
84 84
85 85 rm = RepoModel()
86 86 if hasattr(repo, 'repo_id'):
87 87 repo_obj = rm.get(repo.repo_id, cache=False)
88 88 repo_name = repo_obj.repo_name
89 89 elif isinstance(repo, basestring):
90 90 repo_name = repo.lstrip('/')
91 91 repo_obj = rm.get_by_repo_name(repo_name, cache=False)
92 92 else:
93 93 raise Exception('You have to provide repository to action logger')
94 94
95 95
96 96 user_log = UserLog()
97 97 user_log.user_id = user_obj.user_id
98 98 user_log.action = action
99 99
100 100 user_log.repository_id = repo_obj.repo_id
101 101 user_log.repository_name = repo_name
102 102
103 103 user_log.action_date = datetime.datetime.now()
104 104 user_log.user_ip = ipaddr
105 105 sa.add(user_log)
106 106 sa.commit()
107 107
108 108 log.info('Adding user %s, action %s on %s', user_obj, action, repo)
109 109 except:
110 110 log.error(traceback.format_exc())
111 111 sa.rollback()
112 112
113 113 def get_repos(path, recursive=False, initial=False):
114 114 """
115 115 Scans given path for repos and return (name,(type,path)) tuple
116
116 117 :param prefix:
117 118 :param path:
118 119 :param recursive:
119 120 :param initial:
120 121 """
121 122 from vcs.utils.helpers import get_scm
122 123 from vcs.exceptions import VCSError
123 124
124 125 try:
125 126 scm = get_scm(path)
126 127 except:
127 128 pass
128 129 else:
129 130 raise Exception('The given path %s should not be a repository got %s',
130 131 path, scm)
131 132
132 133 for dirpath in os.listdir(path):
133 134 try:
134 135 yield dirpath, get_scm(os.path.join(path, dirpath))
135 136 except VCSError:
136 137 pass
137 138
138 139 def check_repo_fast(repo_name, base_path):
139 140 """
140 Check given path for existance of directory
141 Check given path for existence of directory
141 142 :param repo_name:
142 143 :param base_path:
143 144
144 145 :return False: if this directory is present
145 146 """
146 147 if os.path.isdir(os.path.join(base_path, repo_name)):return False
147 148 return True
148 149
149 150 def check_repo(repo_name, base_path, verify=True):
150 151
151 152 repo_path = os.path.join(base_path, repo_name)
152 153
153 154 try:
154 155 if not check_repo_fast(repo_name, base_path):
155 156 return False
156 157 r = hg.repository(ui.ui(), repo_path)
157 158 if verify:
158 159 hg.verify(r)
159 160 #here we hnow that repo exists it was verified
160 161 log.info('%s repo is already created', repo_name)
161 162 return False
162 163 except RepoError:
163 164 #it means that there is no valid repo there...
164 165 log.info('%s repo is free for creation', repo_name)
165 166 return True
166 167
167 168 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
168 169 while True:
169 170 ok = raw_input(prompt)
170 171 if ok in ('y', 'ye', 'yes'): return True
171 172 if ok in ('n', 'no', 'nop', 'nope'): return False
172 173 retries = retries - 1
173 174 if retries < 0: raise IOError
174 175 print complaint
175 176
176 177 #propagated from mercurial documentation
177 178 ui_sections = ['alias', 'auth',
178 179 'decode/encode', 'defaults',
179 180 'diff', 'email',
180 181 'extensions', 'format',
181 182 'merge-patterns', 'merge-tools',
182 183 'hooks', 'http_proxy',
183 184 'smtp', 'patch',
184 185 'paths', 'profiling',
185 186 'server', 'trusted',
186 187 'ui', 'web', ]
187 188
188 189 def make_ui(read_from='file', path=None, checkpaths=True):
189 190 """
190 191 A function that will read python rc files or database
191 192 and make an mercurial ui object from read options
192 193
193 194 :param path: path to mercurial config file
194 195 :param checkpaths: check the path
195 196 :param read_from: read from 'file' or 'db'
196 197 """
197 198
198 199 baseui = ui.ui()
199 200
200 201 #clean the baseui object
201 202 baseui._ocfg = config.config()
202 203 baseui._ucfg = config.config()
203 204 baseui._tcfg = config.config()
204 205
205 206 if read_from == 'file':
206 207 if not os.path.isfile(path):
207 208 log.warning('Unable to read config file %s' % path)
208 209 return False
209 210 log.debug('reading hgrc from %s', path)
210 211 cfg = config.config()
211 212 cfg.read(path)
212 213 for section in ui_sections:
213 214 for k, v in cfg.items(section):
214 215 log.debug('settings ui from file[%s]%s:%s', section, k, v)
215 216 baseui.setconfig(section, k, v)
216 217
217 218
218 219 elif read_from == 'db':
219 220 sa = meta.Session()
220 221 ret = sa.query(RhodeCodeUi)\
221 222 .options(FromCache("sql_cache_short",
222 223 "get_hg_ui_settings")).all()
223 224
224 225 hg_ui = ret
225 226 for ui_ in hg_ui:
226 227 if ui_.ui_active:
227 228 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
228 229 ui_.ui_key, ui_.ui_value)
229 230 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
230 231
231 232 meta.Session.remove()
232 233 return baseui
233 234
234 235
235 236 def set_rhodecode_config(config):
236 """
237 Updates pylons config with new settings from database
237 """Updates pylons config with new settings from database
238
238 239 :param config:
239 240 """
240 241 from rhodecode.model.settings import SettingsModel
241 242 hgsettings = SettingsModel().get_app_settings()
242 243
243 244 for k, v in hgsettings.items():
244 245 config[k] = v
245 246
246 247 def invalidate_cache(cache_key, *args):
247 """
248 Puts cache invalidation task into db for
248 """Puts cache invalidation task into db for
249 249 further global cache invalidation
250 250 """
251
251 252 from rhodecode.model.scm import ScmModel
252 253
253 254 if cache_key.startswith('get_repo_cached_'):
254 255 name = cache_key.split('get_repo_cached_')[-1]
255 256 ScmModel().mark_for_invalidation(name)
256 257
257 258 class EmptyChangeset(BaseChangeset):
258 259 """
259 260 An dummy empty changeset. It's possible to pass hash when creating
260 261 an EmptyChangeset
261 262 """
262 263
263 264 def __init__(self, cs='0' * 40):
264 265 self._empty_cs = cs
265 266 self.revision = -1
266 267 self.message = ''
267 268 self.author = ''
268 269 self.date = ''
269 270
270 271 @LazyProperty
271 272 def raw_id(self):
272 """
273 Returns raw string identifying this changeset, useful for web
273 """Returns raw string identifying this changeset, useful for web
274 274 representation.
275 275 """
276
276 277 return self._empty_cs
277 278
278 279 @LazyProperty
279 280 def short_id(self):
280 281 return self.raw_id[:12]
281 282
282 283 def get_file_changeset(self, path):
283 284 return self
284 285
285 286 def get_file_content(self, path):
286 287 return u''
287 288
288 289 def get_file_size(self, path):
289 290 return 0
290 291
291 292 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
292 """
293 maps all found repositories into db
293 """maps all found repositories into db
294 294 """
295 295
296 296 sa = meta.Session()
297 297 rm = RepoModel()
298 298 user = sa.query(User).filter(User.admin == True).first()
299 299
300 300 for name, repo in initial_repo_list.items():
301 301 if not rm.get_by_repo_name(name, cache=False):
302 302 log.info('repository %s not found creating default', name)
303 303
304 304 form_data = {
305 305 'repo_name':name,
306 306 'repo_type':repo.alias,
307 307 'description':repo.description \
308 308 if repo.description != 'unknown' else \
309 309 '%s repository' % name,
310 310 'private':False
311 311 }
312 312 rm.create(form_data, user, just_db=True)
313 313
314 314 if remove_obsolete:
315 315 #remove from database those repositories that are not in the filesystem
316 316 for repo in sa.query(Repository).all():
317 317 if repo.repo_name not in initial_repo_list.keys():
318 318 sa.delete(repo)
319 319 sa.commit()
320 320
321 321 class OrderedDict(dict, DictMixin):
322 322
323 323 def __init__(self, *args, **kwds):
324 324 if len(args) > 1:
325 325 raise TypeError('expected at most 1 arguments, got %d' % len(args))
326 326 try:
327 327 self.__end
328 328 except AttributeError:
329 329 self.clear()
330 330 self.update(*args, **kwds)
331 331
332 332 def clear(self):
333 333 self.__end = end = []
334 334 end += [None, end, end] # sentinel node for doubly linked list
335 335 self.__map = {} # key --> [key, prev, next]
336 336 dict.clear(self)
337 337
338 338 def __setitem__(self, key, value):
339 339 if key not in self:
340 340 end = self.__end
341 341 curr = end[1]
342 342 curr[2] = end[1] = self.__map[key] = [key, curr, end]
343 343 dict.__setitem__(self, key, value)
344 344
345 345 def __delitem__(self, key):
346 346 dict.__delitem__(self, key)
347 347 key, prev, next = self.__map.pop(key)
348 348 prev[2] = next
349 349 next[1] = prev
350 350
351 351 def __iter__(self):
352 352 end = self.__end
353 353 curr = end[2]
354 354 while curr is not end:
355 355 yield curr[0]
356 356 curr = curr[2]
357 357
358 358 def __reversed__(self):
359 359 end = self.__end
360 360 curr = end[1]
361 361 while curr is not end:
362 362 yield curr[0]
363 363 curr = curr[1]
364 364
365 365 def popitem(self, last=True):
366 366 if not self:
367 367 raise KeyError('dictionary is empty')
368 368 if last:
369 369 key = reversed(self).next()
370 370 else:
371 371 key = iter(self).next()
372 372 value = self.pop(key)
373 373 return key, value
374 374
375 375 def __reduce__(self):
376 376 items = [[k, self[k]] for k in self]
377 377 tmp = self.__map, self.__end
378 378 del self.__map, self.__end
379 379 inst_dict = vars(self).copy()
380 380 self.__map, self.__end = tmp
381 381 if inst_dict:
382 382 return (self.__class__, (items,), inst_dict)
383 383 return self.__class__, (items,)
384 384
385 385 def keys(self):
386 386 return list(self)
387 387
388 388 setdefault = DictMixin.setdefault
389 389 update = DictMixin.update
390 390 pop = DictMixin.pop
391 391 values = DictMixin.values
392 392 items = DictMixin.items
393 393 iterkeys = DictMixin.iterkeys
394 394 itervalues = DictMixin.itervalues
395 395 iteritems = DictMixin.iteritems
396 396
397 397 def __repr__(self):
398 398 if not self:
399 399 return '%s()' % (self.__class__.__name__,)
400 400 return '%s(%r)' % (self.__class__.__name__, self.items())
401 401
402 402 def copy(self):
403 403 return self.__class__(self)
404 404
405 405 @classmethod
406 406 def fromkeys(cls, iterable, value=None):
407 407 d = cls()
408 408 for key in iterable:
409 409 d[key] = value
410 410 return d
411 411
412 412 def __eq__(self, other):
413 413 if isinstance(other, OrderedDict):
414 414 return len(self) == len(other) and self.items() == other.items()
415 415 return dict.__eq__(self, other)
416 416
417 417 def __ne__(self, other):
418 418 return not self == other
419 419
420 420
421 421 #set cache regions for beaker so celery can utilise it
422 422 def add_cache(settings):
423 423 cache_settings = {'regions':None}
424 424 for key in settings.keys():
425 425 for prefix in ['beaker.cache.', 'cache.']:
426 426 if key.startswith(prefix):
427 427 name = key.split(prefix)[1].strip()
428 428 cache_settings[name] = settings[key].strip()
429 429 if cache_settings['regions']:
430 430 for region in cache_settings['regions'].split(','):
431 431 region = region.strip()
432 432 region_settings = {}
433 433 for key, value in cache_settings.items():
434 434 if key.startswith(region):
435 435 region_settings[key.split('.')[1]] = value
436 436 region_settings['expire'] = int(region_settings.get('expire',
437 437 60))
438 438 region_settings.setdefault('lock_dir',
439 439 cache_settings.get('lock_dir'))
440 440 if 'type' not in region_settings:
441 441 region_settings['type'] = cache_settings.get('type',
442 442 'memory')
443 443 beaker.cache.cache_regions[region] = region_settings
444 444
445 445 def get_current_revision():
446 """
447 Returns tuple of (number, id) from repository containing this package
446 """Returns tuple of (number, id) from repository containing this package
448 447 or None if repository could not be found.
449 448 """
449
450 450 try:
451 451 from vcs import get_repo
452 452 from vcs.utils.helpers import get_scm
453 453 from vcs.exceptions import RepositoryError, VCSError
454 454 repopath = os.path.join(os.path.dirname(__file__), '..', '..')
455 455 scm = get_scm(repopath)[0]
456 456 repo = get_repo(path=repopath, alias=scm)
457 457 tip = repo.get_changeset()
458 458 return (tip.revision, tip.short_id)
459 459 except (ImportError, RepositoryError, VCSError), err:
460 460 logging.debug("Cannot retrieve rhodecode's revision. Original error "
461 461 "was: %s" % err)
462 462 return None
463 463
464 464 #===============================================================================
465 465 # TEST FUNCTIONS AND CREATORS
466 466 #===============================================================================
467 467 def create_test_index(repo_location, full_index):
468 468 """Makes default test index
469 469 :param repo_location:
470 470 :param full_index:
471 471 """
472 472 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
473 473 from rhodecode.lib.pidlock import DaemonLock, LockHeld
474 474 import shutil
475 475
476 476 index_location = os.path.join(repo_location, 'index')
477 477 if os.path.exists(index_location):
478 478 shutil.rmtree(index_location)
479 479
480 480 try:
481 481 l = DaemonLock()
482 482 WhooshIndexingDaemon(index_location=index_location,
483 483 repo_location=repo_location)\
484 484 .run(full_index=full_index)
485 485 l.release()
486 486 except LockHeld:
487 487 pass
488 488
489 489 def create_test_env(repos_test_path, config):
490 490 """Makes a fresh database and
491 491 install test repository into tmp dir
492 492 """
493 493 from rhodecode.lib.db_manage import DbManage
494 494 from rhodecode.tests import HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, \
495 495 HG_FORK, GIT_FORK, TESTS_TMP_PATH
496 496 import tarfile
497 497 import shutil
498 498 from os.path import dirname as dn, join as jn, abspath
499 499
500 500 log = logging.getLogger('TestEnvCreator')
501 501 # create logger
502 502 log.setLevel(logging.DEBUG)
503 503 log.propagate = True
504 504 # create console handler and set level to debug
505 505 ch = logging.StreamHandler()
506 506 ch.setLevel(logging.DEBUG)
507 507
508 508 # create formatter
509 509 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
510 510
511 511 # add formatter to ch
512 512 ch.setFormatter(formatter)
513 513
514 514 # add ch to logger
515 515 log.addHandler(ch)
516 516
517 517 #PART ONE create db
518 518 dbconf = config['sqlalchemy.db1.url']
519 519 log.debug('making test db %s', dbconf)
520 520
521 521 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
522 522 tests=True)
523 523 dbmanage.create_tables(override=True)
524 524 dbmanage.config_prompt(repos_test_path)
525 525 dbmanage.create_default_user()
526 526 dbmanage.admin_prompt()
527 527 dbmanage.create_permissions()
528 528 dbmanage.populate_default_permissions()
529 529
530 530 #PART TWO make test repo
531 531 log.debug('making test vcs repositories')
532 532
533 533 #remove old one from previos tests
534 534 for r in [HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, HG_FORK, GIT_FORK]:
535 535
536 536 if os.path.isdir(jn(TESTS_TMP_PATH, r)):
537 537 log.debug('removing %s', r)
538 538 shutil.rmtree(jn(TESTS_TMP_PATH, r))
539 539
540 540 #CREATE DEFAULT HG REPOSITORY
541 541 cur_dir = dn(dn(abspath(__file__)))
542 542 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
543 543 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
544 544 tar.close()
545 545
546 546
547 547 #==============================================================================
548 548 # PASTER COMMANDS
549 549 #==============================================================================
550 550
551 551 class BasePasterCommand(Command):
552 552 """
553 553 Abstract Base Class for paster commands.
554 554
555 555 The celery commands are somewhat aggressive about loading
556 556 celery.conf, and since our module sets the `CELERY_LOADER`
557 557 environment variable to our loader, we have to bootstrap a bit and
558 558 make sure we've had a chance to load the pylons config off of the
559 559 command line, otherwise everything fails.
560 560 """
561 561 min_args = 1
562 562 min_args_error = "Please provide a paster config file as an argument."
563 563 takes_config_file = 1
564 564 requires_config_file = True
565 565
566 566 def notify_msg(self, msg, log=False):
567 567 """Make a notification to user, additionally if logger is passed
568 568 it logs this action using given logger
569 569
570 570 :param msg: message that will be printed to user
571 571 :param log: logging instance, to use to additionally log this message
572 572
573 573 """
574 574 print msg
575 575 if log and isinstance(log, logging):
576 576 log(msg)
577 577
578 578
579 579 def run(self, args):
580 580 """
581 581 Overrides Command.run
582 582
583 583 Checks for a config file argument and loads it.
584 584 """
585 585 if len(args) < self.min_args:
586 586 raise BadCommand(
587 587 self.min_args_error % {'min_args': self.min_args,
588 588 'actual_args': len(args)})
589 589
590 590 # Decrement because we're going to lob off the first argument.
591 591 # @@ This is hacky
592 592 self.min_args -= 1
593 593 self.bootstrap_config(args[0])
594 594 self.update_parser()
595 595 return super(BasePasterCommand, self).run(args[1:])
596 596
597 597 def update_parser(self):
598 598 """
599 599 Abstract method. Allows for the class's parser to be updated
600 600 before the superclass's `run` method is called. Necessary to
601 601 allow options/arguments to be passed through to the underlying
602 602 celery command.
603 603 """
604 604 raise NotImplementedError("Abstract Method.")
605 605
606 606 def bootstrap_config(self, conf):
607 607 """
608 608 Loads the pylons configuration.
609 609 """
610 610 from pylons import config as pylonsconfig
611 611
612 612 path_to_ini_file = os.path.realpath(conf)
613 613 conf = paste.deploy.appconfig('config:' + path_to_ini_file)
614 614 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
General Comments 0
You need to be logged in to leave comments. Login now