Show More
@@ -32,8 +32,7 b' from tg import tmpl_context as c' | |||||
32 | from tg.i18n import ugettext as _ |
|
32 | from tg.i18n import ugettext as _ | |
33 | from webob.exc import HTTPFound |
|
33 | from webob.exc import HTTPFound | |
34 |
|
34 | |||
35 | from kallithea.lib import auth_modules |
|
35 | from kallithea.lib import auth_modules, webutils | |
36 | from kallithea.lib import helpers as h |
|
|||
37 | from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired |
|
36 | from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired | |
38 | from kallithea.lib.base import BaseController, render |
|
37 | from kallithea.lib.base import BaseController, render | |
39 | from kallithea.lib.webutils import url |
|
38 | from kallithea.lib.webutils import url | |
@@ -132,7 +131,7 b' class AuthSettingsController(BaseControl' | |||||
132 | log.debug("%s = %s", k, str(v)) |
|
131 | log.debug("%s = %s", k, str(v)) | |
133 | setting = db.Setting.create_or_update(k, v) |
|
132 | setting = db.Setting.create_or_update(k, v) | |
134 | meta.Session().commit() |
|
133 | meta.Session().commit() | |
135 |
|
|
134 | webutils.flash(_('Auth settings updated successfully'), | |
136 | category='success') |
|
135 | category='success') | |
137 | except formencode.Invalid as errors: |
|
136 | except formencode.Invalid as errors: | |
138 | log.error(traceback.format_exc()) |
|
137 | log.error(traceback.format_exc()) | |
@@ -143,7 +142,7 b' class AuthSettingsController(BaseControl' | |||||
143 | ) |
|
142 | ) | |
144 | except Exception: |
|
143 | except Exception: | |
145 | log.error(traceback.format_exc()) |
|
144 | log.error(traceback.format_exc()) | |
146 |
|
|
145 | webutils.flash(_('error occurred during update of auth settings'), | |
147 | category='error') |
|
146 | category='error') | |
148 |
|
147 | |||
149 | raise HTTPFound(location=url('auth_home')) |
|
148 | raise HTTPFound(location=url('auth_home')) |
@@ -34,7 +34,7 b' from tg import request' | |||||
34 | from tg.i18n import ugettext as _ |
|
34 | from tg.i18n import ugettext as _ | |
35 | from webob.exc import HTTPFound |
|
35 | from webob.exc import HTTPFound | |
36 |
|
36 | |||
37 |
from kallithea.lib import |
|
37 | from kallithea.lib import webutils | |
38 | from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired |
|
38 | from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired | |
39 | from kallithea.lib.base import BaseController, render |
|
39 | from kallithea.lib.base import BaseController, render | |
40 | from kallithea.lib.webutils import url |
|
40 | from kallithea.lib.webutils import url | |
@@ -70,7 +70,7 b' class DefaultsController(BaseController)' | |||||
70 | for k, v in form_result.items(): |
|
70 | for k, v in form_result.items(): | |
71 | setting = db.Setting.create_or_update(k, v) |
|
71 | setting = db.Setting.create_or_update(k, v) | |
72 | meta.Session().commit() |
|
72 | meta.Session().commit() | |
73 |
|
|
73 | webutils.flash(_('Default settings updated successfully'), | |
74 | category='success') |
|
74 | category='success') | |
75 |
|
75 | |||
76 | except formencode.Invalid as errors: |
|
76 | except formencode.Invalid as errors: | |
@@ -85,7 +85,7 b' class DefaultsController(BaseController)' | |||||
85 | force_defaults=False) |
|
85 | force_defaults=False) | |
86 | except Exception: |
|
86 | except Exception: | |
87 | log.error(traceback.format_exc()) |
|
87 | log.error(traceback.format_exc()) | |
88 |
|
|
88 | webutils.flash(_('Error occurred during update of defaults'), | |
89 | category='error') |
|
89 | category='error') | |
90 |
|
90 | |||
91 | raise HTTPFound(location=url('defaults')) |
|
91 | raise HTTPFound(location=url('defaults')) |
@@ -35,8 +35,7 b' from tg import tmpl_context as c' | |||||
35 | from tg.i18n import ugettext as _ |
|
35 | from tg.i18n import ugettext as _ | |
36 | from webob.exc import HTTPForbidden, HTTPFound, HTTPNotFound |
|
36 | from webob.exc import HTTPForbidden, HTTPFound, HTTPNotFound | |
37 |
|
37 | |||
38 | from kallithea.lib import auth |
|
38 | from kallithea.lib import auth, webutils | |
39 | from kallithea.lib import helpers as h |
|
|||
40 | from kallithea.lib.auth import LoginRequired |
|
39 | from kallithea.lib.auth import LoginRequired | |
41 | from kallithea.lib.base import BaseController, jsonify, render |
|
40 | from kallithea.lib.base import BaseController, jsonify, render | |
42 | from kallithea.lib.page import Page |
|
41 | from kallithea.lib.page import Page | |
@@ -144,7 +143,7 b' class GistsController(BaseController):' | |||||
144 |
|
143 | |||
145 | except Exception as e: |
|
144 | except Exception as e: | |
146 | log.error(traceback.format_exc()) |
|
145 | log.error(traceback.format_exc()) | |
147 |
|
|
146 | webutils.flash(_('Error occurred during gist creation'), category='error') | |
148 | raise HTTPFound(location=url('new_gist')) |
|
147 | raise HTTPFound(location=url('new_gist')) | |
149 | raise HTTPFound(location=url('gist', gist_id=new_gist_id)) |
|
148 | raise HTTPFound(location=url('gist', gist_id=new_gist_id)) | |
150 |
|
149 | |||
@@ -160,7 +159,7 b' class GistsController(BaseController):' | |||||
160 | if auth.HasPermissionAny('hg.admin')() or owner: |
|
159 | if auth.HasPermissionAny('hg.admin')() or owner: | |
161 | GistModel().delete(gist) |
|
160 | GistModel().delete(gist) | |
162 | meta.Session().commit() |
|
161 | meta.Session().commit() | |
163 |
|
|
162 | webutils.flash(_('Deleted gist %s') % gist.gist_access_id, category='success') | |
164 | else: |
|
163 | else: | |
165 | raise HTTPForbidden() |
|
164 | raise HTTPForbidden() | |
166 |
|
165 | |||
@@ -233,15 +232,15 b' class GistsController(BaseController):' | |||||
233 | ) |
|
232 | ) | |
234 |
|
233 | |||
235 | meta.Session().commit() |
|
234 | meta.Session().commit() | |
236 |
|
|
235 | webutils.flash(_('Successfully updated gist content'), category='success') | |
237 | except NodeNotChangedError: |
|
236 | except NodeNotChangedError: | |
238 | # raised if nothing was changed in repo itself. We anyway then |
|
237 | # raised if nothing was changed in repo itself. We anyway then | |
239 | # store only DB stuff for gist |
|
238 | # store only DB stuff for gist | |
240 | meta.Session().commit() |
|
239 | meta.Session().commit() | |
241 |
|
|
240 | webutils.flash(_('Successfully updated gist data'), category='success') | |
242 | except Exception: |
|
241 | except Exception: | |
243 | log.error(traceback.format_exc()) |
|
242 | log.error(traceback.format_exc()) | |
244 |
|
|
243 | webutils.flash(_('Error occurred during update of gist %s') % gist_id, | |
245 | category='error') |
|
244 | category='error') | |
246 |
|
245 | |||
247 | raise HTTPFound(location=url('gist', gist_id=gist_id)) |
|
246 | raise HTTPFound(location=url('gist', gist_id=gist_id)) |
@@ -35,8 +35,7 b' from tg import tmpl_context as c' | |||||
35 | from tg.i18n import ugettext as _ |
|
35 | from tg.i18n import ugettext as _ | |
36 | from webob.exc import HTTPFound |
|
36 | from webob.exc import HTTPFound | |
37 |
|
37 | |||
38 | from kallithea.lib import auth_modules |
|
38 | from kallithea.lib import auth_modules, webutils | |
39 | from kallithea.lib import helpers as h |
|
|||
40 | from kallithea.lib.auth import AuthUser, LoginRequired |
|
39 | from kallithea.lib.auth import AuthUser, LoginRequired | |
41 | from kallithea.lib.base import BaseController, IfSshEnabled, render |
|
40 | from kallithea.lib.base import BaseController, IfSshEnabled, render | |
42 | from kallithea.lib.utils2 import generate_api_key, safe_int |
|
41 | from kallithea.lib.utils2 import generate_api_key, safe_int | |
@@ -61,7 +60,7 b' class MyAccountController(BaseController' | |||||
61 | def __load_data(self): |
|
60 | def __load_data(self): | |
62 | c.user = db.User.get(request.authuser.user_id) |
|
61 | c.user = db.User.get(request.authuser.user_id) | |
63 | if c.user.is_default_user: |
|
62 | if c.user.is_default_user: | |
64 |
|
|
63 | webutils.flash(_("You can't edit this user since it's" | |
65 | " crucial for entire application"), category='warning') |
|
64 | " crucial for entire application"), category='warning') | |
66 | raise HTTPFound(location=url('users')) |
|
65 | raise HTTPFound(location=url('users')) | |
67 |
|
66 | |||
@@ -110,7 +109,7 b' class MyAccountController(BaseController' | |||||
110 |
|
109 | |||
111 | UserModel().update(request.authuser.user_id, form_result, |
|
110 | UserModel().update(request.authuser.user_id, form_result, | |
112 | skip_attrs=skip_attrs) |
|
111 | skip_attrs=skip_attrs) | |
113 |
|
|
112 | webutils.flash(_('Your account was updated successfully'), | |
114 | category='success') |
|
113 | category='success') | |
115 | meta.Session().commit() |
|
114 | meta.Session().commit() | |
116 | update = True |
|
115 | update = True | |
@@ -125,7 +124,7 b' class MyAccountController(BaseController' | |||||
125 | force_defaults=False) |
|
124 | force_defaults=False) | |
126 | except Exception: |
|
125 | except Exception: | |
127 | log.error(traceback.format_exc()) |
|
126 | log.error(traceback.format_exc()) | |
128 |
|
|
127 | webutils.flash(_('Error occurred during update of user %s') | |
129 | % form_result.get('username'), category='error') |
|
128 | % form_result.get('username'), category='error') | |
130 | if update: |
|
129 | if update: | |
131 | raise HTTPFound(location='my_account') |
|
130 | raise HTTPFound(location='my_account') | |
@@ -148,7 +147,7 b' class MyAccountController(BaseController' | |||||
148 | form_result = _form.to_python(request.POST) |
|
147 | form_result = _form.to_python(request.POST) | |
149 | UserModel().update(request.authuser.user_id, form_result) |
|
148 | UserModel().update(request.authuser.user_id, form_result) | |
150 | meta.Session().commit() |
|
149 | meta.Session().commit() | |
151 |
|
|
150 | webutils.flash(_("Successfully updated password"), category='success') | |
152 | except formencode.Invalid as errors: |
|
151 | except formencode.Invalid as errors: | |
153 | return htmlfill.render( |
|
152 | return htmlfill.render( | |
154 | render('admin/my_account/my_account.html'), |
|
153 | render('admin/my_account/my_account.html'), | |
@@ -159,7 +158,7 b' class MyAccountController(BaseController' | |||||
159 | force_defaults=False) |
|
158 | force_defaults=False) | |
160 | except Exception: |
|
159 | except Exception: | |
161 | log.error(traceback.format_exc()) |
|
160 | log.error(traceback.format_exc()) | |
162 |
|
|
161 | webutils.flash(_('Error occurred during update of user password'), | |
163 | category='error') |
|
162 | category='error') | |
164 | return render('admin/my_account/my_account.html') |
|
163 | return render('admin/my_account/my_account.html') | |
165 |
|
164 | |||
@@ -200,13 +199,13 b' class MyAccountController(BaseController' | |||||
200 | try: |
|
199 | try: | |
201 | UserModel().add_extra_email(request.authuser.user_id, email) |
|
200 | UserModel().add_extra_email(request.authuser.user_id, email) | |
202 | meta.Session().commit() |
|
201 | meta.Session().commit() | |
203 |
|
|
202 | webutils.flash(_("Added email %s to user") % email, category='success') | |
204 | except formencode.Invalid as error: |
|
203 | except formencode.Invalid as error: | |
205 | msg = error.error_dict['email'] |
|
204 | msg = error.error_dict['email'] | |
206 |
|
|
205 | webutils.flash(msg, category='error') | |
207 | except Exception: |
|
206 | except Exception: | |
208 | log.error(traceback.format_exc()) |
|
207 | log.error(traceback.format_exc()) | |
209 |
|
|
208 | webutils.flash(_('An error occurred during email saving'), | |
210 | category='error') |
|
209 | category='error') | |
211 | raise HTTPFound(location=url('my_account_emails')) |
|
210 | raise HTTPFound(location=url('my_account_emails')) | |
212 |
|
211 | |||
@@ -215,7 +214,7 b' class MyAccountController(BaseController' | |||||
215 | user_model = UserModel() |
|
214 | user_model = UserModel() | |
216 | user_model.delete_extra_email(request.authuser.user_id, email_id) |
|
215 | user_model.delete_extra_email(request.authuser.user_id, email_id) | |
217 | meta.Session().commit() |
|
216 | meta.Session().commit() | |
218 |
|
|
217 | webutils.flash(_("Removed email from user"), category='success') | |
219 | raise HTTPFound(location=url('my_account_emails')) |
|
218 | raise HTTPFound(location=url('my_account_emails')) | |
220 |
|
219 | |||
221 | def my_account_api_keys(self): |
|
220 | def my_account_api_keys(self): | |
@@ -239,7 +238,7 b' class MyAccountController(BaseController' | |||||
239 | description = request.POST.get('description') |
|
238 | description = request.POST.get('description') | |
240 | ApiKeyModel().create(request.authuser.user_id, description, lifetime) |
|
239 | ApiKeyModel().create(request.authuser.user_id, description, lifetime) | |
241 | meta.Session().commit() |
|
240 | meta.Session().commit() | |
242 |
|
|
241 | webutils.flash(_("API key successfully created"), category='success') | |
243 | raise HTTPFound(location=url('my_account_api_keys')) |
|
242 | raise HTTPFound(location=url('my_account_api_keys')) | |
244 |
|
243 | |||
245 | def my_account_api_keys_delete(self): |
|
244 | def my_account_api_keys_delete(self): | |
@@ -248,11 +247,11 b' class MyAccountController(BaseController' | |||||
248 | user = db.User.get(request.authuser.user_id) |
|
247 | user = db.User.get(request.authuser.user_id) | |
249 | user.api_key = generate_api_key() |
|
248 | user.api_key = generate_api_key() | |
250 | meta.Session().commit() |
|
249 | meta.Session().commit() | |
251 |
|
|
250 | webutils.flash(_("API key successfully reset"), category='success') | |
252 | elif api_key: |
|
251 | elif api_key: | |
253 | ApiKeyModel().delete(api_key, request.authuser.user_id) |
|
252 | ApiKeyModel().delete(api_key, request.authuser.user_id) | |
254 | meta.Session().commit() |
|
253 | meta.Session().commit() | |
255 |
|
|
254 | webutils.flash(_("API key successfully deleted"), category='success') | |
256 |
|
255 | |||
257 | raise HTTPFound(location=url('my_account_api_keys')) |
|
256 | raise HTTPFound(location=url('my_account_api_keys')) | |
258 |
|
257 | |||
@@ -272,9 +271,9 b' class MyAccountController(BaseController' | |||||
272 | description, public_key) |
|
271 | description, public_key) | |
273 | meta.Session().commit() |
|
272 | meta.Session().commit() | |
274 | SshKeyModel().write_authorized_keys() |
|
273 | SshKeyModel().write_authorized_keys() | |
275 |
|
|
274 | webutils.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success') | |
276 | except SshKeyModelException as e: |
|
275 | except SshKeyModelException as e: | |
277 |
|
|
276 | webutils.flash(e.args[0], category='error') | |
278 | raise HTTPFound(location=url('my_account_ssh_keys')) |
|
277 | raise HTTPFound(location=url('my_account_ssh_keys')) | |
279 |
|
278 | |||
280 | @IfSshEnabled |
|
279 | @IfSshEnabled | |
@@ -284,7 +283,7 b' class MyAccountController(BaseController' | |||||
284 | SshKeyModel().delete(fingerprint, request.authuser.user_id) |
|
283 | SshKeyModel().delete(fingerprint, request.authuser.user_id) | |
285 | meta.Session().commit() |
|
284 | meta.Session().commit() | |
286 | SshKeyModel().write_authorized_keys() |
|
285 | SshKeyModel().write_authorized_keys() | |
287 |
|
|
286 | webutils.flash(_("SSH key successfully deleted"), category='success') | |
288 | except SshKeyModelException as e: |
|
287 | except SshKeyModelException as e: | |
289 |
|
|
288 | webutils.flash(e.args[0], category='error') | |
290 | raise HTTPFound(location=url('my_account_ssh_keys')) |
|
289 | raise HTTPFound(location=url('my_account_ssh_keys')) |
@@ -36,7 +36,7 b' from tg import tmpl_context as c' | |||||
36 | from tg.i18n import ugettext as _ |
|
36 | from tg.i18n import ugettext as _ | |
37 | from webob.exc import HTTPFound |
|
37 | from webob.exc import HTTPFound | |
38 |
|
38 | |||
39 |
from kallithea.lib import |
|
39 | from kallithea.lib import webutils | |
40 | from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired |
|
40 | from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired | |
41 | from kallithea.lib.base import BaseController, render |
|
41 | from kallithea.lib.base import BaseController, render | |
42 | from kallithea.lib.webutils import url |
|
42 | from kallithea.lib.webutils import url | |
@@ -113,7 +113,7 b' class PermissionsController(BaseControll' | |||||
113 | form_result.update({'perm_user_name': 'default'}) |
|
113 | form_result.update({'perm_user_name': 'default'}) | |
114 | PermissionModel().update(form_result) |
|
114 | PermissionModel().update(form_result) | |
115 | meta.Session().commit() |
|
115 | meta.Session().commit() | |
116 |
|
|
116 | webutils.flash(_('Global permissions updated successfully'), | |
117 | category='success') |
|
117 | category='success') | |
118 |
|
118 | |||
119 | except formencode.Invalid as errors: |
|
119 | except formencode.Invalid as errors: | |
@@ -128,7 +128,7 b' class PermissionsController(BaseControll' | |||||
128 | force_defaults=False) |
|
128 | force_defaults=False) | |
129 | except Exception: |
|
129 | except Exception: | |
130 | log.error(traceback.format_exc()) |
|
130 | log.error(traceback.format_exc()) | |
131 |
|
|
131 | webutils.flash(_('Error occurred during update of permissions'), | |
132 | category='error') |
|
132 | category='error') | |
133 |
|
133 | |||
134 | raise HTTPFound(location=url('admin_permissions')) |
|
134 | raise HTTPFound(location=url('admin_permissions')) |
@@ -37,6 +37,7 b' from tg.i18n import ungettext' | |||||
37 | from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound |
|
37 | from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound | |
38 |
|
38 | |||
39 | from kallithea.lib import helpers as h |
|
39 | from kallithea.lib import helpers as h | |
|
40 | from kallithea.lib import webutils | |||
40 | from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoGroupPermissionLevelDecorator, LoginRequired |
|
41 | from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoGroupPermissionLevelDecorator, LoginRequired | |
41 | from kallithea.lib.base import BaseController, render |
|
42 | from kallithea.lib.base import BaseController, render | |
42 | from kallithea.lib.utils2 import safe_int |
|
43 | from kallithea.lib.utils2 import safe_int | |
@@ -118,7 +119,7 b' class RepoGroupsController(BaseControlle' | |||||
118 | repo_groups_data.append({ |
|
119 | repo_groups_data.append({ | |
119 | "raw_name": repo_gr.group_name, |
|
120 | "raw_name": repo_gr.group_name, | |
120 | "group_name": repo_group_name(repo_gr.group_name, children_groups), |
|
121 | "group_name": repo_group_name(repo_gr.group_name, children_groups), | |
121 |
"desc": |
|
122 | "desc": webutils.escape(repo_gr.group_description), | |
122 | "repos": repo_count, |
|
123 | "repos": repo_count, | |
123 | "owner": h.person(repo_gr.owner), |
|
124 | "owner": h.person(repo_gr.owner), | |
124 | "action": repo_group_actions(repo_gr.group_id, repo_gr.group_name, |
|
125 | "action": repo_group_actions(repo_gr.group_id, repo_gr.group_name, | |
@@ -161,14 +162,14 b' class RepoGroupsController(BaseControlle' | |||||
161 | force_defaults=False) |
|
162 | force_defaults=False) | |
162 | except Exception: |
|
163 | except Exception: | |
163 | log.error(traceback.format_exc()) |
|
164 | log.error(traceback.format_exc()) | |
164 |
|
|
165 | webutils.flash(_('Error occurred during creation of repository group %s') | |
165 | % request.POST.get('group_name'), category='error') |
|
166 | % request.POST.get('group_name'), category='error') | |
166 | if form_result is None: |
|
167 | if form_result is None: | |
167 | raise |
|
168 | raise | |
168 | parent_group_id = form_result['parent_group_id'] |
|
169 | parent_group_id = form_result['parent_group_id'] | |
169 | # TODO: maybe we should get back to the main view, not the admin one |
|
170 | # TODO: maybe we should get back to the main view, not the admin one | |
170 | raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id)) |
|
171 | raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id)) | |
171 |
|
|
172 | webutils.flash(_('Created repository group %s') % gr.group_name, | |
172 | category='success') |
|
173 | category='success') | |
173 | raise HTTPFound(location=url('repos_group_home', group_name=gr.group_name)) |
|
174 | raise HTTPFound(location=url('repos_group_home', group_name=gr.group_name)) | |
174 |
|
175 | |||
@@ -215,7 +216,7 b' class RepoGroupsController(BaseControlle' | |||||
215 |
|
216 | |||
216 | new_gr = RepoGroupModel().update(group_name, form_result) |
|
217 | new_gr = RepoGroupModel().update(group_name, form_result) | |
217 | meta.Session().commit() |
|
218 | meta.Session().commit() | |
218 |
|
|
219 | webutils.flash(_('Updated repository group %s') | |
219 | % form_result['group_name'], category='success') |
|
220 | % form_result['group_name'], category='success') | |
220 | # we now have new name ! |
|
221 | # we now have new name ! | |
221 | group_name = new_gr.group_name |
|
222 | group_name = new_gr.group_name | |
@@ -231,7 +232,7 b' class RepoGroupsController(BaseControlle' | |||||
231 | force_defaults=False) |
|
232 | force_defaults=False) | |
232 | except Exception: |
|
233 | except Exception: | |
233 | log.error(traceback.format_exc()) |
|
234 | log.error(traceback.format_exc()) | |
234 |
|
|
235 | webutils.flash(_('Error occurred during update of repository group %s') | |
235 | % request.POST.get('group_name'), category='error') |
|
236 | % request.POST.get('group_name'), category='error') | |
236 |
|
237 | |||
237 | raise HTTPFound(location=url('edit_repo_group', group_name=group_name)) |
|
238 | raise HTTPFound(location=url('edit_repo_group', group_name=group_name)) | |
@@ -241,25 +242,25 b' class RepoGroupsController(BaseControlle' | |||||
241 | gr = c.repo_group = db.RepoGroup.guess_instance(group_name) |
|
242 | gr = c.repo_group = db.RepoGroup.guess_instance(group_name) | |
242 | repos = gr.repositories.all() |
|
243 | repos = gr.repositories.all() | |
243 | if repos: |
|
244 | if repos: | |
244 |
|
|
245 | webutils.flash(_('This group contains %s repositories and cannot be ' | |
245 | 'deleted') % len(repos), category='warning') |
|
246 | 'deleted') % len(repos), category='warning') | |
246 | raise HTTPFound(location=url('repos_groups')) |
|
247 | raise HTTPFound(location=url('repos_groups')) | |
247 |
|
248 | |||
248 | children = gr.children.all() |
|
249 | children = gr.children.all() | |
249 | if children: |
|
250 | if children: | |
250 |
|
|
251 | webutils.flash(_('This group contains %s subgroups and cannot be deleted' | |
251 | % (len(children))), category='warning') |
|
252 | % (len(children))), category='warning') | |
252 | raise HTTPFound(location=url('repos_groups')) |
|
253 | raise HTTPFound(location=url('repos_groups')) | |
253 |
|
254 | |||
254 | try: |
|
255 | try: | |
255 | RepoGroupModel().delete(group_name) |
|
256 | RepoGroupModel().delete(group_name) | |
256 | meta.Session().commit() |
|
257 | meta.Session().commit() | |
257 |
|
|
258 | webutils.flash(_('Removed repository group %s') % group_name, | |
258 | category='success') |
|
259 | category='success') | |
259 | # TODO: in future action_logger(, '', '', '') |
|
260 | # TODO: in future action_logger(, '', '', '') | |
260 | except Exception: |
|
261 | except Exception: | |
261 | log.error(traceback.format_exc()) |
|
262 | log.error(traceback.format_exc()) | |
262 |
|
|
263 | webutils.flash(_('Error occurred during deletion of repository group %s') | |
263 | % group_name, category='error') |
|
264 | % group_name, category='error') | |
264 |
|
265 | |||
265 | if gr.parent_group: |
|
266 | if gr.parent_group: | |
@@ -344,7 +345,7 b' class RepoGroupsController(BaseControlle' | |||||
344 | if not request.authuser.is_admin: |
|
345 | if not request.authuser.is_admin: | |
345 | if self._revoke_perms_on_yourself(form_result): |
|
346 | if self._revoke_perms_on_yourself(form_result): | |
346 | msg = _('Cannot revoke permission for yourself as admin') |
|
347 | msg = _('Cannot revoke permission for yourself as admin') | |
347 |
|
|
348 | webutils.flash(msg, category='warning') | |
348 | raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name)) |
|
349 | raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name)) | |
349 | recursive = form_result['recursive'] |
|
350 | recursive = form_result['recursive'] | |
350 | # iterate over all members(if in recursive mode) of this groups and |
|
351 | # iterate over all members(if in recursive mode) of this groups and | |
@@ -358,7 +359,7 b' class RepoGroupsController(BaseControlle' | |||||
358 | #action_logger(request.authuser, 'admin_changed_repo_permissions', |
|
359 | #action_logger(request.authuser, 'admin_changed_repo_permissions', | |
359 | # repo_name, request.ip_addr) |
|
360 | # repo_name, request.ip_addr) | |
360 | meta.Session().commit() |
|
361 | meta.Session().commit() | |
361 |
|
|
362 | webutils.flash(_('Repository group permissions updated'), category='success') | |
362 | raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name)) |
|
363 | raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name)) | |
363 |
|
364 | |||
364 | @HasRepoGroupPermissionLevelDecorator('admin') |
|
365 | @HasRepoGroupPermissionLevelDecorator('admin') | |
@@ -374,7 +375,7 b' class RepoGroupsController(BaseControlle' | |||||
374 | if not request.authuser.is_admin: |
|
375 | if not request.authuser.is_admin: | |
375 | if obj_type == 'user' and request.authuser.user_id == obj_id: |
|
376 | if obj_type == 'user' and request.authuser.user_id == obj_id: | |
376 | msg = _('Cannot revoke permission for yourself as admin') |
|
377 | msg = _('Cannot revoke permission for yourself as admin') | |
377 |
|
|
378 | webutils.flash(msg, category='warning') | |
378 | raise Exception('revoke admin permission on self') |
|
379 | raise Exception('revoke admin permission on self') | |
379 | recursive = request.POST.get('recursive', 'none') |
|
380 | recursive = request.POST.get('recursive', 'none') | |
380 | if obj_type == 'user': |
|
381 | if obj_type == 'user': | |
@@ -390,6 +391,6 b' class RepoGroupsController(BaseControlle' | |||||
390 | meta.Session().commit() |
|
391 | meta.Session().commit() | |
391 | except Exception: |
|
392 | except Exception: | |
392 | log.error(traceback.format_exc()) |
|
393 | log.error(traceback.format_exc()) | |
393 |
|
|
394 | webutils.flash(_('An error occurred during revoking of permission'), | |
394 | category='error') |
|
395 | category='error') | |
395 | raise HTTPInternalServerError() |
|
396 | raise HTTPInternalServerError() |
@@ -37,7 +37,6 b' from tg.i18n import ugettext as _' | |||||
37 | from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound |
|
37 | from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound | |
38 |
|
38 | |||
39 | import kallithea |
|
39 | import kallithea | |
40 | from kallithea.lib import helpers as h |
|
|||
41 | from kallithea.lib import webutils |
|
40 | from kallithea.lib import webutils | |
42 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired, NotAnonymous |
|
41 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired, NotAnonymous | |
43 | from kallithea.lib.base import BaseRepoController, jsonify, render |
|
42 | from kallithea.lib.base import BaseRepoController, jsonify, render | |
@@ -125,7 +124,7 b' class ReposController(BaseRepoController' | |||||
125 | log.error(traceback.format_exc()) |
|
124 | log.error(traceback.format_exc()) | |
126 | msg = (_('Error creating repository %s') |
|
125 | msg = (_('Error creating repository %s') | |
127 | % form_result.get('repo_name')) |
|
126 | % form_result.get('repo_name')) | |
128 |
|
|
127 | webutils.flash(msg, category='error') | |
129 | raise HTTPFound(location=url('home')) |
|
128 | raise HTTPFound(location=url('home')) | |
130 |
|
129 | |||
131 | raise HTTPFound(location=webutils.url('repo_creating_home', |
|
130 | raise HTTPFound(location=webutils.url('repo_creating_home', | |
@@ -179,19 +178,19 b' class ReposController(BaseRepoController' | |||||
179 | repo = db.Repository.get_by_repo_name(repo_name) |
|
178 | repo = db.Repository.get_by_repo_name(repo_name) | |
180 | if repo and repo.repo_state == db.Repository.STATE_CREATED: |
|
179 | if repo and repo.repo_state == db.Repository.STATE_CREATED: | |
181 | if repo.clone_uri: |
|
180 | if repo.clone_uri: | |
182 |
|
|
181 | webutils.flash(_('Created repository %s from %s') | |
183 | % (repo.repo_name, repo.clone_uri_hidden), category='success') |
|
182 | % (repo.repo_name, repo.clone_uri_hidden), category='success') | |
184 | else: |
|
183 | else: | |
185 |
repo_url = |
|
184 | repo_url = webutils.link_to(repo.repo_name, | |
186 | webutils.url('summary_home', |
|
185 | webutils.url('summary_home', | |
187 | repo_name=repo.repo_name)) |
|
186 | repo_name=repo.repo_name)) | |
188 | fork = repo.fork |
|
187 | fork = repo.fork | |
189 | if fork is not None: |
|
188 | if fork is not None: | |
190 | fork_name = fork.repo_name |
|
189 | fork_name = fork.repo_name | |
191 |
|
|
190 | webutils.flash(webutils.HTML(_('Forked repository %s as %s')) | |
192 | % (fork_name, repo_url), category='success') |
|
191 | % (fork_name, repo_url), category='success') | |
193 | else: |
|
192 | else: | |
194 |
|
|
193 | webutils.flash(webutils.HTML(_('Created repository %s')) % repo_url, | |
195 | category='success') |
|
194 | category='success') | |
196 | return {'result': True} |
|
195 | return {'result': True} | |
197 | return {'result': False} |
|
196 | return {'result': False} | |
@@ -220,7 +219,7 b' class ReposController(BaseRepoController' | |||||
220 | form_result = _form.to_python(dict(request.POST)) |
|
219 | form_result = _form.to_python(dict(request.POST)) | |
221 | repo = repo_model.update(repo_name, **form_result) |
|
220 | repo = repo_model.update(repo_name, **form_result) | |
222 | ScmModel().mark_for_invalidation(repo_name) |
|
221 | ScmModel().mark_for_invalidation(repo_name) | |
223 |
|
|
222 | webutils.flash(_('Repository %s updated successfully') % repo_name, | |
224 | category='success') |
|
223 | category='success') | |
225 | changed_name = repo.repo_name |
|
224 | changed_name = repo.repo_name | |
226 | action_logger(request.authuser, 'admin_updated_repo', |
|
225 | action_logger(request.authuser, 'admin_updated_repo', | |
@@ -240,7 +239,7 b' class ReposController(BaseRepoController' | |||||
240 |
|
239 | |||
241 | except Exception: |
|
240 | except Exception: | |
242 | log.error(traceback.format_exc()) |
|
241 | log.error(traceback.format_exc()) | |
243 |
|
|
242 | webutils.flash(_('Error occurred during update of repository %s') | |
244 | % repo_name, category='error') |
|
243 | % repo_name, category='error') | |
245 | raise HTTPFound(location=url('edit_repo', repo_name=changed_name)) |
|
244 | raise HTTPFound(location=url('edit_repo', repo_name=changed_name)) | |
246 |
|
245 | |||
@@ -257,23 +256,23 b' class ReposController(BaseRepoController' | |||||
257 | do = request.POST['forks'] |
|
256 | do = request.POST['forks'] | |
258 | if do == 'detach_forks': |
|
257 | if do == 'detach_forks': | |
259 | handle_forks = 'detach' |
|
258 | handle_forks = 'detach' | |
260 |
|
|
259 | webutils.flash(_('Detached %s forks') % _forks, category='success') | |
261 | elif do == 'delete_forks': |
|
260 | elif do == 'delete_forks': | |
262 | handle_forks = 'delete' |
|
261 | handle_forks = 'delete' | |
263 |
|
|
262 | webutils.flash(_('Deleted %s forks') % _forks, category='success') | |
264 | repo_model.delete(repo, forks=handle_forks) |
|
263 | repo_model.delete(repo, forks=handle_forks) | |
265 | action_logger(request.authuser, 'admin_deleted_repo', |
|
264 | action_logger(request.authuser, 'admin_deleted_repo', | |
266 | repo_name, request.ip_addr) |
|
265 | repo_name, request.ip_addr) | |
267 | ScmModel().mark_for_invalidation(repo_name) |
|
266 | ScmModel().mark_for_invalidation(repo_name) | |
268 |
|
|
267 | webutils.flash(_('Deleted repository %s') % repo_name, category='success') | |
269 | meta.Session().commit() |
|
268 | meta.Session().commit() | |
270 | except AttachedForksError: |
|
269 | except AttachedForksError: | |
271 |
|
|
270 | webutils.flash(_('Cannot delete repository %s which still has forks') | |
272 | % repo_name, category='warning') |
|
271 | % repo_name, category='warning') | |
273 |
|
272 | |||
274 | except Exception: |
|
273 | except Exception: | |
275 | log.error(traceback.format_exc()) |
|
274 | log.error(traceback.format_exc()) | |
276 |
|
|
275 | webutils.flash(_('An error occurred during deletion of %s') % repo_name, | |
277 | category='error') |
|
276 | category='error') | |
278 |
|
277 | |||
279 | if repo.group: |
|
278 | if repo.group: | |
@@ -313,7 +312,7 b' class ReposController(BaseRepoController' | |||||
313 | #action_logger(request.authuser, 'admin_changed_repo_permissions', |
|
312 | #action_logger(request.authuser, 'admin_changed_repo_permissions', | |
314 | # repo_name, request.ip_addr) |
|
313 | # repo_name, request.ip_addr) | |
315 | meta.Session().commit() |
|
314 | meta.Session().commit() | |
316 |
|
|
315 | webutils.flash(_('Repository permissions updated'), category='success') | |
317 | raise HTTPFound(location=url('edit_repo_perms', repo_name=repo_name)) |
|
316 | raise HTTPFound(location=url('edit_repo_perms', repo_name=repo_name)) | |
318 |
|
317 | |||
319 | @HasRepoPermissionLevelDecorator('admin') |
|
318 | @HasRepoPermissionLevelDecorator('admin') | |
@@ -342,7 +341,7 b' class ReposController(BaseRepoController' | |||||
342 | meta.Session().commit() |
|
341 | meta.Session().commit() | |
343 | except Exception: |
|
342 | except Exception: | |
344 | log.error(traceback.format_exc()) |
|
343 | log.error(traceback.format_exc()) | |
345 |
|
|
344 | webutils.flash(_('An error occurred during revoking of permission'), | |
346 | category='error') |
|
345 | category='error') | |
347 | raise HTTPInternalServerError() |
|
346 | raise HTTPInternalServerError() | |
348 | return [] |
|
347 | return [] | |
@@ -372,10 +371,10 b' class ReposController(BaseRepoController' | |||||
372 | meta.Session().add(new_field) |
|
371 | meta.Session().add(new_field) | |
373 | meta.Session().commit() |
|
372 | meta.Session().commit() | |
374 | except formencode.Invalid as e: |
|
373 | except formencode.Invalid as e: | |
375 |
|
|
374 | webutils.flash(_('Field validation error: %s') % e.msg, category='error') | |
376 | except Exception as e: |
|
375 | except Exception as e: | |
377 | log.error(traceback.format_exc()) |
|
376 | log.error(traceback.format_exc()) | |
378 |
|
|
377 | webutils.flash(_('An error occurred during creation of field: %r') % e, category='error') | |
379 | raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) |
|
378 | raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) | |
380 |
|
379 | |||
381 | @HasRepoPermissionLevelDecorator('admin') |
|
380 | @HasRepoPermissionLevelDecorator('admin') | |
@@ -387,7 +386,7 b' class ReposController(BaseRepoController' | |||||
387 | except Exception as e: |
|
386 | except Exception as e: | |
388 | log.error(traceback.format_exc()) |
|
387 | log.error(traceback.format_exc()) | |
389 | msg = _('An error occurred during removal of field') |
|
388 | msg = _('An error occurred during removal of field') | |
390 |
|
|
389 | webutils.flash(msg, category='error') | |
391 | raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) |
|
390 | raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) | |
392 |
|
391 | |||
393 | @HasRepoPermissionLevelDecorator('admin') |
|
392 | @HasRepoPermissionLevelDecorator('admin') | |
@@ -432,11 +431,11 b' class ReposController(BaseRepoController' | |||||
432 | repo_id = db.Repository.get_by_repo_name(repo_name).repo_id |
|
431 | repo_id = db.Repository.get_by_repo_name(repo_name).repo_id | |
433 | user_id = kallithea.DEFAULT_USER_ID |
|
432 | user_id = kallithea.DEFAULT_USER_ID | |
434 | self.scm_model.toggle_following_repo(repo_id, user_id) |
|
433 | self.scm_model.toggle_following_repo(repo_id, user_id) | |
435 |
|
|
434 | webutils.flash(_('Updated repository visibility in public journal'), | |
436 | category='success') |
|
435 | category='success') | |
437 | meta.Session().commit() |
|
436 | meta.Session().commit() | |
438 | except Exception: |
|
437 | except Exception: | |
439 |
|
|
438 | webutils.flash(_('An error occurred during setting this' | |
440 | ' repository in public journal'), |
|
439 | ' repository in public journal'), | |
441 | category='error') |
|
440 | category='error') | |
442 | raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) |
|
441 | raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) | |
@@ -454,14 +453,14 b' class ReposController(BaseRepoController' | |||||
454 | request.authuser.username) |
|
453 | request.authuser.username) | |
455 | fork = repo.fork.repo_name if repo.fork else _('Nothing') |
|
454 | fork = repo.fork.repo_name if repo.fork else _('Nothing') | |
456 | meta.Session().commit() |
|
455 | meta.Session().commit() | |
457 |
|
|
456 | webutils.flash(_('Marked repository %s as fork of %s') % (repo_name, fork), | |
458 | category='success') |
|
457 | category='success') | |
459 | except RepositoryError as e: |
|
458 | except RepositoryError as e: | |
460 | log.error(traceback.format_exc()) |
|
459 | log.error(traceback.format_exc()) | |
461 |
|
|
460 | webutils.flash(e, category='error') | |
462 | except Exception as e: |
|
461 | except Exception as e: | |
463 | log.error(traceback.format_exc()) |
|
462 | log.error(traceback.format_exc()) | |
464 |
|
|
463 | webutils.flash(_('An error occurred during this operation'), | |
465 | category='error') |
|
464 | category='error') | |
466 |
|
465 | |||
467 | raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) |
|
466 | raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) | |
@@ -473,10 +472,10 b' class ReposController(BaseRepoController' | |||||
473 | if request.POST: |
|
472 | if request.POST: | |
474 | try: |
|
473 | try: | |
475 | ScmModel().pull_changes(repo_name, request.authuser.username, request.ip_addr) |
|
474 | ScmModel().pull_changes(repo_name, request.authuser.username, request.ip_addr) | |
476 |
|
|
475 | webutils.flash(_('Pulled from remote location'), category='success') | |
477 | except Exception as e: |
|
476 | except Exception as e: | |
478 | log.error(traceback.format_exc()) |
|
477 | log.error(traceback.format_exc()) | |
479 |
|
|
478 | webutils.flash(_('An error occurred during pull from remote location'), | |
480 | category='error') |
|
479 | category='error') | |
481 | raise HTTPFound(location=url('edit_repo_remote', repo_name=c.repo_name)) |
|
480 | raise HTTPFound(location=url('edit_repo_remote', repo_name=c.repo_name)) | |
482 | return render('admin/repos/repo_edit.html') |
|
481 | return render('admin/repos/repo_edit.html') | |
@@ -507,7 +506,7 b' class ReposController(BaseRepoController' | |||||
507 | meta.Session().commit() |
|
506 | meta.Session().commit() | |
508 | except Exception as e: |
|
507 | except Exception as e: | |
509 | log.error(traceback.format_exc()) |
|
508 | log.error(traceback.format_exc()) | |
510 |
|
|
509 | webutils.flash(_('An error occurred during deletion of repository stats'), | |
511 | category='error') |
|
510 | category='error') | |
512 | raise HTTPFound(location=url('edit_repo_statistics', repo_name=c.repo_name)) |
|
511 | raise HTTPFound(location=url('edit_repo_statistics', repo_name=c.repo_name)) | |
513 |
|
512 |
@@ -35,7 +35,6 b' from tg import tmpl_context as c' | |||||
35 | from tg.i18n import ugettext as _ |
|
35 | from tg.i18n import ugettext as _ | |
36 | from webob.exc import HTTPFound |
|
36 | from webob.exc import HTTPFound | |
37 |
|
37 | |||
38 | from kallithea.lib import helpers as h |
|
|||
39 | from kallithea.lib import webutils |
|
38 | from kallithea.lib import webutils | |
40 | from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired |
|
39 | from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired | |
41 | from kallithea.lib.base import BaseController, render |
|
40 | from kallithea.lib.base import BaseController, render | |
@@ -114,11 +113,11 b' class SettingsController(BaseController)' | |||||
114 |
|
113 | |||
115 | meta.Session().commit() |
|
114 | meta.Session().commit() | |
116 |
|
115 | |||
117 |
|
|
116 | webutils.flash(_('Updated VCS settings'), category='success') | |
118 |
|
117 | |||
119 | except Exception: |
|
118 | except Exception: | |
120 | log.error(traceback.format_exc()) |
|
119 | log.error(traceback.format_exc()) | |
121 |
|
|
120 | webutils.flash(_('Error occurred while updating ' | |
122 | 'application settings'), category='error') |
|
121 | 'application settings'), category='error') | |
123 |
|
122 | |||
124 | defaults = db.Setting.get_app_settings() |
|
123 | defaults = db.Setting.get_app_settings() | |
@@ -147,13 +146,13 b' class SettingsController(BaseController)' | |||||
147 | install_git_hooks=install_git_hooks, |
|
146 | install_git_hooks=install_git_hooks, | |
148 | user=request.authuser.username, |
|
147 | user=request.authuser.username, | |
149 | overwrite_git_hooks=overwrite_git_hooks) |
|
148 | overwrite_git_hooks=overwrite_git_hooks) | |
150 |
added_msg = |
|
149 | added_msg = webutils.HTML(', ').join( | |
151 |
|
|
150 | webutils.link_to(safe_str(repo_name), webutils.url('summary_home', repo_name=repo_name)) for repo_name in added | |
152 | ) or '-' |
|
151 | ) or '-' | |
153 |
removed_msg = |
|
152 | removed_msg = webutils.HTML(', ').join( | |
154 | safe_str(repo_name) for repo_name in removed |
|
153 | safe_str(repo_name) for repo_name in removed | |
155 | ) or '-' |
|
154 | ) or '-' | |
156 |
|
|
155 | webutils.flash(webutils.HTML(_('Repositories successfully rescanned. Added: %s. Removed: %s.')) % | |
157 | (added_msg, removed_msg), category='success') |
|
156 | (added_msg, removed_msg), category='success') | |
158 |
|
157 | |||
159 | if invalidate_cache: |
|
158 | if invalidate_cache: | |
@@ -165,7 +164,7 b' class SettingsController(BaseController)' | |||||
165 | i += 1 |
|
164 | i += 1 | |
166 | except VCSError as e: |
|
165 | except VCSError as e: | |
167 | log.warning('VCS error invalidating %s: %s', repo.repo_name, e) |
|
166 | log.warning('VCS error invalidating %s: %s', repo.repo_name, e) | |
168 |
|
|
167 | webutils.flash(_('Invalidated %s repositories') % i, category='success') | |
169 |
|
168 | |||
170 | raise HTTPFound(location=url('admin_settings_mapping')) |
|
169 | raise HTTPFound(location=url('admin_settings_mapping')) | |
171 |
|
170 | |||
@@ -206,11 +205,11 b' class SettingsController(BaseController)' | |||||
206 |
|
205 | |||
207 | meta.Session().commit() |
|
206 | meta.Session().commit() | |
208 | set_app_settings(config) |
|
207 | set_app_settings(config) | |
209 |
|
|
208 | webutils.flash(_('Updated application settings'), category='success') | |
210 |
|
209 | |||
211 | except Exception: |
|
210 | except Exception: | |
212 | log.error(traceback.format_exc()) |
|
211 | log.error(traceback.format_exc()) | |
213 |
|
|
212 | webutils.flash(_('Error occurred while updating ' | |
214 | 'application settings'), |
|
213 | 'application settings'), | |
215 | category='error') |
|
214 | category='error') | |
216 |
|
215 | |||
@@ -260,12 +259,12 b' class SettingsController(BaseController)' | |||||
260 |
|
259 | |||
261 | meta.Session().commit() |
|
260 | meta.Session().commit() | |
262 | set_app_settings(config) |
|
261 | set_app_settings(config) | |
263 |
|
|
262 | webutils.flash(_('Updated visualisation settings'), | |
264 | category='success') |
|
263 | category='success') | |
265 |
|
264 | |||
266 | except Exception: |
|
265 | except Exception: | |
267 | log.error(traceback.format_exc()) |
|
266 | log.error(traceback.format_exc()) | |
268 |
|
|
267 | webutils.flash(_('Error occurred during updating ' | |
269 | 'visualisation settings'), |
|
268 | 'visualisation settings'), | |
270 | category='error') |
|
269 | category='error') | |
271 |
|
270 | |||
@@ -289,7 +288,7 b' class SettingsController(BaseController)' | |||||
289 | test_body = ('Kallithea Email test, ' |
|
288 | test_body = ('Kallithea Email test, ' | |
290 | 'Kallithea version: %s' % c.kallithea_version) |
|
289 | 'Kallithea version: %s' % c.kallithea_version) | |
291 | if not test_email: |
|
290 | if not test_email: | |
292 |
|
|
291 | webutils.flash(_('Please enter email address'), category='error') | |
293 | raise HTTPFound(location=url('admin_settings_email')) |
|
292 | raise HTTPFound(location=url('admin_settings_email')) | |
294 |
|
293 | |||
295 | test_email_txt_body = EmailNotificationModel() \ |
|
294 | test_email_txt_body = EmailNotificationModel() \ | |
@@ -304,7 +303,7 b' class SettingsController(BaseController)' | |||||
304 | tasks.send_email(recipients, test_email_subj, |
|
303 | tasks.send_email(recipients, test_email_subj, | |
305 | test_email_txt_body, test_email_html_body) |
|
304 | test_email_txt_body, test_email_html_body) | |
306 |
|
305 | |||
307 |
|
|
306 | webutils.flash(_('Send email task created'), category='success') | |
308 | raise HTTPFound(location=url('admin_settings_email')) |
|
307 | raise HTTPFound(location=url('admin_settings_email')) | |
309 |
|
308 | |||
310 | defaults = db.Setting.get_app_settings() |
|
309 | defaults = db.Setting.get_app_settings() | |
@@ -332,12 +331,12 b' class SettingsController(BaseController)' | |||||
332 | try: |
|
331 | try: | |
333 | ui_key = ui_key and ui_key.strip() |
|
332 | ui_key = ui_key and ui_key.strip() | |
334 | if ui_key in (x.ui_key for x in db.Ui.get_custom_hooks()): |
|
333 | if ui_key in (x.ui_key for x in db.Ui.get_custom_hooks()): | |
335 |
|
|
334 | webutils.flash(_('Hook already exists'), category='error') | |
336 | elif ui_key in (x.ui_key for x in db.Ui.get_builtin_hooks()): |
|
335 | elif ui_key in (x.ui_key for x in db.Ui.get_builtin_hooks()): | |
337 |
|
|
336 | webutils.flash(_('Builtin hooks are read-only. Please use another hook name.'), category='error') | |
338 | elif ui_value and ui_key: |
|
337 | elif ui_value and ui_key: | |
339 | db.Ui.create_or_update_hook(ui_key, ui_value) |
|
338 | db.Ui.create_or_update_hook(ui_key, ui_value) | |
340 |
|
|
339 | webutils.flash(_('Added new hook'), category='success') | |
341 | elif hook_id: |
|
340 | elif hook_id: | |
342 | db.Ui.delete(hook_id) |
|
341 | db.Ui.delete(hook_id) | |
343 | meta.Session().commit() |
|
342 | meta.Session().commit() | |
@@ -353,11 +352,11 b' class SettingsController(BaseController)' | |||||
353 | update = True |
|
352 | update = True | |
354 |
|
353 | |||
355 | if update: |
|
354 | if update: | |
356 |
|
|
355 | webutils.flash(_('Updated hooks'), category='success') | |
357 | meta.Session().commit() |
|
356 | meta.Session().commit() | |
358 | except Exception: |
|
357 | except Exception: | |
359 | log.error(traceback.format_exc()) |
|
358 | log.error(traceback.format_exc()) | |
360 |
|
|
359 | webutils.flash(_('Error occurred during hook creation'), | |
361 | category='error') |
|
360 | category='error') | |
362 |
|
361 | |||
363 | raise HTTPFound(location=url('admin_settings_hooks')) |
|
362 | raise HTTPFound(location=url('admin_settings_hooks')) | |
@@ -381,7 +380,7 b' class SettingsController(BaseController)' | |||||
381 | repo_location = self._get_hg_ui_settings()['paths_root_path'] |
|
380 | repo_location = self._get_hg_ui_settings()['paths_root_path'] | |
382 | full_index = request.POST.get('full_index', False) |
|
381 | full_index = request.POST.get('full_index', False) | |
383 | tasks.whoosh_index(repo_location, full_index) |
|
382 | tasks.whoosh_index(repo_location, full_index) | |
384 |
|
|
383 | webutils.flash(_('Whoosh reindex task scheduled'), category='success') | |
385 | raise HTTPFound(location=url('admin_settings_search')) |
|
384 | raise HTTPFound(location=url('admin_settings_search')) | |
386 |
|
385 | |||
387 | defaults = db.Setting.get_app_settings() |
|
386 | defaults = db.Setting.get_app_settings() |
@@ -38,6 +38,7 b' from tg.i18n import ugettext as _' | |||||
38 | from webob.exc import HTTPFound, HTTPInternalServerError |
|
38 | from webob.exc import HTTPFound, HTTPInternalServerError | |
39 |
|
39 | |||
40 | from kallithea.lib import helpers as h |
|
40 | from kallithea.lib import helpers as h | |
|
41 | from kallithea.lib import webutils | |||
41 | from kallithea.lib.auth import HasPermissionAnyDecorator, HasUserGroupPermissionLevelDecorator, LoginRequired |
|
42 | from kallithea.lib.auth import HasPermissionAnyDecorator, HasUserGroupPermissionLevelDecorator, LoginRequired | |
42 | from kallithea.lib.base import BaseController, render |
|
43 | from kallithea.lib.base import BaseController, render | |
43 | from kallithea.lib.exceptions import RepoGroupAssignmentError, UserGroupsAssignedException |
|
44 | from kallithea.lib.exceptions import RepoGroupAssignmentError, UserGroupsAssignedException | |
@@ -100,7 +101,7 b' class UserGroupsController(BaseControlle' | |||||
100 | "raw_name": user_gr.users_group_name, |
|
101 | "raw_name": user_gr.users_group_name, | |
101 | "group_name": user_group_name(user_gr.users_group_id, |
|
102 | "group_name": user_group_name(user_gr.users_group_id, | |
102 | user_gr.users_group_name), |
|
103 | user_gr.users_group_name), | |
103 |
"desc": |
|
104 | "desc": webutils.escape(user_gr.user_group_description), | |
104 | "members": len(user_gr.members), |
|
105 | "members": len(user_gr.members), | |
105 | "active": h.boolicon(user_gr.users_group_active), |
|
106 | "active": h.boolicon(user_gr.users_group_active), | |
106 | "owner": h.person(user_gr.owner.username), |
|
107 | "owner": h.person(user_gr.owner.username), | |
@@ -129,7 +130,7 b' class UserGroupsController(BaseControlle' | |||||
129 | action_logger(request.authuser, |
|
130 | action_logger(request.authuser, | |
130 | 'admin_created_users_group:%s' % gr, |
|
131 | 'admin_created_users_group:%s' % gr, | |
131 | None, request.ip_addr) |
|
132 | None, request.ip_addr) | |
132 |
|
|
133 | webutils.flash(webutils.HTML(_('Created user group %s')) % webutils.link_to(gr, url('edit_users_group', id=ug.users_group_id)), | |
133 | category='success') |
|
134 | category='success') | |
134 | meta.Session().commit() |
|
135 | meta.Session().commit() | |
135 | except formencode.Invalid as errors: |
|
136 | except formencode.Invalid as errors: | |
@@ -142,7 +143,7 b' class UserGroupsController(BaseControlle' | |||||
142 | force_defaults=False) |
|
143 | force_defaults=False) | |
143 | except Exception: |
|
144 | except Exception: | |
144 | log.error(traceback.format_exc()) |
|
145 | log.error(traceback.format_exc()) | |
145 |
|
|
146 | webutils.flash(_('Error occurred during creation of user group %s') | |
146 | % request.POST.get('users_group_name'), category='error') |
|
147 | % request.POST.get('users_group_name'), category='error') | |
147 |
|
148 | |||
148 | raise HTTPFound(location=url('users_groups')) |
|
149 | raise HTTPFound(location=url('users_groups')) | |
@@ -170,7 +171,7 b' class UserGroupsController(BaseControlle' | |||||
170 | action_logger(request.authuser, |
|
171 | action_logger(request.authuser, | |
171 | 'admin_updated_users_group:%s' % gr, |
|
172 | 'admin_updated_users_group:%s' % gr, | |
172 | None, request.ip_addr) |
|
173 | None, request.ip_addr) | |
173 |
|
|
174 | webutils.flash(_('Updated user group %s') % gr, category='success') | |
174 | meta.Session().commit() |
|
175 | meta.Session().commit() | |
175 | except formencode.Invalid as errors: |
|
176 | except formencode.Invalid as errors: | |
176 | ug_model = UserGroupModel() |
|
177 | ug_model = UserGroupModel() | |
@@ -192,7 +193,7 b' class UserGroupsController(BaseControlle' | |||||
192 | force_defaults=False) |
|
193 | force_defaults=False) | |
193 | except Exception: |
|
194 | except Exception: | |
194 | log.error(traceback.format_exc()) |
|
195 | log.error(traceback.format_exc()) | |
195 |
|
|
196 | webutils.flash(_('Error occurred during update of user group %s') | |
196 | % request.POST.get('users_group_name'), category='error') |
|
197 | % request.POST.get('users_group_name'), category='error') | |
197 |
|
198 | |||
198 | raise HTTPFound(location=url('edit_users_group', id=id)) |
|
199 | raise HTTPFound(location=url('edit_users_group', id=id)) | |
@@ -203,12 +204,12 b' class UserGroupsController(BaseControlle' | |||||
203 | try: |
|
204 | try: | |
204 | UserGroupModel().delete(usr_gr) |
|
205 | UserGroupModel().delete(usr_gr) | |
205 | meta.Session().commit() |
|
206 | meta.Session().commit() | |
206 |
|
|
207 | webutils.flash(_('Successfully deleted user group'), category='success') | |
207 | except UserGroupsAssignedException as e: |
|
208 | except UserGroupsAssignedException as e: | |
208 |
|
|
209 | webutils.flash(e, category='error') | |
209 | except Exception: |
|
210 | except Exception: | |
210 | log.error(traceback.format_exc()) |
|
211 | log.error(traceback.format_exc()) | |
211 |
|
|
212 | webutils.flash(_('An error occurred during deletion of user group'), | |
212 | category='error') |
|
213 | category='error') | |
213 | raise HTTPFound(location=url('users_groups')) |
|
214 | raise HTTPFound(location=url('users_groups')) | |
214 |
|
215 | |||
@@ -264,13 +265,13 b' class UserGroupsController(BaseControlle' | |||||
264 | UserGroupModel()._update_permissions(user_group, form['perms_new'], |
|
265 | UserGroupModel()._update_permissions(user_group, form['perms_new'], | |
265 | form['perms_updates']) |
|
266 | form['perms_updates']) | |
266 | except RepoGroupAssignmentError: |
|
267 | except RepoGroupAssignmentError: | |
267 |
|
|
268 | webutils.flash(_('Target group cannot be the same'), category='error') | |
268 | raise HTTPFound(location=url('edit_user_group_perms', id=id)) |
|
269 | raise HTTPFound(location=url('edit_user_group_perms', id=id)) | |
269 | # TODO: implement this |
|
270 | # TODO: implement this | |
270 | #action_logger(request.authuser, 'admin_changed_repo_permissions', |
|
271 | #action_logger(request.authuser, 'admin_changed_repo_permissions', | |
271 | # repo_name, request.ip_addr) |
|
272 | # repo_name, request.ip_addr) | |
272 | meta.Session().commit() |
|
273 | meta.Session().commit() | |
273 |
|
|
274 | webutils.flash(_('User group permissions updated'), category='success') | |
274 | raise HTTPFound(location=url('edit_user_group_perms', id=id)) |
|
275 | raise HTTPFound(location=url('edit_user_group_perms', id=id)) | |
275 |
|
276 | |||
276 | @HasUserGroupPermissionLevelDecorator('admin') |
|
277 | @HasUserGroupPermissionLevelDecorator('admin') | |
@@ -286,7 +287,7 b' class UserGroupsController(BaseControlle' | |||||
286 | if not request.authuser.is_admin: |
|
287 | if not request.authuser.is_admin: | |
287 | if obj_type == 'user' and request.authuser.user_id == obj_id: |
|
288 | if obj_type == 'user' and request.authuser.user_id == obj_id: | |
288 | msg = _('Cannot revoke permission for yourself as admin') |
|
289 | msg = _('Cannot revoke permission for yourself as admin') | |
289 |
|
|
290 | webutils.flash(msg, category='warning') | |
290 | raise Exception('revoke admin permission on self') |
|
291 | raise Exception('revoke admin permission on self') | |
291 | if obj_type == 'user': |
|
292 | if obj_type == 'user': | |
292 | UserGroupModel().revoke_user_permission(user_group=id, |
|
293 | UserGroupModel().revoke_user_permission(user_group=id, | |
@@ -297,7 +298,7 b' class UserGroupsController(BaseControlle' | |||||
297 | meta.Session().commit() |
|
298 | meta.Session().commit() | |
298 | except Exception: |
|
299 | except Exception: | |
299 | log.error(traceback.format_exc()) |
|
300 | log.error(traceback.format_exc()) | |
300 |
|
|
301 | webutils.flash(_('An error occurred during revoking of permission'), | |
301 | category='error') |
|
302 | category='error') | |
302 | raise HTTPInternalServerError() |
|
303 | raise HTTPInternalServerError() | |
303 |
|
304 | |||
@@ -379,11 +380,11 b' class UserGroupsController(BaseControlle' | |||||
379 | else: |
|
380 | else: | |
380 | usergroup_model.grant_perm(id, 'hg.fork.none') |
|
381 | usergroup_model.grant_perm(id, 'hg.fork.none') | |
381 |
|
382 | |||
382 |
|
|
383 | webutils.flash(_("Updated permissions"), category='success') | |
383 | meta.Session().commit() |
|
384 | meta.Session().commit() | |
384 | except Exception: |
|
385 | except Exception: | |
385 | log.error(traceback.format_exc()) |
|
386 | log.error(traceback.format_exc()) | |
386 |
|
|
387 | webutils.flash(_('An error occurred during permissions saving'), | |
387 | category='error') |
|
388 | category='error') | |
388 |
|
389 | |||
389 | raise HTTPFound(location=url('edit_user_group_default_perms', id=id)) |
|
390 | raise HTTPFound(location=url('edit_user_group_default_perms', id=id)) |
@@ -39,6 +39,7 b' from webob.exc import HTTPFound, HTTPNot' | |||||
39 | import kallithea |
|
39 | import kallithea | |
40 | from kallithea.lib import auth_modules |
|
40 | from kallithea.lib import auth_modules | |
41 | from kallithea.lib import helpers as h |
|
41 | from kallithea.lib import helpers as h | |
|
42 | from kallithea.lib import webutils | |||
42 | from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired |
|
43 | from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired | |
43 | from kallithea.lib.base import BaseController, IfSshEnabled, render |
|
44 | from kallithea.lib.base import BaseController, IfSshEnabled, render | |
44 | from kallithea.lib.exceptions import DefaultUserException, UserCreationError, UserOwnsReposException |
|
45 | from kallithea.lib.exceptions import DefaultUserException, UserCreationError, UserOwnsReposException | |
@@ -87,8 +88,8 b' class UsersController(BaseController):' | |||||
87 | "gravatar": grav_tmpl % h.gravatar(user.email, size=20), |
|
88 | "gravatar": grav_tmpl % h.gravatar(user.email, size=20), | |
88 | "raw_name": user.username, |
|
89 | "raw_name": user.username, | |
89 | "username": username(user.user_id, user.username), |
|
90 | "username": username(user.user_id, user.username), | |
90 |
"firstname": |
|
91 | "firstname": webutils.escape(user.name), | |
91 |
"lastname": |
|
92 | "lastname": webutils.escape(user.lastname), | |
92 | "last_login": h.fmt_date(user.last_login), |
|
93 | "last_login": h.fmt_date(user.last_login), | |
93 | "last_login_raw": datetime_to_time(user.last_login), |
|
94 | "last_login_raw": datetime_to_time(user.last_login), | |
94 | "active": h.boolicon(user.active), |
|
95 | "active": h.boolicon(user.active), | |
@@ -116,7 +117,7 b' class UsersController(BaseController):' | |||||
116 | user = user_model.create(form_result) |
|
117 | user = user_model.create(form_result) | |
117 | action_logger(request.authuser, 'admin_created_user:%s' % user.username, |
|
118 | action_logger(request.authuser, 'admin_created_user:%s' % user.username, | |
118 | None, request.ip_addr) |
|
119 | None, request.ip_addr) | |
119 |
|
|
120 | webutils.flash(_('Created user %s') % user.username, | |
120 | category='success') |
|
121 | category='success') | |
121 | meta.Session().commit() |
|
122 | meta.Session().commit() | |
122 | except formencode.Invalid as errors: |
|
123 | except formencode.Invalid as errors: | |
@@ -128,10 +129,10 b' class UsersController(BaseController):' | |||||
128 | encoding="UTF-8", |
|
129 | encoding="UTF-8", | |
129 | force_defaults=False) |
|
130 | force_defaults=False) | |
130 | except UserCreationError as e: |
|
131 | except UserCreationError as e: | |
131 |
|
|
132 | webutils.flash(e, 'error') | |
132 | except Exception: |
|
133 | except Exception: | |
133 | log.error(traceback.format_exc()) |
|
134 | log.error(traceback.format_exc()) | |
134 |
|
|
135 | webutils.flash(_('Error occurred during creation of user %s') | |
135 | % request.POST.get('username'), category='error') |
|
136 | % request.POST.get('username'), category='error') | |
136 | raise HTTPFound(location=url('edit_user', id=user.user_id)) |
|
137 | raise HTTPFound(location=url('edit_user', id=user.user_id)) | |
137 |
|
138 | |||
@@ -155,7 +156,7 b' class UsersController(BaseController):' | |||||
155 | usr = form_result['username'] |
|
156 | usr = form_result['username'] | |
156 | action_logger(request.authuser, 'admin_updated_user:%s' % usr, |
|
157 | action_logger(request.authuser, 'admin_updated_user:%s' % usr, | |
157 | None, request.ip_addr) |
|
158 | None, request.ip_addr) | |
158 |
|
|
159 | webutils.flash(_('User updated successfully'), category='success') | |
159 | meta.Session().commit() |
|
160 | meta.Session().commit() | |
160 | except formencode.Invalid as errors: |
|
161 | except formencode.Invalid as errors: | |
161 | defaults = errors.value |
|
162 | defaults = errors.value | |
@@ -174,7 +175,7 b' class UsersController(BaseController):' | |||||
174 | force_defaults=False) |
|
175 | force_defaults=False) | |
175 | except Exception: |
|
176 | except Exception: | |
176 | log.error(traceback.format_exc()) |
|
177 | log.error(traceback.format_exc()) | |
177 |
|
|
178 | webutils.flash(_('Error occurred during update of user %s') | |
178 | % form_result.get('username'), category='error') |
|
179 | % form_result.get('username'), category='error') | |
179 | raise HTTPFound(location=url('edit_user', id=id)) |
|
180 | raise HTTPFound(location=url('edit_user', id=id)) | |
180 |
|
181 | |||
@@ -184,12 +185,12 b' class UsersController(BaseController):' | |||||
184 | try: |
|
185 | try: | |
185 | UserModel().delete(usr) |
|
186 | UserModel().delete(usr) | |
186 | meta.Session().commit() |
|
187 | meta.Session().commit() | |
187 |
|
|
188 | webutils.flash(_('Successfully deleted user'), category='success') | |
188 | except (UserOwnsReposException, DefaultUserException) as e: |
|
189 | except (UserOwnsReposException, DefaultUserException) as e: | |
189 |
|
|
190 | webutils.flash(e, category='warning') | |
190 | except Exception: |
|
191 | except Exception: | |
191 | log.error(traceback.format_exc()) |
|
192 | log.error(traceback.format_exc()) | |
192 |
|
|
193 | webutils.flash(_('An error occurred during deletion of user'), | |
193 | category='error') |
|
194 | category='error') | |
194 | else: |
|
195 | else: | |
195 | if has_ssh_keys: |
|
196 | if has_ssh_keys: | |
@@ -200,7 +201,7 b' class UsersController(BaseController):' | |||||
200 | try: |
|
201 | try: | |
201 | return db.User.get_or_404(id, allow_default=False) |
|
202 | return db.User.get_or_404(id, allow_default=False) | |
202 | except DefaultUserException: |
|
203 | except DefaultUserException: | |
203 |
|
|
204 | webutils.flash(_("The default user cannot be edited"), category='warning') | |
204 | raise HTTPNotFound |
|
205 | raise HTTPNotFound | |
205 |
|
206 | |||
206 | def _render_edit_profile(self, user): |
|
207 | def _render_edit_profile(self, user): | |
@@ -268,7 +269,7 b' class UsersController(BaseController):' | |||||
268 | description = request.POST.get('description') |
|
269 | description = request.POST.get('description') | |
269 | ApiKeyModel().create(c.user.user_id, description, lifetime) |
|
270 | ApiKeyModel().create(c.user.user_id, description, lifetime) | |
270 | meta.Session().commit() |
|
271 | meta.Session().commit() | |
271 |
|
|
272 | webutils.flash(_("API key successfully created"), category='success') | |
272 | raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id)) |
|
273 | raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id)) | |
273 |
|
274 | |||
274 | def delete_api_key(self, id): |
|
275 | def delete_api_key(self, id): | |
@@ -278,11 +279,11 b' class UsersController(BaseController):' | |||||
278 | if request.POST.get('del_api_key_builtin'): |
|
279 | if request.POST.get('del_api_key_builtin'): | |
279 | c.user.api_key = generate_api_key() |
|
280 | c.user.api_key = generate_api_key() | |
280 | meta.Session().commit() |
|
281 | meta.Session().commit() | |
281 |
|
|
282 | webutils.flash(_("API key successfully reset"), category='success') | |
282 | elif api_key: |
|
283 | elif api_key: | |
283 | ApiKeyModel().delete(api_key, c.user.user_id) |
|
284 | ApiKeyModel().delete(api_key, c.user.user_id) | |
284 | meta.Session().commit() |
|
285 | meta.Session().commit() | |
285 |
|
|
286 | webutils.flash(_("API key successfully deleted"), category='success') | |
286 |
|
287 | |||
287 | raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id)) |
|
288 | raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id)) | |
288 |
|
289 | |||
@@ -335,11 +336,11 b' class UsersController(BaseController):' | |||||
335 | user_model.grant_perm(id, 'hg.fork.repository') |
|
336 | user_model.grant_perm(id, 'hg.fork.repository') | |
336 | else: |
|
337 | else: | |
337 | user_model.grant_perm(id, 'hg.fork.none') |
|
338 | user_model.grant_perm(id, 'hg.fork.none') | |
338 |
|
|
339 | webutils.flash(_("Updated permissions"), category='success') | |
339 | meta.Session().commit() |
|
340 | meta.Session().commit() | |
340 | except Exception: |
|
341 | except Exception: | |
341 | log.error(traceback.format_exc()) |
|
342 | log.error(traceback.format_exc()) | |
342 |
|
|
343 | webutils.flash(_('An error occurred during permissions saving'), | |
343 | category='error') |
|
344 | category='error') | |
344 | raise HTTPFound(location=url('edit_user_perms', id=id)) |
|
345 | raise HTTPFound(location=url('edit_user_perms', id=id)) | |
345 |
|
346 | |||
@@ -364,13 +365,13 b' class UsersController(BaseController):' | |||||
364 | try: |
|
365 | try: | |
365 | user_model.add_extra_email(id, email) |
|
366 | user_model.add_extra_email(id, email) | |
366 | meta.Session().commit() |
|
367 | meta.Session().commit() | |
367 |
|
|
368 | webutils.flash(_("Added email %s to user") % email, category='success') | |
368 | except formencode.Invalid as error: |
|
369 | except formencode.Invalid as error: | |
369 | msg = error.error_dict['email'] |
|
370 | msg = error.error_dict['email'] | |
370 |
|
|
371 | webutils.flash(msg, category='error') | |
371 | except Exception: |
|
372 | except Exception: | |
372 | log.error(traceback.format_exc()) |
|
373 | log.error(traceback.format_exc()) | |
373 |
|
|
374 | webutils.flash(_('An error occurred during email saving'), | |
374 | category='error') |
|
375 | category='error') | |
375 | raise HTTPFound(location=url('edit_user_emails', id=id)) |
|
376 | raise HTTPFound(location=url('edit_user_emails', id=id)) | |
376 |
|
377 | |||
@@ -380,7 +381,7 b' class UsersController(BaseController):' | |||||
380 | user_model = UserModel() |
|
381 | user_model = UserModel() | |
381 | user_model.delete_extra_email(id, email_id) |
|
382 | user_model.delete_extra_email(id, email_id) | |
382 | meta.Session().commit() |
|
383 | meta.Session().commit() | |
383 |
|
|
384 | webutils.flash(_("Removed email from user"), category='success') | |
384 | raise HTTPFound(location=url('edit_user_emails', id=id)) |
|
385 | raise HTTPFound(location=url('edit_user_emails', id=id)) | |
385 |
|
386 | |||
386 | def edit_ips(self, id): |
|
387 | def edit_ips(self, id): | |
@@ -406,13 +407,13 b' class UsersController(BaseController):' | |||||
406 | try: |
|
407 | try: | |
407 | user_model.add_extra_ip(id, ip) |
|
408 | user_model.add_extra_ip(id, ip) | |
408 | meta.Session().commit() |
|
409 | meta.Session().commit() | |
409 |
|
|
410 | webutils.flash(_("Added IP address %s to user whitelist") % ip, category='success') | |
410 | except formencode.Invalid as error: |
|
411 | except formencode.Invalid as error: | |
411 | msg = error.error_dict['ip'] |
|
412 | msg = error.error_dict['ip'] | |
412 |
|
|
413 | webutils.flash(msg, category='error') | |
413 | except Exception: |
|
414 | except Exception: | |
414 | log.error(traceback.format_exc()) |
|
415 | log.error(traceback.format_exc()) | |
415 |
|
|
416 | webutils.flash(_('An error occurred while adding IP address'), | |
416 | category='error') |
|
417 | category='error') | |
417 |
|
418 | |||
418 | if 'default_user' in request.POST: |
|
419 | if 'default_user' in request.POST: | |
@@ -424,7 +425,7 b' class UsersController(BaseController):' | |||||
424 | user_model = UserModel() |
|
425 | user_model = UserModel() | |
425 | user_model.delete_extra_ip(id, ip_id) |
|
426 | user_model.delete_extra_ip(id, ip_id) | |
426 | meta.Session().commit() |
|
427 | meta.Session().commit() | |
427 |
|
|
428 | webutils.flash(_("Removed IP address from user whitelist"), category='success') | |
428 |
|
429 | |||
429 | if 'default_user' in request.POST: |
|
430 | if 'default_user' in request.POST: | |
430 | raise HTTPFound(location=url('admin_permissions_ips')) |
|
431 | raise HTTPFound(location=url('admin_permissions_ips')) | |
@@ -453,9 +454,9 b' class UsersController(BaseController):' | |||||
453 | description, public_key) |
|
454 | description, public_key) | |
454 | meta.Session().commit() |
|
455 | meta.Session().commit() | |
455 | SshKeyModel().write_authorized_keys() |
|
456 | SshKeyModel().write_authorized_keys() | |
456 |
|
|
457 | webutils.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success') | |
457 | except SshKeyModelException as e: |
|
458 | except SshKeyModelException as e: | |
458 |
|
|
459 | webutils.flash(e.args[0], category='error') | |
459 | raise HTTPFound(location=url('edit_user_ssh_keys', id=c.user.user_id)) |
|
460 | raise HTTPFound(location=url('edit_user_ssh_keys', id=c.user.user_id)) | |
460 |
|
461 | |||
461 | @IfSshEnabled |
|
462 | @IfSshEnabled | |
@@ -467,7 +468,7 b' class UsersController(BaseController):' | |||||
467 | SshKeyModel().delete(fingerprint, c.user.user_id) |
|
468 | SshKeyModel().delete(fingerprint, c.user.user_id) | |
468 | meta.Session().commit() |
|
469 | meta.Session().commit() | |
469 | SshKeyModel().write_authorized_keys() |
|
470 | SshKeyModel().write_authorized_keys() | |
470 |
|
|
471 | webutils.flash(_("SSH key successfully deleted"), category='success') | |
471 | except SshKeyModelException as e: |
|
472 | except SshKeyModelException as e: | |
472 |
|
|
473 | webutils.flash(e.args[0], category='error') | |
473 | raise HTTPFound(location=url('edit_user_ssh_keys', id=c.user.user_id)) |
|
474 | raise HTTPFound(location=url('edit_user_ssh_keys', id=c.user.user_id)) |
@@ -33,7 +33,6 b' from tg import tmpl_context as c' | |||||
33 | from tg.i18n import ugettext as _ |
|
33 | from tg.i18n import ugettext as _ | |
34 | from webob.exc import HTTPBadRequest, HTTPFound, HTTPNotFound |
|
34 | from webob.exc import HTTPBadRequest, HTTPFound, HTTPNotFound | |
35 |
|
35 | |||
36 | import kallithea.lib.helpers as h |
|
|||
37 | from kallithea.lib import webutils |
|
36 | from kallithea.lib import webutils | |
38 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired |
|
37 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired | |
39 | from kallithea.lib.base import BaseRepoController, render |
|
38 | from kallithea.lib.base import BaseRepoController, render | |
@@ -65,10 +64,10 b' class ChangelogController(BaseRepoContro' | |||||
65 | try: |
|
64 | try: | |
66 | return c.db_repo_scm_instance.get_changeset(rev) |
|
65 | return c.db_repo_scm_instance.get_changeset(rev) | |
67 | except EmptyRepositoryError as e: |
|
66 | except EmptyRepositoryError as e: | |
68 |
|
|
67 | webutils.flash(_('There are no changesets yet'), category='error') | |
69 | except RepositoryError as e: |
|
68 | except RepositoryError as e: | |
70 | log.error(traceback.format_exc()) |
|
69 | log.error(traceback.format_exc()) | |
71 |
|
|
70 | webutils.flash(e, category='error') | |
72 | raise HTTPBadRequest() |
|
71 | raise HTTPBadRequest() | |
73 |
|
72 | |||
74 | @LoginRequired(allow_default_user=True) |
|
73 | @LoginRequired(allow_default_user=True) | |
@@ -112,7 +111,7 b' class ChangelogController(BaseRepoContro' | |||||
112 | cs = self.__get_cs(revision, repo_name) |
|
111 | cs = self.__get_cs(revision, repo_name) | |
113 | collection = cs.get_file_history(f_path) |
|
112 | collection = cs.get_file_history(f_path) | |
114 | except RepositoryError as e: |
|
113 | except RepositoryError as e: | |
115 |
|
|
114 | webutils.flash(e, category='warning') | |
116 | raise HTTPFound(location=webutils.url('changelog_home', repo_name=repo_name)) |
|
115 | raise HTTPFound(location=webutils.url('changelog_home', repo_name=repo_name)) | |
117 | else: |
|
116 | else: | |
118 | collection = c.db_repo_scm_instance.get_changesets(start=0, end=revision, |
|
117 | collection = c.db_repo_scm_instance.get_changesets(start=0, end=revision, | |
@@ -126,11 +125,11 b' class ChangelogController(BaseRepoContro' | |||||
126 | c.cs_comments = c.db_repo.get_comments(page_revisions) |
|
125 | c.cs_comments = c.db_repo.get_comments(page_revisions) | |
127 | c.cs_statuses = c.db_repo.statuses(page_revisions) |
|
126 | c.cs_statuses = c.db_repo.statuses(page_revisions) | |
128 | except EmptyRepositoryError as e: |
|
127 | except EmptyRepositoryError as e: | |
129 |
|
|
128 | webutils.flash(e, category='warning') | |
130 | raise HTTPFound(location=url('summary_home', repo_name=c.repo_name)) |
|
129 | raise HTTPFound(location=url('summary_home', repo_name=c.repo_name)) | |
131 | except (RepositoryError, ChangesetDoesNotExistError, Exception) as e: |
|
130 | except (RepositoryError, ChangesetDoesNotExistError, Exception) as e: | |
132 | log.error(traceback.format_exc()) |
|
131 | log.error(traceback.format_exc()) | |
133 |
|
|
132 | webutils.flash(e, category='error') | |
134 | raise HTTPFound(location=url('changelog_home', repo_name=c.repo_name)) |
|
133 | raise HTTPFound(location=url('changelog_home', repo_name=c.repo_name)) | |
135 |
|
134 | |||
136 | c.branch_name = branch_name |
|
135 | c.branch_name = branch_name |
@@ -86,7 +86,7 b' def create_cs_pr_comment(repo_name, revi' | |||||
86 |
|
86 | |||
87 | if not allowed_to_change_status: |
|
87 | if not allowed_to_change_status: | |
88 | if status or close_pr: |
|
88 | if status or close_pr: | |
89 |
|
|
89 | webutils.flash(_('No permission to change status'), 'error') | |
90 | raise HTTPForbidden() |
|
90 | raise HTTPForbidden() | |
91 |
|
91 | |||
92 | if pull_request and delete == "delete": |
|
92 | if pull_request and delete == "delete": | |
@@ -97,7 +97,7 b' def create_cs_pr_comment(repo_name, revi' | |||||
97 | ) and not pull_request.is_closed(): |
|
97 | ) and not pull_request.is_closed(): | |
98 | PullRequestModel().delete(pull_request) |
|
98 | PullRequestModel().delete(pull_request) | |
99 | meta.Session().commit() |
|
99 | meta.Session().commit() | |
100 |
|
|
100 | webutils.flash(_('Successfully deleted pull request %s') % pull_request_id, | |
101 | category='success') |
|
101 | category='success') | |
102 | return { |
|
102 | return { | |
103 | 'location': webutils.url('my_pullrequests'), # or repo pr list? |
|
103 | 'location': webutils.url('my_pullrequests'), # or repo pr list? | |
@@ -143,7 +143,7 b' def create_cs_pr_comment(repo_name, revi' | |||||
143 | meta.Session().commit() |
|
143 | meta.Session().commit() | |
144 |
|
144 | |||
145 | data = { |
|
145 | data = { | |
146 |
'target_id': |
|
146 | 'target_id': webutils.safeid(request.POST.get('f_path')), | |
147 | } |
|
147 | } | |
148 | if comment is not None: |
|
148 | if comment is not None: | |
149 | c.comment = comment |
|
149 | c.comment = comment | |
@@ -199,7 +199,7 b' class ChangesetController(BaseRepoContro' | |||||
199 | except (ChangesetDoesNotExistError, EmptyRepositoryError): |
|
199 | except (ChangesetDoesNotExistError, EmptyRepositoryError): | |
200 | log.debug(traceback.format_exc()) |
|
200 | log.debug(traceback.format_exc()) | |
201 | msg = _('Such revision does not exist for this repository') |
|
201 | msg = _('Such revision does not exist for this repository') | |
202 |
|
|
202 | webutils.flash(msg, category='error') | |
203 | raise HTTPNotFound() |
|
203 | raise HTTPNotFound() | |
204 |
|
204 | |||
205 | c.changes = OrderedDict() |
|
205 | c.changes = OrderedDict() |
@@ -63,13 +63,13 b' class CompareController(BaseRepoControll' | |||||
63 | c.cs_repo = db.Repository.get_by_repo_name(other_repo) |
|
63 | c.cs_repo = db.Repository.get_by_repo_name(other_repo) | |
64 | if c.cs_repo is None: |
|
64 | if c.cs_repo is None: | |
65 | msg = _('Could not find other repository %s') % other_repo |
|
65 | msg = _('Could not find other repository %s') % other_repo | |
66 |
|
|
66 | webutils.flash(msg, category='error') | |
67 | raise HTTPFound(location=url('compare_home', repo_name=c.a_repo.repo_name)) |
|
67 | raise HTTPFound(location=url('compare_home', repo_name=c.a_repo.repo_name)) | |
68 |
|
68 | |||
69 | # Verify that it's even possible to compare these two repositories. |
|
69 | # Verify that it's even possible to compare these two repositories. | |
70 | if c.a_repo.scm_instance.alias != c.cs_repo.scm_instance.alias: |
|
70 | if c.a_repo.scm_instance.alias != c.cs_repo.scm_instance.alias: | |
71 | msg = _('Cannot compare repositories of different types') |
|
71 | msg = _('Cannot compare repositories of different types') | |
72 |
|
|
72 | webutils.flash(msg, category='error') | |
73 | raise HTTPFound(location=url('compare_home', repo_name=c.a_repo.repo_name)) |
|
73 | raise HTTPFound(location=url('compare_home', repo_name=c.a_repo.repo_name)) | |
74 |
|
74 | |||
75 | @LoginRequired(allow_default_user=True) |
|
75 | @LoginRequired(allow_default_user=True) | |
@@ -146,7 +146,7 b' class CompareController(BaseRepoControll' | |||||
146 | else: |
|
146 | else: | |
147 | msg = _('Multiple merge ancestors found for merge compare') |
|
147 | msg = _('Multiple merge ancestors found for merge compare') | |
148 | if rev1 is None: |
|
148 | if rev1 is None: | |
149 |
|
|
149 | webutils.flash(msg, category='error') | |
150 | log.error(msg) |
|
150 | log.error(msg) | |
151 | raise HTTPNotFound |
|
151 | raise HTTPNotFound | |
152 |
|
152 | |||
@@ -160,7 +160,7 b' class CompareController(BaseRepoControll' | |||||
160 | if org_repo != other_repo: |
|
160 | if org_repo != other_repo: | |
161 | # TODO: we could do this by using hg unionrepo |
|
161 | # TODO: we could do this by using hg unionrepo | |
162 | log.error('cannot compare across repos %s and %s', org_repo, other_repo) |
|
162 | log.error('cannot compare across repos %s and %s', org_repo, other_repo) | |
163 |
|
|
163 | webutils.flash(_('Cannot compare repositories without using common ancestor'), category='error') | |
164 | raise HTTPBadRequest |
|
164 | raise HTTPBadRequest | |
165 | rev1 = c.a_rev |
|
165 | rev1 = c.a_rev | |
166 |
|
166 |
@@ -83,15 +83,15 b' class FilesController(BaseRepoController' | |||||
83 | url_ = url('files_add_home', |
|
83 | url_ = url('files_add_home', | |
84 | repo_name=c.repo_name, |
|
84 | repo_name=c.repo_name, | |
85 | revision=0, f_path='', anchor='edit') |
|
85 | revision=0, f_path='', anchor='edit') | |
86 |
add_new = |
|
86 | add_new = webutils.link_to(_('Click here to add new file'), url_, class_="alert-link") | |
87 |
|
|
87 | webutils.flash(_('There are no files yet.') + ' ' + add_new, category='warning') | |
88 | raise HTTPNotFound() |
|
88 | raise HTTPNotFound() | |
89 | except (ChangesetDoesNotExistError, LookupError): |
|
89 | except (ChangesetDoesNotExistError, LookupError): | |
90 | msg = _('Such revision does not exist for this repository') |
|
90 | msg = _('Such revision does not exist for this repository') | |
91 |
|
|
91 | webutils.flash(msg, category='error') | |
92 | raise HTTPNotFound() |
|
92 | raise HTTPNotFound() | |
93 | except RepositoryError as e: |
|
93 | except RepositoryError as e: | |
94 |
|
|
94 | webutils.flash(e, category='error') | |
95 | raise HTTPNotFound() |
|
95 | raise HTTPNotFound() | |
96 |
|
96 | |||
97 | def __get_filenode(self, cs, path): |
|
97 | def __get_filenode(self, cs, path): | |
@@ -108,10 +108,10 b' class FilesController(BaseRepoController' | |||||
108 | raise RepositoryError('given path is a directory') |
|
108 | raise RepositoryError('given path is a directory') | |
109 | except ChangesetDoesNotExistError: |
|
109 | except ChangesetDoesNotExistError: | |
110 | msg = _('Such revision does not exist for this repository') |
|
110 | msg = _('Such revision does not exist for this repository') | |
111 |
|
|
111 | webutils.flash(msg, category='error') | |
112 | raise HTTPNotFound() |
|
112 | raise HTTPNotFound() | |
113 | except RepositoryError as e: |
|
113 | except RepositoryError as e: | |
114 |
|
|
114 | webutils.flash(e, category='error') | |
115 | raise HTTPNotFound() |
|
115 | raise HTTPNotFound() | |
116 |
|
116 | |||
117 | return file_node |
|
117 | return file_node | |
@@ -176,7 +176,7 b' class FilesController(BaseRepoController' | |||||
176 | else: |
|
176 | else: | |
177 | c.authors = c.file_history = [] |
|
177 | c.authors = c.file_history = [] | |
178 | except RepositoryError as e: |
|
178 | except RepositoryError as e: | |
179 |
|
|
179 | webutils.flash(e, category='error') | |
180 | raise HTTPNotFound() |
|
180 | raise HTTPNotFound() | |
181 |
|
181 | |||
182 | if request.environ.get('HTTP_X_PARTIAL_XHR'): |
|
182 | if request.environ.get('HTTP_X_PARTIAL_XHR'): | |
@@ -293,7 +293,7 b' class FilesController(BaseRepoController' | |||||
293 | _branches = repo.scm_instance.branches |
|
293 | _branches = repo.scm_instance.branches | |
294 | # check if revision is a branch name or branch hash |
|
294 | # check if revision is a branch name or branch hash | |
295 | if revision not in _branches and revision not in _branches.values(): |
|
295 | if revision not in _branches and revision not in _branches.values(): | |
296 |
|
|
296 | webutils.flash(_('You can only delete files with revision ' | |
297 | 'being a valid branch'), category='warning') |
|
297 | 'being a valid branch'), category='warning') | |
298 | raise HTTPFound(location=webutils.url('files_home', |
|
298 | raise HTTPFound(location=webutils.url('files_home', | |
299 | repo_name=repo_name, revision='tip', |
|
299 | repo_name=repo_name, revision='tip', | |
@@ -328,11 +328,11 b' class FilesController(BaseRepoController' | |||||
328 | author=author, |
|
328 | author=author, | |
329 | ) |
|
329 | ) | |
330 |
|
330 | |||
331 |
|
|
331 | webutils.flash(_('Successfully deleted file %s') % f_path, | |
332 | category='success') |
|
332 | category='success') | |
333 | except Exception: |
|
333 | except Exception: | |
334 | log.error(traceback.format_exc()) |
|
334 | log.error(traceback.format_exc()) | |
335 |
|
|
335 | webutils.flash(_('Error occurred during commit'), category='error') | |
336 | raise HTTPFound(location=url('changeset_home', |
|
336 | raise HTTPFound(location=url('changeset_home', | |
337 | repo_name=c.repo_name, revision='tip')) |
|
337 | repo_name=c.repo_name, revision='tip')) | |
338 |
|
338 | |||
@@ -347,7 +347,7 b' class FilesController(BaseRepoController' | |||||
347 | _branches = repo.scm_instance.branches |
|
347 | _branches = repo.scm_instance.branches | |
348 | # check if revision is a branch name or branch hash |
|
348 | # check if revision is a branch name or branch hash | |
349 | if revision not in _branches and revision not in _branches.values(): |
|
349 | if revision not in _branches and revision not in _branches.values(): | |
350 |
|
|
350 | webutils.flash(_('You can only edit files with revision ' | |
351 | 'being a valid branch'), category='warning') |
|
351 | 'being a valid branch'), category='warning') | |
352 | raise HTTPFound(location=webutils.url('files_home', |
|
352 | raise HTTPFound(location=webutils.url('files_home', | |
353 | repo_name=repo_name, revision='tip', |
|
353 | repo_name=repo_name, revision='tip', | |
@@ -376,7 +376,7 b' class FilesController(BaseRepoController' | |||||
376 | author = request.authuser.full_contact |
|
376 | author = request.authuser.full_contact | |
377 |
|
377 | |||
378 | if content == old_content: |
|
378 | if content == old_content: | |
379 |
|
|
379 | webutils.flash(_('No changes'), category='warning') | |
380 | raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, |
|
380 | raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, | |
381 | revision='tip')) |
|
381 | revision='tip')) | |
382 | try: |
|
382 | try: | |
@@ -386,11 +386,11 b' class FilesController(BaseRepoController' | |||||
386 | ip_addr=request.ip_addr, |
|
386 | ip_addr=request.ip_addr, | |
387 | author=author, message=message, |
|
387 | author=author, message=message, | |
388 | content=content, f_path=f_path) |
|
388 | content=content, f_path=f_path) | |
389 |
|
|
389 | webutils.flash(_('Successfully committed to %s') % f_path, | |
390 | category='success') |
|
390 | category='success') | |
391 | except Exception: |
|
391 | except Exception: | |
392 | log.error(traceback.format_exc()) |
|
392 | log.error(traceback.format_exc()) | |
393 |
|
|
393 | webutils.flash(_('Error occurred during commit'), category='error') | |
394 | raise HTTPFound(location=url('changeset_home', |
|
394 | raise HTTPFound(location=url('changeset_home', | |
395 | repo_name=c.repo_name, revision='tip')) |
|
395 | repo_name=c.repo_name, revision='tip')) | |
396 |
|
396 | |||
@@ -426,11 +426,11 b' class FilesController(BaseRepoController' | |||||
426 | content = content.file |
|
426 | content = content.file | |
427 |
|
427 | |||
428 | if not content: |
|
428 | if not content: | |
429 |
|
|
429 | webutils.flash(_('No content'), category='warning') | |
430 | raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, |
|
430 | raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, | |
431 | revision='tip')) |
|
431 | revision='tip')) | |
432 | if not filename: |
|
432 | if not filename: | |
433 |
|
|
433 | webutils.flash(_('No filename'), category='warning') | |
434 | raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, |
|
434 | raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, | |
435 | revision='tip')) |
|
435 | revision='tip')) | |
436 | # strip all crap out of file, just leave the basename |
|
436 | # strip all crap out of file, just leave the basename | |
@@ -454,18 +454,18 b' class FilesController(BaseRepoController' | |||||
454 | author=author, |
|
454 | author=author, | |
455 | ) |
|
455 | ) | |
456 |
|
456 | |||
457 |
|
|
457 | webutils.flash(_('Successfully committed to %s') % node_path, | |
458 | category='success') |
|
458 | category='success') | |
459 | except NonRelativePathError as e: |
|
459 | except NonRelativePathError as e: | |
460 |
|
|
460 | webutils.flash(_('Location must be relative path and must not ' | |
461 | 'contain .. in path'), category='warning') |
|
461 | 'contain .. in path'), category='warning') | |
462 | raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, |
|
462 | raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, | |
463 | revision='tip')) |
|
463 | revision='tip')) | |
464 | except (NodeError, NodeAlreadyExistsError) as e: |
|
464 | except (NodeError, NodeAlreadyExistsError) as e: | |
465 |
|
|
465 | webutils.flash(_(e), category='error') | |
466 | except Exception: |
|
466 | except Exception: | |
467 | log.error(traceback.format_exc()) |
|
467 | log.error(traceback.format_exc()) | |
468 |
|
|
468 | webutils.flash(_('Error occurred during commit'), category='error') | |
469 | raise HTTPFound(location=url('changeset_home', |
|
469 | raise HTTPFound(location=url('changeset_home', | |
470 | repo_name=c.repo_name, revision='tip')) |
|
470 | repo_name=c.repo_name, revision='tip')) | |
471 |
|
471 | |||
@@ -687,7 +687,7 b' class FilesController(BaseRepoController' | |||||
687 | node2 = FileNode(f_path, '', changeset=c.changeset_2) |
|
687 | node2 = FileNode(f_path, '', changeset=c.changeset_2) | |
688 | except ChangesetDoesNotExistError as e: |
|
688 | except ChangesetDoesNotExistError as e: | |
689 | msg = _('Such revision does not exist for this repository') |
|
689 | msg = _('Such revision does not exist for this repository') | |
690 |
|
|
690 | webutils.flash(msg, category='error') | |
691 | raise HTTPNotFound() |
|
691 | raise HTTPNotFound() | |
692 | c.node1 = node1 |
|
692 | c.node1 = node1 | |
693 | c.node2 = node2 |
|
693 | c.node2 = node2 |
@@ -36,7 +36,6 b' from tg.i18n import ugettext as _' | |||||
36 | from webob.exc import HTTPFound, HTTPNotFound |
|
36 | from webob.exc import HTTPFound, HTTPNotFound | |
37 |
|
37 | |||
38 | import kallithea |
|
38 | import kallithea | |
39 | import kallithea.lib.helpers as h |
|
|||
40 | from kallithea.lib import webutils |
|
39 | from kallithea.lib import webutils | |
41 | from kallithea.lib.auth import HasPermissionAnyDecorator, HasRepoPermissionLevel, HasRepoPermissionLevelDecorator, LoginRequired |
|
40 | from kallithea.lib.auth import HasPermissionAnyDecorator, HasRepoPermissionLevel, HasRepoPermissionLevelDecorator, LoginRequired | |
42 | from kallithea.lib.base import BaseRepoController, render |
|
41 | from kallithea.lib.base import BaseRepoController, render | |
@@ -166,7 +165,7 b' class ForksController(BaseRepoController' | |||||
166 | force_defaults=False) |
|
165 | force_defaults=False) | |
167 | except Exception: |
|
166 | except Exception: | |
168 | log.error(traceback.format_exc()) |
|
167 | log.error(traceback.format_exc()) | |
169 |
|
|
168 | webutils.flash(_('An error occurred during repository forking %s') % | |
170 | repo_name, category='error') |
|
169 | repo_name, category='error') | |
171 |
|
170 | |||
172 | raise HTTPFound(location=webutils.url('repo_creating_home', |
|
171 | raise HTTPFound(location=webutils.url('repo_creating_home', |
@@ -36,7 +36,7 b' from tg import tmpl_context as c' | |||||
36 | from tg.i18n import ugettext as _ |
|
36 | from tg.i18n import ugettext as _ | |
37 | from webob.exc import HTTPBadRequest, HTTPFound |
|
37 | from webob.exc import HTTPBadRequest, HTTPFound | |
38 |
|
38 | |||
39 | import kallithea.lib.helpers as h |
|
39 | from kallithea.lib import webutils | |
40 | from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator |
|
40 | from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator | |
41 | from kallithea.lib.base import BaseController, log_in_user, render |
|
41 | from kallithea.lib.base import BaseController, log_in_user, render | |
42 | from kallithea.lib.exceptions import UserCreationError |
|
42 | from kallithea.lib.exceptions import UserCreationError | |
@@ -99,13 +99,13 b' class LoginController(BaseController):' | |||||
99 | # the fly can throw this exception signaling that there's issue |
|
99 | # the fly can throw this exception signaling that there's issue | |
100 | # with user creation, explanation should be provided in |
|
100 | # with user creation, explanation should be provided in | |
101 | # Exception itself |
|
101 | # Exception itself | |
102 |
|
|
102 | webutils.flash(e, 'error') | |
103 | else: |
|
103 | else: | |
104 | # login_form already validated the password - now set the session cookie accordingly |
|
104 | # login_form already validated the password - now set the session cookie accordingly | |
105 | auth_user = log_in_user(user, c.form_result['remember'], is_external_auth=False, ip_addr=request.ip_addr) |
|
105 | auth_user = log_in_user(user, c.form_result['remember'], is_external_auth=False, ip_addr=request.ip_addr) | |
106 | if auth_user: |
|
106 | if auth_user: | |
107 | raise HTTPFound(location=c.came_from) |
|
107 | raise HTTPFound(location=c.came_from) | |
108 |
|
|
108 | webutils.flash(_('Authentication failed.'), 'error') | |
109 | else: |
|
109 | else: | |
110 | # redirect if already logged in |
|
110 | # redirect if already logged in | |
111 | if not request.authuser.is_anonymous: |
|
111 | if not request.authuser.is_anonymous: | |
@@ -144,7 +144,7 b' class LoginController(BaseController):' | |||||
144 | error_dict=error_dict) |
|
144 | error_dict=error_dict) | |
145 |
|
145 | |||
146 | UserModel().create_registration(form_result) |
|
146 | UserModel().create_registration(form_result) | |
147 |
|
|
147 | webutils.flash(_('You have successfully registered with %s') % (c.site_name or 'Kallithea'), | |
148 | category='success') |
|
148 | category='success') | |
149 | meta.Session().commit() |
|
149 | meta.Session().commit() | |
150 | raise HTTPFound(location=url('login_home')) |
|
150 | raise HTTPFound(location=url('login_home')) | |
@@ -162,7 +162,7 b' class LoginController(BaseController):' | |||||
162 | # the fly can throw this exception signaling that there's issue |
|
162 | # the fly can throw this exception signaling that there's issue | |
163 | # with user creation, explanation should be provided in |
|
163 | # with user creation, explanation should be provided in | |
164 | # Exception itself |
|
164 | # Exception itself | |
165 |
|
|
165 | webutils.flash(e, 'error') | |
166 |
|
166 | |||
167 | return render('/register.html') |
|
167 | return render('/register.html') | |
168 |
|
168 | |||
@@ -188,7 +188,7 b' class LoginController(BaseController):' | |||||
188 | raise formencode.Invalid(_msg, _value, None, |
|
188 | raise formencode.Invalid(_msg, _value, None, | |
189 | error_dict=error_dict) |
|
189 | error_dict=error_dict) | |
190 | redirect_link = UserModel().send_reset_password_email(form_result) |
|
190 | redirect_link = UserModel().send_reset_password_email(form_result) | |
191 |
|
|
191 | webutils.flash(_('A password reset confirmation code has been sent'), | |
192 | category='success') |
|
192 | category='success') | |
193 | raise HTTPFound(location=redirect_link) |
|
193 | raise HTTPFound(location=redirect_link) | |
194 |
|
194 | |||
@@ -240,7 +240,7 b' class LoginController(BaseController):' | |||||
240 | encoding='UTF-8') |
|
240 | encoding='UTF-8') | |
241 |
|
241 | |||
242 | UserModel().reset_password(form_result['email'], form_result['password']) |
|
242 | UserModel().reset_password(form_result['email'], form_result['password']) | |
243 |
|
|
243 | webutils.flash(_('Successfully updated password'), category='success') | |
244 | raise HTTPFound(location=url('login_home')) |
|
244 | raise HTTPFound(location=url('login_home')) | |
245 |
|
245 | |||
246 | def logout(self): |
|
246 | def logout(self): | |
@@ -254,4 +254,4 b' class LoginController(BaseController):' | |||||
254 | Only intended for testing but might also be useful for other kinds |
|
254 | Only intended for testing but might also be useful for other kinds | |
255 | of automation. |
|
255 | of automation. | |
256 | """ |
|
256 | """ | |
257 |
return |
|
257 | return webutils.session_csrf_secret_token() |
@@ -35,9 +35,9 b' from tg import tmpl_context as c' | |||||
35 | from tg.i18n import ugettext as _ |
|
35 | from tg.i18n import ugettext as _ | |
36 | from webob.exc import HTTPBadRequest, HTTPForbidden, HTTPFound, HTTPNotFound |
|
36 | from webob.exc import HTTPBadRequest, HTTPForbidden, HTTPFound, HTTPNotFound | |
37 |
|
37 | |||
|
38 | import kallithea.lib.helpers as h | |||
38 | from kallithea.controllers.changeset import create_cs_pr_comment, delete_cs_pr_comment |
|
39 | from kallithea.controllers.changeset import create_cs_pr_comment, delete_cs_pr_comment | |
39 | from kallithea.lib import auth, diffs |
|
40 | from kallithea.lib import auth, diffs, webutils | |
40 | from kallithea.lib import helpers as h |
|
|||
41 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired |
|
41 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired | |
42 | from kallithea.lib.base import BaseRepoController, jsonify, render |
|
42 | from kallithea.lib.base import BaseRepoController, jsonify, render | |
43 | from kallithea.lib.graphmod import graph_data |
|
43 | from kallithea.lib.graphmod import graph_data | |
@@ -63,7 +63,7 b' def _get_reviewer(user_id):' | |||||
63 | user = None |
|
63 | user = None | |
64 |
|
64 | |||
65 | if user is None or user.is_default_user: |
|
65 | if user is None or user.is_default_user: | |
66 |
|
|
66 | webutils.flash(_('Invalid reviewer "%s" specified') % user_id, category='error') | |
67 | raise HTTPBadRequest() |
|
67 | raise HTTPBadRequest() | |
68 |
|
68 | |||
69 | return user |
|
69 | return user | |
@@ -245,7 +245,7 b' class PullrequestsController(BaseRepoCon' | |||||
245 | try: |
|
245 | try: | |
246 | org_scm_instance.get_changeset() |
|
246 | org_scm_instance.get_changeset() | |
247 | except EmptyRepositoryError as e: |
|
247 | except EmptyRepositoryError as e: | |
248 |
|
|
248 | webutils.flash(_('There are no changesets yet'), | |
249 | category='warning') |
|
249 | category='warning') | |
250 | raise HTTPFound(location=url('summary_home', repo_name=org_repo.repo_name)) |
|
250 | raise HTTPFound(location=url('summary_home', repo_name=org_repo.repo_name)) | |
251 |
|
251 | |||
@@ -314,7 +314,7 b' class PullrequestsController(BaseRepoCon' | |||||
314 | log.error(traceback.format_exc()) |
|
314 | log.error(traceback.format_exc()) | |
315 | log.error(str(errors)) |
|
315 | log.error(str(errors)) | |
316 | msg = _('Error creating pull request: %s') % errors.msg |
|
316 | msg = _('Error creating pull request: %s') % errors.msg | |
317 |
|
|
317 | webutils.flash(msg, 'error') | |
318 | raise HTTPBadRequest |
|
318 | raise HTTPBadRequest | |
319 |
|
319 | |||
320 | # heads up: org and other might seem backward here ... |
|
320 | # heads up: org and other might seem backward here ... | |
@@ -333,19 +333,19 b' class PullrequestsController(BaseRepoCon' | |||||
333 | try: |
|
333 | try: | |
334 | cmd = CreatePullRequestAction(org_repo, other_repo, org_ref, other_ref, title, description, owner, reviewers) |
|
334 | cmd = CreatePullRequestAction(org_repo, other_repo, org_ref, other_ref, title, description, owner, reviewers) | |
335 | except CreatePullRequestAction.ValidationError as e: |
|
335 | except CreatePullRequestAction.ValidationError as e: | |
336 |
|
|
336 | webutils.flash(e, category='error', logf=log.error) | |
337 | raise HTTPNotFound |
|
337 | raise HTTPNotFound | |
338 |
|
338 | |||
339 | try: |
|
339 | try: | |
340 | pull_request = cmd.execute() |
|
340 | pull_request = cmd.execute() | |
341 | meta.Session().commit() |
|
341 | meta.Session().commit() | |
342 | except Exception: |
|
342 | except Exception: | |
343 |
|
|
343 | webutils.flash(_('Error occurred while creating pull request'), | |
344 | category='error') |
|
344 | category='error') | |
345 | log.error(traceback.format_exc()) |
|
345 | log.error(traceback.format_exc()) | |
346 | raise HTTPFound(location=url('pullrequest_home', repo_name=repo_name)) |
|
346 | raise HTTPFound(location=url('pullrequest_home', repo_name=repo_name)) | |
347 |
|
347 | |||
348 |
|
|
348 | webutils.flash(_('Successfully opened new pull request'), | |
349 | category='success') |
|
349 | category='success') | |
350 | raise HTTPFound(location=pull_request.url()) |
|
350 | raise HTTPFound(location=pull_request.url()) | |
351 |
|
351 | |||
@@ -356,19 +356,19 b' class PullrequestsController(BaseRepoCon' | |||||
356 | try: |
|
356 | try: | |
357 | cmd = CreatePullRequestIterationAction(old_pull_request, new_org_rev, new_other_rev, title, description, owner, reviewers) |
|
357 | cmd = CreatePullRequestIterationAction(old_pull_request, new_org_rev, new_other_rev, title, description, owner, reviewers) | |
358 | except CreatePullRequestAction.ValidationError as e: |
|
358 | except CreatePullRequestAction.ValidationError as e: | |
359 |
|
|
359 | webutils.flash(e, category='error', logf=log.error) | |
360 | raise HTTPNotFound |
|
360 | raise HTTPNotFound | |
361 |
|
361 | |||
362 | try: |
|
362 | try: | |
363 | pull_request = cmd.execute() |
|
363 | pull_request = cmd.execute() | |
364 | meta.Session().commit() |
|
364 | meta.Session().commit() | |
365 | except Exception: |
|
365 | except Exception: | |
366 |
|
|
366 | webutils.flash(_('Error occurred while creating pull request'), | |
367 | category='error') |
|
367 | category='error') | |
368 | log.error(traceback.format_exc()) |
|
368 | log.error(traceback.format_exc()) | |
369 | raise HTTPFound(location=old_pull_request.url()) |
|
369 | raise HTTPFound(location=old_pull_request.url()) | |
370 |
|
370 | |||
371 |
|
|
371 | webutils.flash(_('New pull request iteration created'), | |
372 | category='success') |
|
372 | category='success') | |
373 | raise HTTPFound(location=pull_request.url()) |
|
373 | raise HTTPFound(location=pull_request.url()) | |
374 |
|
374 | |||
@@ -396,11 +396,11 b' class PullrequestsController(BaseRepoCon' | |||||
396 | other_removed = old_reviewers - cur_reviewers |
|
396 | other_removed = old_reviewers - cur_reviewers | |
397 |
|
397 | |||
398 | if other_added: |
|
398 | if other_added: | |
399 |
|
|
399 | webutils.flash(_('Meanwhile, the following reviewers have been added: %s') % | |
400 | (', '.join(u.username for u in other_added)), |
|
400 | (', '.join(u.username for u in other_added)), | |
401 | category='warning') |
|
401 | category='warning') | |
402 | if other_removed: |
|
402 | if other_removed: | |
403 |
|
|
403 | webutils.flash(_('Meanwhile, the following reviewers have been removed: %s') % | |
404 | (', '.join(u.username for u in other_removed)), |
|
404 | (', '.join(u.username for u in other_removed)), | |
405 | category='warning') |
|
405 | category='warning') | |
406 |
|
406 | |||
@@ -425,7 +425,7 b' class PullrequestsController(BaseRepoCon' | |||||
425 | PullRequestModel().remove_reviewers(user, pull_request, removed_reviewers) |
|
425 | PullRequestModel().remove_reviewers(user, pull_request, removed_reviewers) | |
426 |
|
426 | |||
427 | meta.Session().commit() |
|
427 | meta.Session().commit() | |
428 |
|
|
428 | webutils.flash(_('Pull request updated'), category='success') | |
429 |
|
429 | |||
430 | raise HTTPFound(location=pull_request.url()) |
|
430 | raise HTTPFound(location=pull_request.url()) | |
431 |
|
431 | |||
@@ -438,7 +438,7 b' class PullrequestsController(BaseRepoCon' | |||||
438 | if pull_request.owner_id == request.authuser.user_id: |
|
438 | if pull_request.owner_id == request.authuser.user_id: | |
439 | PullRequestModel().delete(pull_request) |
|
439 | PullRequestModel().delete(pull_request) | |
440 | meta.Session().commit() |
|
440 | meta.Session().commit() | |
441 |
|
|
441 | webutils.flash(_('Successfully deleted pull request'), | |
442 | category='success') |
|
442 | category='success') | |
443 | raise HTTPFound(location=url('my_pullrequests')) |
|
443 | raise HTTPFound(location=url('my_pullrequests')) | |
444 | raise HTTPForbidden() |
|
444 | raise HTTPForbidden() | |
@@ -474,7 +474,7 b' class PullrequestsController(BaseRepoCon' | |||||
474 | c.cs_ranges.append(org_scm_instance.get_changeset(x)) |
|
474 | c.cs_ranges.append(org_scm_instance.get_changeset(x)) | |
475 | except ChangesetDoesNotExistError: |
|
475 | except ChangesetDoesNotExistError: | |
476 | c.cs_ranges = [] |
|
476 | c.cs_ranges = [] | |
477 |
|
|
477 | webutils.flash(_('Revision %s not found in %s') % (x, c.cs_repo.repo_name), | |
478 | 'error') |
|
478 | 'error') | |
479 | break |
|
479 | break | |
480 | c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ... |
|
480 | c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ... |
@@ -38,8 +38,7 b' from tg import tmpl_context as c' | |||||
38 | from tg.i18n import ugettext as _ |
|
38 | from tg.i18n import ugettext as _ | |
39 | from webob.exc import HTTPBadRequest |
|
39 | from webob.exc import HTTPBadRequest | |
40 |
|
40 | |||
41 | import kallithea.lib.helpers as h |
|
41 | from kallithea.lib import ext_json, webutils | |
42 | from kallithea.lib import ext_json |
|
|||
43 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired |
|
42 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired | |
44 | from kallithea.lib.base import BaseRepoController, jsonify, render |
|
43 | from kallithea.lib.base import BaseRepoController, jsonify, render | |
45 | from kallithea.lib.celerylib.tasks import get_commits_stats |
|
44 | from kallithea.lib.celerylib.tasks import get_commits_stats | |
@@ -108,7 +107,7 b' class SummaryController(BaseRepoControll' | |||||
108 | try: |
|
107 | try: | |
109 | collection = c.db_repo_scm_instance.get_changesets(reverse=True) |
|
108 | collection = c.db_repo_scm_instance.get_changesets(reverse=True) | |
110 | except EmptyRepositoryError as e: |
|
109 | except EmptyRepositoryError as e: | |
111 |
|
|
110 | webutils.flash(e, category='warning') | |
112 | collection = [] |
|
111 | collection = [] | |
113 | c.cs_pagination = Page(collection, page=p, items_per_page=size) |
|
112 | c.cs_pagination = Page(collection, page=p, items_per_page=size) | |
114 | page_revisions = [x.raw_id for x in list(c.cs_pagination)] |
|
113 | page_revisions = [x.raw_id for x in list(c.cs_pagination)] |
@@ -40,6 +40,7 b' from tg.i18n import ugettext as _' | |||||
40 | from webob.exc import HTTPForbidden, HTTPFound |
|
40 | from webob.exc import HTTPForbidden, HTTPFound | |
41 |
|
41 | |||
42 | import kallithea |
|
42 | import kallithea | |
|
43 | from kallithea.lib import webutils | |||
43 | from kallithea.lib.utils import get_repo_group_slug, get_repo_slug, get_user_group_slug |
|
44 | from kallithea.lib.utils import get_repo_group_slug, get_repo_slug, get_user_group_slug | |
44 | from kallithea.lib.utils2 import ascii_bytes, ascii_str, safe_bytes |
|
45 | from kallithea.lib.utils2 import ascii_bytes, ascii_str, safe_bytes | |
45 | from kallithea.lib.vcs.utils.lazy import LazyProperty |
|
46 | from kallithea.lib.vcs.utils.lazy import LazyProperty | |
@@ -544,9 +545,8 b' def _redirect_to_login(message=None):' | |||||
544 | """Return an exception that must be raised. It will redirect to the login |
|
545 | """Return an exception that must be raised. It will redirect to the login | |
545 | page which will redirect back to the current URL after authentication. |
|
546 | page which will redirect back to the current URL after authentication. | |
546 | The optional message will be shown in a flash message.""" |
|
547 | The optional message will be shown in a flash message.""" | |
547 | from kallithea.lib import helpers as h |
|
|||
548 | if message: |
|
548 | if message: | |
549 |
|
|
549 | webutils.flash(message, category='warning') | |
550 | p = request.path_qs |
|
550 | p = request.path_qs | |
551 | log.debug('Redirecting to login page, origin: %s', p) |
|
551 | log.debug('Redirecting to login page, origin: %s', p) | |
552 | return HTTPFound(location=url('login_home', came_from=p)) |
|
552 | return HTTPFound(location=url('login_home', came_from=p)) |
@@ -44,7 +44,7 b' from tg import tmpl_context as c' | |||||
44 | from tg.i18n import ugettext as _ |
|
44 | from tg.i18n import ugettext as _ | |
45 |
|
45 | |||
46 | import kallithea |
|
46 | import kallithea | |
47 | from kallithea.lib import auth_modules, ext_json |
|
47 | from kallithea.lib import auth_modules, ext_json, webutils | |
48 | from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware |
|
48 | from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware | |
49 | from kallithea.lib.exceptions import UserCreationError |
|
49 | from kallithea.lib.exceptions import UserCreationError | |
50 | from kallithea.lib.utils import get_repo_slug, is_valid_repo |
|
50 | from kallithea.lib.utils import get_repo_slug, is_valid_repo | |
@@ -361,9 +361,8 b' class BaseController(TGController):' | |||||
361 | # guaranteed to be side effect free. In practice, the only situation |
|
361 | # guaranteed to be side effect free. In practice, the only situation | |
362 | # where we allow side effects without ambient authority is when the |
|
362 | # where we allow side effects without ambient authority is when the | |
363 | # authority comes from an API key; and that is handled above. |
|
363 | # authority comes from an API key; and that is handled above. | |
364 | from kallithea.lib import helpers as h |
|
364 | token = request.POST.get(webutils.session_csrf_secret_name) | |
365 |
token |
|
365 | if not token or token != webutils.session_csrf_secret_token(): | |
366 | if not token or token != h.session_csrf_secret_token(): |
|
|||
367 | log.error('CSRF check failed') |
|
366 | log.error('CSRF check failed') | |
368 | raise webob.exc.HTTPForbidden() |
|
367 | raise webob.exc.HTTPForbidden() | |
369 |
|
368 | |||
@@ -444,8 +443,7 b' class BaseController(TGController):' | |||||
444 | try: |
|
443 | try: | |
445 | user_info = auth_modules.authenticate('', '', request.environ) |
|
444 | user_info = auth_modules.authenticate('', '', request.environ) | |
446 | except UserCreationError as e: |
|
445 | except UserCreationError as e: | |
447 | from kallithea.lib import helpers as h |
|
446 | webutils.flash(e, 'error', logf=log.error) | |
448 | h.flash(e, 'error', logf=log.error) |
|
|||
449 | else: |
|
447 | else: | |
450 | if user_info is not None: |
|
448 | if user_info is not None: | |
451 | username = user_info['username'] |
|
449 | username = user_info['username'] | |
@@ -474,12 +472,11 b' class BaseController(TGController):' | |||||
474 | raise webob.exc.HTTPMethodNotAllowed() |
|
472 | raise webob.exc.HTTPMethodNotAllowed() | |
475 |
|
473 | |||
476 | # Make sure CSRF token never appears in the URL. If so, invalidate it. |
|
474 | # Make sure CSRF token never appears in the URL. If so, invalidate it. | |
477 | from kallithea.lib import helpers as h |
|
475 | if webutils.session_csrf_secret_name in request.GET: | |
478 | if h.session_csrf_secret_name in request.GET: |
|
|||
479 | log.error('CSRF key leak detected') |
|
476 | log.error('CSRF key leak detected') | |
480 |
session.pop( |
|
477 | session.pop(webutils.session_csrf_secret_name, None) | |
481 | session.save() |
|
478 | session.save() | |
482 |
|
|
479 | webutils.flash(_('CSRF token leak has been detected - all form tokens have been expired'), | |
483 | category='error') |
|
480 | category='error') | |
484 |
|
481 | |||
485 | # WebOb already ignores request payload parameters for anything other |
|
482 | # WebOb already ignores request payload parameters for anything other | |
@@ -575,8 +572,7 b' class BaseRepoController(BaseController)' | |||||
575 | if c.db_repo_scm_instance is None: |
|
572 | if c.db_repo_scm_instance is None: | |
576 | log.error('%s this repository is present in database but it ' |
|
573 | log.error('%s this repository is present in database but it ' | |
577 | 'cannot be created as an scm instance', c.repo_name) |
|
574 | 'cannot be created as an scm instance', c.repo_name) | |
578 | from kallithea.lib import helpers as h |
|
575 | webutils.flash(_('Repository not found in the filesystem'), | |
579 | h.flash(_('Repository not found in the filesystem'), |
|
|||
580 | category='error') |
|
576 | category='error') | |
581 | raise webob.exc.HTTPNotFound() |
|
577 | raise webob.exc.HTTPNotFound() | |
582 |
|
578 | |||
@@ -592,22 +588,21 b' class BaseRepoController(BaseController)' | |||||
592 | """ |
|
588 | """ | |
593 | Safe way to get changeset. If error occurs show error. |
|
589 | Safe way to get changeset. If error occurs show error. | |
594 | """ |
|
590 | """ | |
595 | from kallithea.lib import helpers as h |
|
|||
596 | try: |
|
591 | try: | |
597 | return repo.scm_instance.get_ref_revision(ref_type, ref_name) |
|
592 | return repo.scm_instance.get_ref_revision(ref_type, ref_name) | |
598 | except EmptyRepositoryError as e: |
|
593 | except EmptyRepositoryError as e: | |
599 | if returnempty: |
|
594 | if returnempty: | |
600 | return repo.scm_instance.EMPTY_CHANGESET |
|
595 | return repo.scm_instance.EMPTY_CHANGESET | |
601 |
|
|
596 | webutils.flash(_('There are no changesets yet'), category='error') | |
602 | raise webob.exc.HTTPNotFound() |
|
597 | raise webob.exc.HTTPNotFound() | |
603 | except ChangesetDoesNotExistError as e: |
|
598 | except ChangesetDoesNotExistError as e: | |
604 |
|
|
599 | webutils.flash(_('Changeset for %s %s not found in %s') % | |
605 | (ref_type, ref_name, repo.repo_name), |
|
600 | (ref_type, ref_name, repo.repo_name), | |
606 | category='error') |
|
601 | category='error') | |
607 | raise webob.exc.HTTPNotFound() |
|
602 | raise webob.exc.HTTPNotFound() | |
608 | except RepositoryError as e: |
|
603 | except RepositoryError as e: | |
609 | log.error(traceback.format_exc()) |
|
604 | log.error(traceback.format_exc()) | |
610 |
|
|
605 | webutils.flash(e, category='error') | |
611 | raise webob.exc.HTTPBadRequest() |
|
606 | raise webob.exc.HTTPBadRequest() | |
612 |
|
607 | |||
613 |
|
608 | |||
@@ -642,7 +637,6 b' def IfSshEnabled(func, *args, **kwargs):' | |||||
642 | If SSH access is disabled in the configuration file, HTTPNotFound is raised. |
|
637 | If SSH access is disabled in the configuration file, HTTPNotFound is raised. | |
643 | """ |
|
638 | """ | |
644 | if not c.ssh_enabled: |
|
639 | if not c.ssh_enabled: | |
645 | from kallithea.lib import helpers as h |
|
640 | webutils.flash(_("SSH access is disabled."), category='warning') | |
646 | h.flash(_("SSH access is disabled."), category='warning') |
|
|||
647 | raise webob.exc.HTTPNotFound() |
|
641 | raise webob.exc.HTTPNotFound() | |
648 | return func(*args, **kwargs) |
|
642 | return func(*args, **kwargs) |
@@ -31,7 +31,7 b' import re' | |||||
31 |
|
31 | |||
32 | from tg.i18n import ugettext as _ |
|
32 | from tg.i18n import ugettext as _ | |
33 |
|
33 | |||
34 |
from kallithea.lib import |
|
34 | from kallithea.lib import webutils | |
35 | from kallithea.lib.utils2 import safe_str |
|
35 | from kallithea.lib.utils2 import safe_str | |
36 | from kallithea.lib.vcs.backends.base import EmptyChangeset |
|
36 | from kallithea.lib.vcs.backends.base import EmptyChangeset | |
37 | from kallithea.lib.vcs.exceptions import VCSError |
|
37 | from kallithea.lib.vcs.exceptions import VCSError | |
@@ -207,7 +207,7 b' def wrapped_diff(filenode_old, filenode_' | |||||
207 | if not html_diff: |
|
207 | if not html_diff: | |
208 | submodules = [o for o in [filenode_new, filenode_old] if isinstance(o, SubModuleNode)] |
|
208 | submodules = [o for o in [filenode_new, filenode_old] if isinstance(o, SubModuleNode)] | |
209 | if submodules: |
|
209 | if submodules: | |
210 |
html_diff = wrap_to_table( |
|
210 | html_diff = wrap_to_table(webutils.escape('Submodule %r' % submodules[0])) | |
211 | else: |
|
211 | else: | |
212 | html_diff = wrap_to_table(_('No changes detected')) |
|
212 | html_diff = wrap_to_table(_('No changes detected')) | |
213 |
|
213 | |||
@@ -249,7 +249,7 b' def get_diff(scm_instance, rev1, rev2, p' | |||||
249 | return scm_instance.get_diff(rev1, rev2, path=path, |
|
249 | return scm_instance.get_diff(rev1, rev2, path=path, | |
250 | ignore_whitespace=ignore_whitespace, context=context) |
|
250 | ignore_whitespace=ignore_whitespace, context=context) | |
251 | except MemoryError: |
|
251 | except MemoryError: | |
252 |
|
|
252 | webutils.flash('MemoryError: Diff is too big', category='error') | |
253 | return b'' |
|
253 | return b'' | |
254 |
|
254 | |||
255 |
|
255 |
@@ -20,7 +20,6 b' available to Controllers. This module is' | |||||
20 | import hashlib |
|
20 | import hashlib | |
21 | import json |
|
21 | import json | |
22 | import logging |
|
22 | import logging | |
23 | import random |
|
|||
24 | import re |
|
23 | import re | |
25 | import textwrap |
|
24 | import textwrap | |
26 | import urllib.parse |
|
25 | import urllib.parse | |
@@ -28,16 +27,7 b' import urllib.parse' | |||||
28 | from beaker.cache import cache_region |
|
27 | from beaker.cache import cache_region | |
29 | from pygments import highlight as code_highlight |
|
28 | from pygments import highlight as code_highlight | |
30 | from pygments.formatters.html import HtmlFormatter |
|
29 | from pygments.formatters.html import HtmlFormatter | |
31 | from tg import session |
|
|||
32 | from tg.i18n import ugettext as _ |
|
30 | from tg.i18n import ugettext as _ | |
33 | from webhelpers2.html import HTML, escape, literal |
|
|||
34 | from webhelpers2.html.tags import NotGiven, Option, Options, _input, _make_safe_id_component, checkbox, end_form |
|
|||
35 | from webhelpers2.html.tags import form as insecure_form |
|
|||
36 | from webhelpers2.html.tags import hidden, link_to, password, radio |
|
|||
37 | from webhelpers2.html.tags import select as webhelpers2_select |
|
|||
38 | from webhelpers2.html.tags import submit, text, textarea |
|
|||
39 | from webhelpers2.number import format_byte_size |
|
|||
40 | from webhelpers2.text import chop_at, truncate, wrap_paragraphs |
|
|||
41 |
|
31 | |||
42 | import kallithea |
|
32 | import kallithea | |
43 | from kallithea.lib.annotate import annotate_highlight |
|
33 | from kallithea.lib.annotate import annotate_highlight | |
@@ -55,47 +45,49 b' from kallithea.lib.vcs.exceptions import' | |||||
55 | # SCM FILTERS available via h. |
|
45 | # SCM FILTERS available via h. | |
56 | #============================================================================== |
|
46 | #============================================================================== | |
57 | from kallithea.lib.vcs.utils import author_email, author_name |
|
47 | from kallithea.lib.vcs.utils import author_email, author_name | |
58 | from kallithea.lib.webutils import canonical_url, url |
|
48 | from kallithea.lib.webutils import (HTML, Option, canonical_url, checkbox, chop_at, end_form, escape, form, format_byte_size, hidden, html_escape, link_to, | |
|
49 | literal, password, pop_flash_messages, radio, reset, safeid, select, session_csrf_secret_name, session_csrf_secret_token, | |||
|
50 | submit, text, textarea, truncate, url, wrap_paragraphs) | |||
59 | from kallithea.model import db |
|
51 | from kallithea.model import db | |
60 | from kallithea.model.changeset_status import ChangesetStatusModel |
|
52 | from kallithea.model.changeset_status import ChangesetStatusModel | |
61 |
|
53 | |||
62 |
|
54 | |||
63 | # mute pyflakes "imported but unused" |
|
55 | # mute pyflakes "imported but unused" | |
|
56 | # from webutils | |||
64 | assert Option |
|
57 | assert Option | |
|
58 | assert canonical_url | |||
65 | assert checkbox |
|
59 | assert checkbox | |
|
60 | assert chop_at | |||
66 | assert end_form |
|
61 | assert end_form | |
|
62 | assert form | |||
|
63 | assert format_byte_size | |||
|
64 | assert hidden | |||
67 | assert password |
|
65 | assert password | |
|
66 | assert pop_flash_messages | |||
68 | assert radio |
|
67 | assert radio | |
|
68 | assert reset | |||
|
69 | assert safeid | |||
|
70 | assert select | |||
|
71 | assert session_csrf_secret_name | |||
|
72 | assert session_csrf_secret_token | |||
69 | assert submit |
|
73 | assert submit | |
70 | assert text |
|
74 | assert text | |
71 | assert textarea |
|
75 | assert textarea | |
72 | assert format_byte_size |
|
|||
73 | assert chop_at |
|
|||
74 | assert wrap_paragraphs |
|
76 | assert wrap_paragraphs | |
|
77 | # from kallithea.lib.auth | |||
75 | assert HasPermissionAny |
|
78 | assert HasPermissionAny | |
76 | assert HasRepoGroupPermissionLevel |
|
79 | assert HasRepoGroupPermissionLevel | |
77 | assert HasRepoPermissionLevel |
|
80 | assert HasRepoPermissionLevel | |
|
81 | # from utils2 | |||
78 | assert age |
|
82 | assert age | |
79 | assert time_to_datetime |
|
83 | assert time_to_datetime | |
|
84 | # from vcs | |||
80 | assert EmptyChangeset |
|
85 | assert EmptyChangeset | |
81 | assert canonical_url |
|
|||
82 |
|
86 | |||
83 |
|
87 | |||
84 | log = logging.getLogger(__name__) |
|
88 | log = logging.getLogger(__name__) | |
85 |
|
89 | |||
86 |
|
90 | |||
87 | def html_escape(s): |
|
|||
88 | """Return string with all html escaped. |
|
|||
89 | This is also safe for javascript in html but not necessarily correct. |
|
|||
90 | """ |
|
|||
91 | return (s |
|
|||
92 | .replace('&', '&') |
|
|||
93 | .replace(">", ">") |
|
|||
94 | .replace("<", "<") |
|
|||
95 | .replace('"', """) |
|
|||
96 | .replace("'", "'") # Note: this is HTML5 not HTML4 and might not work in mails |
|
|||
97 | ) |
|
|||
98 |
|
||||
99 | def js(value): |
|
91 | def js(value): | |
100 | """Convert Python value to the corresponding JavaScript representation. |
|
92 | """Convert Python value to the corresponding JavaScript representation. | |
101 |
|
93 | |||
@@ -152,44 +144,6 b' def shorter(s, size=20, firstline=False,' | |||||
152 | return s |
|
144 | return s | |
153 |
|
145 | |||
154 |
|
146 | |||
155 | def reset(name, value, id=NotGiven, **attrs): |
|
|||
156 | """Create a reset button, similar to webhelpers2.html.tags.submit .""" |
|
|||
157 | return _input("reset", name, value, id, attrs) |
|
|||
158 |
|
||||
159 |
|
||||
160 | def select(name, selected_values, options, id=NotGiven, **attrs): |
|
|||
161 | """Convenient wrapper of webhelpers2 to let it accept options as a tuple list""" |
|
|||
162 | if isinstance(options, list): |
|
|||
163 | option_list = options |
|
|||
164 | # Handle old value,label lists ... where value also can be value,label lists |
|
|||
165 | options = Options() |
|
|||
166 | for x in option_list: |
|
|||
167 | if isinstance(x, tuple) and len(x) == 2: |
|
|||
168 | value, label = x |
|
|||
169 | elif isinstance(x, str): |
|
|||
170 | value = label = x |
|
|||
171 | else: |
|
|||
172 | log.error('invalid select option %r', x) |
|
|||
173 | raise |
|
|||
174 | if isinstance(value, list): |
|
|||
175 | og = options.add_optgroup(label) |
|
|||
176 | for x in value: |
|
|||
177 | if isinstance(x, tuple) and len(x) == 2: |
|
|||
178 | group_value, group_label = x |
|
|||
179 | elif isinstance(x, str): |
|
|||
180 | group_value = group_label = x |
|
|||
181 | else: |
|
|||
182 | log.error('invalid select option %r', x) |
|
|||
183 | raise |
|
|||
184 | og.add_option(group_label, group_value) |
|
|||
185 | else: |
|
|||
186 | options.add_option(label, value) |
|
|||
187 | return webhelpers2_select(name, selected_values, options, id=id, **attrs) |
|
|||
188 |
|
||||
189 |
|
||||
190 | safeid = _make_safe_id_component |
|
|||
191 |
|
||||
192 |
|
||||
193 | def FID(raw_id, path): |
|
147 | def FID(raw_id, path): | |
194 | """ |
|
148 | """ | |
195 | Creates a unique ID for filenode based on it's hash of path and revision |
|
149 | Creates a unique ID for filenode based on it's hash of path and revision | |
@@ -448,76 +402,6 b' def pygmentize_annotation(repo_name, fil' | |||||
448 | return literal(markup_whitespace(annotate_highlight(filenode, url_func, **kwargs))) |
|
402 | return literal(markup_whitespace(annotate_highlight(filenode, url_func, **kwargs))) | |
449 |
|
403 | |||
450 |
|
404 | |||
451 | class _Message(object): |
|
|||
452 | """A message returned by ``pop_flash_messages()``. |
|
|||
453 |
|
||||
454 | Converting the message to a string returns the message text. Instances |
|
|||
455 | also have the following attributes: |
|
|||
456 |
|
||||
457 | * ``category``: the category specified when the message was created. |
|
|||
458 | * ``message``: the html-safe message text. |
|
|||
459 | """ |
|
|||
460 |
|
||||
461 | def __init__(self, category, message): |
|
|||
462 | self.category = category |
|
|||
463 | self.message = message |
|
|||
464 |
|
||||
465 |
|
||||
466 | def _session_flash_messages(append=None, clear=False): |
|
|||
467 | """Manage a message queue in tg.session: return the current message queue |
|
|||
468 | after appending the given message, and possibly clearing the queue.""" |
|
|||
469 | key = 'flash' |
|
|||
470 | if key in session: |
|
|||
471 | flash_messages = session[key] |
|
|||
472 | else: |
|
|||
473 | if append is None: # common fast path - also used for clearing empty queue |
|
|||
474 | return [] # don't bother saving |
|
|||
475 | flash_messages = [] |
|
|||
476 | session[key] = flash_messages |
|
|||
477 | if append is not None and append not in flash_messages: |
|
|||
478 | flash_messages.append(append) |
|
|||
479 | if clear: |
|
|||
480 | session.pop(key, None) |
|
|||
481 | session.save() |
|
|||
482 | return flash_messages |
|
|||
483 |
|
||||
484 |
|
||||
485 | def flash(message, category, logf=None): |
|
|||
486 | """ |
|
|||
487 | Show a message to the user _and_ log it through the specified function |
|
|||
488 |
|
||||
489 | category: notice (default), warning, error, success |
|
|||
490 | logf: a custom log function - such as log.debug |
|
|||
491 |
|
||||
492 | logf defaults to log.info, unless category equals 'success', in which |
|
|||
493 | case logf defaults to log.debug. |
|
|||
494 | """ |
|
|||
495 | assert category in ('error', 'success', 'warning'), category |
|
|||
496 | if hasattr(message, '__html__'): |
|
|||
497 | # render to HTML for storing in cookie |
|
|||
498 | safe_message = str(message) |
|
|||
499 | else: |
|
|||
500 | # Apply str - the message might be an exception with __str__ |
|
|||
501 | # Escape, so we can trust the result without further escaping, without any risk of injection |
|
|||
502 | safe_message = html_escape(str(message)) |
|
|||
503 | if logf is None: |
|
|||
504 | logf = log.info |
|
|||
505 | if category == 'success': |
|
|||
506 | logf = log.debug |
|
|||
507 |
|
||||
508 | logf('Flash %s: %s', category, safe_message) |
|
|||
509 |
|
||||
510 | _session_flash_messages(append=(category, safe_message)) |
|
|||
511 |
|
||||
512 |
|
||||
513 | def pop_flash_messages(): |
|
|||
514 | """Return all accumulated messages and delete them from the session. |
|
|||
515 |
|
||||
516 | The return value is a list of ``Message`` objects. |
|
|||
517 | """ |
|
|||
518 | return [_Message(category, message) for category, message in _session_flash_messages(clear=True)] |
|
|||
519 |
|
||||
520 |
|
||||
521 | def capitalize(x): |
|
405 | def capitalize(x): | |
522 | return x.capitalize() |
|
406 | return x.capitalize() | |
523 |
|
407 | |||
@@ -1317,23 +1201,3 b' def journal_filter_help():' | |||||
1317 | def ip_range(ip_addr): |
|
1201 | def ip_range(ip_addr): | |
1318 | s, e = db.UserIpMap._get_ip_range(ip_addr) |
|
1202 | s, e = db.UserIpMap._get_ip_range(ip_addr) | |
1319 | return '%s - %s' % (s, e) |
|
1203 | return '%s - %s' % (s, e) | |
1320 |
|
||||
1321 |
|
||||
1322 | session_csrf_secret_name = "_session_csrf_secret_token" |
|
|||
1323 |
|
||||
1324 | def session_csrf_secret_token(): |
|
|||
1325 | """Return (and create) the current session's CSRF protection token.""" |
|
|||
1326 | if not session_csrf_secret_name in session: |
|
|||
1327 | session[session_csrf_secret_name] = str(random.getrandbits(128)) |
|
|||
1328 | session.save() |
|
|||
1329 | return session[session_csrf_secret_name] |
|
|||
1330 |
|
||||
1331 | def form(url, method="post", **attrs): |
|
|||
1332 | """Like webhelpers.html.tags.form , but automatically adding |
|
|||
1333 | session_csrf_secret_token for POST. The secret is thus never leaked in GET |
|
|||
1334 | URLs. |
|
|||
1335 | """ |
|
|||
1336 | form = insecure_form(url, method, **attrs) |
|
|||
1337 | if method.lower() == 'get': |
|
|||
1338 | return form |
|
|||
1339 | return form + HTML.div(hidden(session_csrf_secret_name, session_csrf_secret_token()), style="display: none;") |
|
@@ -32,7 +32,7 b' import time' | |||||
32 | import mercurial.scmutil |
|
32 | import mercurial.scmutil | |
33 |
|
33 | |||
34 | import kallithea |
|
34 | import kallithea | |
35 |
from kallithea.lib import |
|
35 | from kallithea.lib import webutils | |
36 | from kallithea.lib.exceptions import UserCreationError |
|
36 | from kallithea.lib.exceptions import UserCreationError | |
37 | from kallithea.lib.utils import action_logger, make_ui |
|
37 | from kallithea.lib.utils import action_logger, make_ui | |
38 | from kallithea.lib.utils2 import HookEnvironmentError, ascii_str, get_hook_environment, safe_bytes, safe_str |
|
38 | from kallithea.lib.utils2 import HookEnvironmentError, ascii_str, get_hook_environment, safe_bytes, safe_str | |
@@ -59,9 +59,9 b' def _get_scm_size(alias, root_path):' | |||||
59 | except OSError: |
|
59 | except OSError: | |
60 | pass |
|
60 | pass | |
61 |
|
61 | |||
62 |
size_scm_f = |
|
62 | size_scm_f = webutils.format_byte_size(size_scm) | |
63 |
size_root_f = |
|
63 | size_root_f = webutils.format_byte_size(size_root) | |
64 |
size_total_f = |
|
64 | size_total_f = webutils.format_byte_size(size_root + size_scm) | |
65 |
|
65 | |||
66 | return size_scm_f, size_root_f, size_total_f |
|
66 | return size_scm_f, size_root_f, size_total_f | |
67 |
|
67 |
@@ -19,9 +19,8 b' import logging' | |||||
19 | import paginate |
|
19 | import paginate | |
20 | import paginate_sqlalchemy |
|
20 | import paginate_sqlalchemy | |
21 | import sqlalchemy.orm |
|
21 | import sqlalchemy.orm | |
22 | from webhelpers2.html import literal |
|
|||
23 |
|
22 | |||
24 |
from kallithea.lib |
|
23 | from kallithea.lib import webutils | |
25 |
|
24 | |||
26 |
|
25 | |||
27 | log = logging.getLogger(__name__) |
|
26 | log = logging.getLogger(__name__) | |
@@ -35,10 +34,10 b' class Page(paginate.Page):' | |||||
35 | if isinstance(collection, sqlalchemy.orm.query.Query): |
|
34 | if isinstance(collection, sqlalchemy.orm.query.Query): | |
36 | collection = paginate_sqlalchemy.SqlalchemyOrmWrapper(collection) |
|
35 | collection = paginate_sqlalchemy.SqlalchemyOrmWrapper(collection) | |
37 | paginate.Page.__init__(self, collection, page=page, items_per_page=items_per_page, item_count=item_count, |
|
36 | paginate.Page.__init__(self, collection, page=page, items_per_page=items_per_page, item_count=item_count, | |
38 | url_maker=lambda page: url.current(page=page, **kwargs)) |
|
37 | url_maker=lambda page: webutils.url.current(page=page, **kwargs)) | |
39 |
|
38 | |||
40 | def pager(self): |
|
39 | def pager(self): | |
41 | return literal( |
|
40 | return webutils.literal( | |
42 | paginate.Page.pager(self, |
|
41 | paginate.Page.pager(self, | |
43 | format='<ul class="pagination">$link_previous\n~4~$link_next</ul>', |
|
42 | format='<ul class="pagination">$link_previous\n~4~$link_next</ul>', | |
44 | link_attr={'class': 'pager_link'}, |
|
43 | link_attr={'class': 'pager_link'}, |
@@ -20,11 +20,46 b' thread-local "global" variables. It shou' | |||||
20 | imported anywhere - just like the global variables can be used everywhere. |
|
20 | imported anywhere - just like the global variables can be used everywhere. | |
21 | """ |
|
21 | """ | |
22 |
|
22 | |||
23 | from tg import request |
|
23 | import logging | |
|
24 | import random | |||
|
25 | ||||
|
26 | from tg import request, session | |||
|
27 | from webhelpers2.html import HTML, escape, literal | |||
|
28 | from webhelpers2.html.tags import NotGiven, Option, Options, _input | |||
|
29 | from webhelpers2.html.tags import _make_safe_id_component as safeid | |||
|
30 | from webhelpers2.html.tags import checkbox, end_form | |||
|
31 | from webhelpers2.html.tags import form as insecure_form | |||
|
32 | from webhelpers2.html.tags import hidden, link_to, password, radio | |||
|
33 | from webhelpers2.html.tags import select as webhelpers2_select | |||
|
34 | from webhelpers2.html.tags import submit, text, textarea | |||
|
35 | from webhelpers2.number import format_byte_size | |||
|
36 | from webhelpers2.text import chop_at, truncate, wrap_paragraphs | |||
24 |
|
37 | |||
25 | import kallithea |
|
38 | import kallithea | |
26 |
|
39 | |||
27 |
|
40 | |||
|
41 | log = logging.getLogger(__name__) | |||
|
42 | ||||
|
43 | ||||
|
44 | # mute pyflakes "imported but unused" | |||
|
45 | assert Option | |||
|
46 | assert checkbox | |||
|
47 | assert chop_at | |||
|
48 | assert end_form | |||
|
49 | assert escape | |||
|
50 | assert format_byte_size | |||
|
51 | assert link_to | |||
|
52 | assert literal | |||
|
53 | assert password | |||
|
54 | assert radio | |||
|
55 | assert safeid | |||
|
56 | assert submit | |||
|
57 | assert text | |||
|
58 | assert textarea | |||
|
59 | assert truncate | |||
|
60 | assert wrap_paragraphs | |||
|
61 | ||||
|
62 | ||||
28 | # |
|
63 | # | |
29 | # General Kallithea URL handling |
|
64 | # General Kallithea URL handling | |
30 | # |
|
65 | # | |
@@ -75,3 +110,149 b' def canonical_hostname():' | |||||
75 | except IndexError: |
|
110 | except IndexError: | |
76 | parts = url('home', qualified=True).split('://', 1) |
|
111 | parts = url('home', qualified=True).split('://', 1) | |
77 | return parts[1].split('/', 1)[0] |
|
112 | return parts[1].split('/', 1)[0] | |
|
113 | ||||
|
114 | ||||
|
115 | # | |||
|
116 | # Custom Webhelpers2 stuff | |||
|
117 | # | |||
|
118 | ||||
|
119 | def html_escape(s): | |||
|
120 | """Return string with all html escaped. | |||
|
121 | This is also safe for javascript in html but not necessarily correct. | |||
|
122 | """ | |||
|
123 | return (s | |||
|
124 | .replace('&', '&') | |||
|
125 | .replace(">", ">") | |||
|
126 | .replace("<", "<") | |||
|
127 | .replace('"', """) | |||
|
128 | .replace("'", "'") # Note: this is HTML5 not HTML4 and might not work in mails | |||
|
129 | ) | |||
|
130 | ||||
|
131 | ||||
|
132 | def reset(name, value, id=NotGiven, **attrs): | |||
|
133 | """Create a reset button, similar to webhelpers2.html.tags.submit .""" | |||
|
134 | return _input("reset", name, value, id, attrs) | |||
|
135 | ||||
|
136 | ||||
|
137 | def select(name, selected_values, options, id=NotGiven, **attrs): | |||
|
138 | """Convenient wrapper of webhelpers2 to let it accept options as a tuple list""" | |||
|
139 | if isinstance(options, list): | |||
|
140 | option_list = options | |||
|
141 | # Handle old value,label lists ... where value also can be value,label lists | |||
|
142 | options = Options() | |||
|
143 | for x in option_list: | |||
|
144 | if isinstance(x, tuple) and len(x) == 2: | |||
|
145 | value, label = x | |||
|
146 | elif isinstance(x, str): | |||
|
147 | value = label = x | |||
|
148 | else: | |||
|
149 | log.error('invalid select option %r', x) | |||
|
150 | raise | |||
|
151 | if isinstance(value, list): | |||
|
152 | og = options.add_optgroup(label) | |||
|
153 | for x in value: | |||
|
154 | if isinstance(x, tuple) and len(x) == 2: | |||
|
155 | group_value, group_label = x | |||
|
156 | elif isinstance(x, str): | |||
|
157 | group_value = group_label = x | |||
|
158 | else: | |||
|
159 | log.error('invalid select option %r', x) | |||
|
160 | raise | |||
|
161 | og.add_option(group_label, group_value) | |||
|
162 | else: | |||
|
163 | options.add_option(label, value) | |||
|
164 | return webhelpers2_select(name, selected_values, options, id=id, **attrs) | |||
|
165 | ||||
|
166 | ||||
|
167 | session_csrf_secret_name = "_session_csrf_secret_token" | |||
|
168 | ||||
|
169 | def session_csrf_secret_token(): | |||
|
170 | """Return (and create) the current session's CSRF protection token.""" | |||
|
171 | if not session_csrf_secret_name in session: | |||
|
172 | session[session_csrf_secret_name] = str(random.getrandbits(128)) | |||
|
173 | session.save() | |||
|
174 | return session[session_csrf_secret_name] | |||
|
175 | ||||
|
176 | def form(url, method="post", **attrs): | |||
|
177 | """Like webhelpers.html.tags.form , but automatically adding | |||
|
178 | session_csrf_secret_token for POST. The secret is thus never leaked in GET | |||
|
179 | URLs. | |||
|
180 | """ | |||
|
181 | form = insecure_form(url, method, **attrs) | |||
|
182 | if method.lower() == 'get': | |||
|
183 | return form | |||
|
184 | return form + HTML.div(hidden(session_csrf_secret_name, session_csrf_secret_token()), style="display: none;") | |||
|
185 | ||||
|
186 | ||||
|
187 | # | |||
|
188 | # Flash messages, stored in cookie | |||
|
189 | # | |||
|
190 | ||||
|
191 | class _Message(object): | |||
|
192 | """A message returned by ``pop_flash_messages()``. | |||
|
193 | ||||
|
194 | Converting the message to a string returns the message text. Instances | |||
|
195 | also have the following attributes: | |||
|
196 | ||||
|
197 | * ``category``: the category specified when the message was created. | |||
|
198 | * ``message``: the html-safe message text. | |||
|
199 | """ | |||
|
200 | ||||
|
201 | def __init__(self, category, message): | |||
|
202 | self.category = category | |||
|
203 | self.message = message | |||
|
204 | ||||
|
205 | ||||
|
206 | def _session_flash_messages(append=None, clear=False): | |||
|
207 | """Manage a message queue in tg.session: return the current message queue | |||
|
208 | after appending the given message, and possibly clearing the queue.""" | |||
|
209 | key = 'flash' | |||
|
210 | if key in session: | |||
|
211 | flash_messages = session[key] | |||
|
212 | else: | |||
|
213 | if append is None: # common fast path - also used for clearing empty queue | |||
|
214 | return [] # don't bother saving | |||
|
215 | flash_messages = [] | |||
|
216 | session[key] = flash_messages | |||
|
217 | if append is not None and append not in flash_messages: | |||
|
218 | flash_messages.append(append) | |||
|
219 | if clear: | |||
|
220 | session.pop(key, None) | |||
|
221 | session.save() | |||
|
222 | return flash_messages | |||
|
223 | ||||
|
224 | ||||
|
225 | def flash(message, category, logf=None): | |||
|
226 | """ | |||
|
227 | Show a message to the user _and_ log it through the specified function | |||
|
228 | ||||
|
229 | category: notice (default), warning, error, success | |||
|
230 | logf: a custom log function - such as log.debug | |||
|
231 | ||||
|
232 | logf defaults to log.info, unless category equals 'success', in which | |||
|
233 | case logf defaults to log.debug. | |||
|
234 | """ | |||
|
235 | assert category in ('error', 'success', 'warning'), category | |||
|
236 | if hasattr(message, '__html__'): | |||
|
237 | # render to HTML for storing in cookie | |||
|
238 | safe_message = str(message) | |||
|
239 | else: | |||
|
240 | # Apply str - the message might be an exception with __str__ | |||
|
241 | # Escape, so we can trust the result without further escaping, without any risk of injection | |||
|
242 | safe_message = html_escape(str(message)) | |||
|
243 | if logf is None: | |||
|
244 | logf = log.info | |||
|
245 | if category == 'success': | |||
|
246 | logf = log.debug | |||
|
247 | ||||
|
248 | logf('Flash %s: %s', category, safe_message) | |||
|
249 | ||||
|
250 | _session_flash_messages(append=(category, safe_message)) | |||
|
251 | ||||
|
252 | ||||
|
253 | def pop_flash_messages(): | |||
|
254 | """Return all accumulated messages and delete them from the session. | |||
|
255 | ||||
|
256 | The return value is a list of ``Message`` objects. | |||
|
257 | """ | |||
|
258 | return [_Message(category, message) for category, message in _session_flash_messages(clear=True)] |
@@ -81,7 +81,7 b' class ChangesetCommentsModel(object):' | |||||
81 | repo_name=repo.repo_name, |
|
81 | repo_name=repo.repo_name, | |
82 | revision=revision, |
|
82 | revision=revision, | |
83 | anchor='comment-%s' % comment.comment_id) |
|
83 | anchor='comment-%s' % comment.comment_id) | |
84 |
subj = |
|
84 | subj = webutils.link_to( | |
85 | 'Re changeset: %(desc)s %(line)s' % |
|
85 | 'Re changeset: %(desc)s %(line)s' % | |
86 | {'desc': desc, 'line': line}, |
|
86 | {'desc': desc, 'line': line}, | |
87 | comment_url) |
|
87 | comment_url) | |
@@ -127,7 +127,7 b' class ChangesetCommentsModel(object):' | |||||
127 | webutils.canonical_hostname())) |
|
127 | webutils.canonical_hostname())) | |
128 | comment_url = pull_request.url(canonical=True, |
|
128 | comment_url = pull_request.url(canonical=True, | |
129 | anchor='comment-%s' % comment.comment_id) |
|
129 | anchor='comment-%s' % comment.comment_id) | |
130 |
subj = |
|
130 | subj = webutils.link_to( | |
131 | 'Re pull request %(pr_nice_id)s: %(desc)s %(line)s' % |
|
131 | 'Re pull request %(pr_nice_id)s: %(desc)s %(line)s' % | |
132 | {'desc': desc, |
|
132 | {'desc': desc, | |
133 | 'pr_nice_id': comment.pull_request.nice_id(), |
|
133 | 'pr_nice_id': comment.pull_request.nice_id(), |
@@ -1306,9 +1306,8 b' class Repository(meta.Base, BaseDbModel)' | |||||
1306 | return grouped |
|
1306 | return grouped | |
1307 |
|
1307 | |||
1308 | def _repo_size(self): |
|
1308 | def _repo_size(self): | |
1309 | from kallithea.lib import helpers as h |
|
|||
1310 | log.debug('calculating repository size...') |
|
1309 | log.debug('calculating repository size...') | |
1311 |
return |
|
1310 | return webutils.format_byte_size(self.scm_instance.size) | |
1312 |
|
1311 | |||
1313 | #========================================================================== |
|
1312 | #========================================================================== | |
1314 | # SCM CACHE INSTANCE |
|
1313 | # SCM CACHE INSTANCE | |
@@ -1397,10 +1396,9 b' class RepoGroup(meta.Base, BaseDbModel):' | |||||
1397 | @classmethod |
|
1396 | @classmethod | |
1398 | def _generate_choice(cls, repo_group): |
|
1397 | def _generate_choice(cls, repo_group): | |
1399 | """Return tuple with group_id and name as html literal""" |
|
1398 | """Return tuple with group_id and name as html literal""" | |
1400 | from webhelpers2.html import literal |
|
|||
1401 | if repo_group is None: |
|
1399 | if repo_group is None: | |
1402 | return (-1, '-- %s --' % _('top level')) |
|
1400 | return (-1, '-- %s --' % _('top level')) | |
1403 | return repo_group.group_id, literal(cls.SEP.join(repo_group.full_path_splitted)) |
|
1401 | return repo_group.group_id, webutils.literal(cls.SEP.join(repo_group.full_path_splitted)) | |
1404 |
|
1402 | |||
1405 | @classmethod |
|
1403 | @classmethod | |
1406 | def groups_choices(cls, groups): |
|
1404 | def groups_choices(cls, groups): |
@@ -82,7 +82,7 b' class PullRequestModel(object):' | |||||
82 | threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name, |
|
82 | threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name, | |
83 | pr.pull_request_id, |
|
83 | pr.pull_request_id, | |
84 | webutils.canonical_hostname())] |
|
84 | webutils.canonical_hostname())] | |
85 |
subject = |
|
85 | subject = webutils.link_to( | |
86 | _('%(user)s wants you to review pull request %(pr_nice_id)s: %(pr_title)s') % |
|
86 | _('%(user)s wants you to review pull request %(pr_nice_id)s: %(pr_title)s') % | |
87 | {'user': user.username, |
|
87 | {'user': user.username, | |
88 | 'pr_title': pr.title, |
|
88 | 'pr_title': pr.title, |
@@ -314,7 +314,6 b' class UserModel(object):' | |||||
314 | allowing users to copy-paste or manually enter the token from the |
|
314 | allowing users to copy-paste or manually enter the token from the | |
315 | email. |
|
315 | email. | |
316 | """ |
|
316 | """ | |
317 | import kallithea.lib.helpers as h |
|
|||
318 | from kallithea.lib.celerylib import tasks |
|
317 | from kallithea.lib.celerylib import tasks | |
319 | from kallithea.model.notification import EmailNotificationModel |
|
318 | from kallithea.model.notification import EmailNotificationModel | |
320 |
|
319 | |||
@@ -326,7 +325,7 b' class UserModel(object):' | |||||
326 | log.debug('password reset user %s found', user) |
|
325 | log.debug('password reset user %s found', user) | |
327 | token = self.get_reset_password_token(user, |
|
326 | token = self.get_reset_password_token(user, | |
328 | timestamp, |
|
327 | timestamp, | |
329 |
|
|
328 | webutils.session_csrf_secret_token()) | |
330 | # URL must be fully qualified; but since the token is locked to |
|
329 | # URL must be fully qualified; but since the token is locked to | |
331 | # the current browser session, we must provide a URL with the |
|
330 | # the current browser session, we must provide a URL with the | |
332 | # current scheme and hostname, rather than the canonical_url. |
|
331 | # current scheme and hostname, rather than the canonical_url. | |
@@ -359,7 +358,6 b' class UserModel(object):' | |||||
359 | timestamp=timestamp) |
|
358 | timestamp=timestamp) | |
360 |
|
359 | |||
361 | def verify_reset_password_token(self, email, timestamp, token): |
|
360 | def verify_reset_password_token(self, email, timestamp, token): | |
362 | import kallithea.lib.helpers as h |
|
|||
363 | user = db.User.get_by_email(email) |
|
361 | user = db.User.get_by_email(email) | |
364 | if user is None: |
|
362 | if user is None: | |
365 | log.debug("user with email %s not found", email) |
|
363 | log.debug("user with email %s not found", email) | |
@@ -377,7 +375,7 b' class UserModel(object):' | |||||
377 |
|
375 | |||
378 | expected_token = self.get_reset_password_token(user, |
|
376 | expected_token = self.get_reset_password_token(user, | |
379 | timestamp, |
|
377 | timestamp, | |
380 |
|
|
378 | webutils.session_csrf_secret_token()) | |
381 | log.debug('computed password reset token: %s', expected_token) |
|
379 | log.debug('computed password reset token: %s', expected_token) | |
382 | log.debug('received password reset token: %s', token) |
|
380 | log.debug('received password reset token: %s', token) | |
383 | return expected_token == token |
|
381 | return expected_token == token |
@@ -19,7 +19,7 b' from webob.exc import HTTPNotFound' | |||||
19 |
|
19 | |||
20 | import kallithea |
|
20 | import kallithea | |
21 | from kallithea.controllers.admin.users import UsersController |
|
21 | from kallithea.controllers.admin.users import UsersController | |
22 |
from kallithea.lib import |
|
22 | from kallithea.lib import webutils | |
23 | from kallithea.lib.auth import check_password |
|
23 | from kallithea.lib.auth import check_password | |
24 | from kallithea.model import db, meta, validators |
|
24 | from kallithea.model import db, meta, validators | |
25 | from kallithea.model.user import UserModel |
|
25 | from kallithea.model.user import UserModel | |
@@ -112,7 +112,7 b' class TestAdminUsersController(base.Test' | |||||
112 |
|
112 | |||
113 | with test_context(self.app): |
|
113 | with test_context(self.app): | |
114 | msg = validators.ValidUsername(False, {})._messages['system_invalid_username'] |
|
114 | msg = validators.ValidUsername(False, {})._messages['system_invalid_username'] | |
115 |
msg = |
|
115 | msg = webutils.html_escape(msg % {'username': 'new_user'}) | |
116 | response.mustcontain("""<span class="error-message">%s</span>""" % msg) |
|
116 | response.mustcontain("""<span class="error-message">%s</span>""" % msg) | |
117 | response.mustcontain("""<span class="error-message">Please enter a value</span>""") |
|
117 | response.mustcontain("""<span class="error-message">Please enter a value</span>""") | |
118 | response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""") |
|
118 | response.mustcontain("""<span class="error-message">An email address must contain a single @</span>""") | |
@@ -569,7 +569,7 b' class TestAdminUsersController_unittest(' | |||||
569 | # flash complains about an non-existing session |
|
569 | # flash complains about an non-existing session | |
570 | def flash_mock(*args, **kwargs): |
|
570 | def flash_mock(*args, **kwargs): | |
571 | pass |
|
571 | pass | |
572 |
monkeypatch.setattr( |
|
572 | monkeypatch.setattr(webutils, 'flash', flash_mock) | |
573 |
|
573 | |||
574 | u = UsersController() |
|
574 | u = UsersController() | |
575 | # a regular user should work correctly |
|
575 | # a regular user should work correctly |
@@ -7,7 +7,7 b' import mock' | |||||
7 | from tg.util.webtest import test_context |
|
7 | from tg.util.webtest import test_context | |
8 |
|
8 | |||
9 | import kallithea.lib.celerylib.tasks |
|
9 | import kallithea.lib.celerylib.tasks | |
10 |
from kallithea.lib import |
|
10 | from kallithea.lib import webutils | |
11 | from kallithea.lib.auth import check_password |
|
11 | from kallithea.lib.auth import check_password | |
12 | from kallithea.lib.utils2 import generate_api_key |
|
12 | from kallithea.lib.utils2 import generate_api_key | |
13 | from kallithea.model import db, meta, validators |
|
13 | from kallithea.model import db, meta, validators | |
@@ -238,7 +238,7 b' class TestLoginController(base.TestContr' | |||||
238 |
|
238 | |||
239 | with test_context(self.app): |
|
239 | with test_context(self.app): | |
240 | msg = validators.ValidUsername()._messages['username_exists'] |
|
240 | msg = validators.ValidUsername()._messages['username_exists'] | |
241 |
msg = |
|
241 | msg = webutils.html_escape(msg % {'username': uname}) | |
242 | response.mustcontain(msg) |
|
242 | response.mustcontain(msg) | |
243 |
|
243 | |||
244 | def test_register_err_same_email(self): |
|
244 | def test_register_err_same_email(self): | |
@@ -311,7 +311,7 b' class TestLoginController(base.TestContr' | |||||
311 | response.mustcontain('An email address must contain a single @') |
|
311 | response.mustcontain('An email address must contain a single @') | |
312 | with test_context(self.app): |
|
312 | with test_context(self.app): | |
313 | msg = validators.ValidUsername()._messages['username_exists'] |
|
313 | msg = validators.ValidUsername()._messages['username_exists'] | |
314 |
msg = |
|
314 | msg = webutils.html_escape(msg % {'username': usr}) | |
315 | response.mustcontain(msg) |
|
315 | response.mustcontain(msg) | |
316 |
|
316 | |||
317 | def test_register_special_chars(self): |
|
317 | def test_register_special_chars(self): |
@@ -2,7 +2,7 b'' | |||||
2 |
|
2 | |||
3 | from tg.util.webtest import test_context |
|
3 | from tg.util.webtest import test_context | |
4 |
|
4 | |||
5 |
from kallithea.lib import |
|
5 | from kallithea.lib import webutils | |
6 | from kallithea.model import db, meta |
|
6 | from kallithea.model import db, meta | |
7 | from kallithea.model.user import UserModel |
|
7 | from kallithea.model.user import UserModel | |
8 | from kallithea.tests import base |
|
8 | from kallithea.tests import base | |
@@ -186,7 +186,7 b' class TestMyAccountController(base.TestC' | |||||
186 | with test_context(self.app): |
|
186 | with test_context(self.app): | |
187 | msg = validators.ValidUsername(edit=False, old_data={}) \ |
|
187 | msg = validators.ValidUsername(edit=False, old_data={}) \ | |
188 | ._messages['username_exists'] |
|
188 | ._messages['username_exists'] | |
189 |
msg = |
|
189 | msg = webutils.html_escape(msg % {'username': base.TEST_USER_ADMIN_LOGIN}) | |
190 | response.mustcontain(msg) |
|
190 | response.mustcontain(msg) | |
191 |
|
191 | |||
192 | def test_my_account_api_keys(self): |
|
192 | def test_my_account_api_keys(self): |
General Comments 0
You need to be logged in to leave comments.
Login now