diff --git a/kallithea/controllers/admin/auth_settings.py b/kallithea/controllers/admin/auth_settings.py --- a/kallithea/controllers/admin/auth_settings.py +++ b/kallithea/controllers/admin/auth_settings.py @@ -32,8 +32,7 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPFound -from kallithea.lib import auth_modules -from kallithea.lib import helpers as h +from kallithea.lib import auth_modules, webutils from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired from kallithea.lib.base import BaseController, render from kallithea.lib.webutils import url @@ -132,7 +131,7 @@ class AuthSettingsController(BaseControl log.debug("%s = %s", k, str(v)) setting = db.Setting.create_or_update(k, v) meta.Session().commit() - h.flash(_('Auth settings updated successfully'), + webutils.flash(_('Auth settings updated successfully'), category='success') except formencode.Invalid as errors: log.error(traceback.format_exc()) @@ -143,7 +142,7 @@ class AuthSettingsController(BaseControl ) except Exception: log.error(traceback.format_exc()) - h.flash(_('error occurred during update of auth settings'), + webutils.flash(_('error occurred during update of auth settings'), category='error') raise HTTPFound(location=url('auth_home')) diff --git a/kallithea/controllers/admin/defaults.py b/kallithea/controllers/admin/defaults.py --- a/kallithea/controllers/admin/defaults.py +++ b/kallithea/controllers/admin/defaults.py @@ -34,7 +34,7 @@ from tg import request from tg.i18n import ugettext as _ from webob.exc import HTTPFound -from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired from kallithea.lib.base import BaseController, render from kallithea.lib.webutils import url @@ -70,7 +70,7 @@ class DefaultsController(BaseController) for k, v in form_result.items(): setting = db.Setting.create_or_update(k, v) meta.Session().commit() - h.flash(_('Default settings updated successfully'), + webutils.flash(_('Default settings updated successfully'), category='success') except formencode.Invalid as errors: @@ -85,7 +85,7 @@ class DefaultsController(BaseController) force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of defaults'), + webutils.flash(_('Error occurred during update of defaults'), category='error') raise HTTPFound(location=url('defaults')) diff --git a/kallithea/controllers/admin/gists.py b/kallithea/controllers/admin/gists.py --- a/kallithea/controllers/admin/gists.py +++ b/kallithea/controllers/admin/gists.py @@ -35,8 +35,7 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPForbidden, HTTPFound, HTTPNotFound -from kallithea.lib import auth -from kallithea.lib import helpers as h +from kallithea.lib import auth, webutils from kallithea.lib.auth import LoginRequired from kallithea.lib.base import BaseController, jsonify, render from kallithea.lib.page import Page @@ -144,7 +143,7 @@ class GistsController(BaseController): except Exception as e: log.error(traceback.format_exc()) - h.flash(_('Error occurred during gist creation'), category='error') + webutils.flash(_('Error occurred during gist creation'), category='error') raise HTTPFound(location=url('new_gist')) raise HTTPFound(location=url('gist', gist_id=new_gist_id)) @@ -160,7 +159,7 @@ class GistsController(BaseController): if auth.HasPermissionAny('hg.admin')() or owner: GistModel().delete(gist) meta.Session().commit() - h.flash(_('Deleted gist %s') % gist.gist_access_id, category='success') + webutils.flash(_('Deleted gist %s') % gist.gist_access_id, category='success') else: raise HTTPForbidden() @@ -233,15 +232,15 @@ class GistsController(BaseController): ) meta.Session().commit() - h.flash(_('Successfully updated gist content'), category='success') + webutils.flash(_('Successfully updated gist content'), category='success') except NodeNotChangedError: # raised if nothing was changed in repo itself. We anyway then # store only DB stuff for gist meta.Session().commit() - h.flash(_('Successfully updated gist data'), category='success') + webutils.flash(_('Successfully updated gist data'), category='success') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of gist %s') % gist_id, + webutils.flash(_('Error occurred during update of gist %s') % gist_id, category='error') raise HTTPFound(location=url('gist', gist_id=gist_id)) diff --git a/kallithea/controllers/admin/my_account.py b/kallithea/controllers/admin/my_account.py --- a/kallithea/controllers/admin/my_account.py +++ b/kallithea/controllers/admin/my_account.py @@ -35,8 +35,7 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPFound -from kallithea.lib import auth_modules -from kallithea.lib import helpers as h +from kallithea.lib import auth_modules, webutils from kallithea.lib.auth import AuthUser, LoginRequired from kallithea.lib.base import BaseController, IfSshEnabled, render from kallithea.lib.utils2 import generate_api_key, safe_int @@ -61,7 +60,7 @@ class MyAccountController(BaseController def __load_data(self): c.user = db.User.get(request.authuser.user_id) if c.user.is_default_user: - h.flash(_("You can't edit this user since it's" + webutils.flash(_("You can't edit this user since it's" " crucial for entire application"), category='warning') raise HTTPFound(location=url('users')) @@ -110,7 +109,7 @@ class MyAccountController(BaseController UserModel().update(request.authuser.user_id, form_result, skip_attrs=skip_attrs) - h.flash(_('Your account was updated successfully'), + webutils.flash(_('Your account was updated successfully'), category='success') meta.Session().commit() update = True @@ -125,7 +124,7 @@ class MyAccountController(BaseController force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of user %s') + webutils.flash(_('Error occurred during update of user %s') % form_result.get('username'), category='error') if update: raise HTTPFound(location='my_account') @@ -148,7 +147,7 @@ class MyAccountController(BaseController form_result = _form.to_python(request.POST) UserModel().update(request.authuser.user_id, form_result) meta.Session().commit() - h.flash(_("Successfully updated password"), category='success') + webutils.flash(_("Successfully updated password"), category='success') except formencode.Invalid as errors: return htmlfill.render( render('admin/my_account/my_account.html'), @@ -159,7 +158,7 @@ class MyAccountController(BaseController force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of user password'), + webutils.flash(_('Error occurred during update of user password'), category='error') return render('admin/my_account/my_account.html') @@ -200,13 +199,13 @@ class MyAccountController(BaseController try: UserModel().add_extra_email(request.authuser.user_id, email) meta.Session().commit() - h.flash(_("Added email %s to user") % email, category='success') + webutils.flash(_("Added email %s to user") % email, category='success') except formencode.Invalid as error: msg = error.error_dict['email'] - h.flash(msg, category='error') + webutils.flash(msg, category='error') except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during email saving'), + webutils.flash(_('An error occurred during email saving'), category='error') raise HTTPFound(location=url('my_account_emails')) @@ -215,7 +214,7 @@ class MyAccountController(BaseController user_model = UserModel() user_model.delete_extra_email(request.authuser.user_id, email_id) meta.Session().commit() - h.flash(_("Removed email from user"), category='success') + webutils.flash(_("Removed email from user"), category='success') raise HTTPFound(location=url('my_account_emails')) def my_account_api_keys(self): @@ -239,7 +238,7 @@ class MyAccountController(BaseController description = request.POST.get('description') ApiKeyModel().create(request.authuser.user_id, description, lifetime) meta.Session().commit() - h.flash(_("API key successfully created"), category='success') + webutils.flash(_("API key successfully created"), category='success') raise HTTPFound(location=url('my_account_api_keys')) def my_account_api_keys_delete(self): @@ -248,11 +247,11 @@ class MyAccountController(BaseController user = db.User.get(request.authuser.user_id) user.api_key = generate_api_key() meta.Session().commit() - h.flash(_("API key successfully reset"), category='success') + webutils.flash(_("API key successfully reset"), category='success') elif api_key: ApiKeyModel().delete(api_key, request.authuser.user_id) meta.Session().commit() - h.flash(_("API key successfully deleted"), category='success') + webutils.flash(_("API key successfully deleted"), category='success') raise HTTPFound(location=url('my_account_api_keys')) @@ -272,9 +271,9 @@ class MyAccountController(BaseController description, public_key) meta.Session().commit() SshKeyModel().write_authorized_keys() - h.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success') + webutils.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success') except SshKeyModelException as e: - h.flash(e.args[0], category='error') + webutils.flash(e.args[0], category='error') raise HTTPFound(location=url('my_account_ssh_keys')) @IfSshEnabled @@ -284,7 +283,7 @@ class MyAccountController(BaseController SshKeyModel().delete(fingerprint, request.authuser.user_id) meta.Session().commit() SshKeyModel().write_authorized_keys() - h.flash(_("SSH key successfully deleted"), category='success') + webutils.flash(_("SSH key successfully deleted"), category='success') except SshKeyModelException as e: - h.flash(e.args[0], category='error') + webutils.flash(e.args[0], category='error') raise HTTPFound(location=url('my_account_ssh_keys')) diff --git a/kallithea/controllers/admin/permissions.py b/kallithea/controllers/admin/permissions.py --- a/kallithea/controllers/admin/permissions.py +++ b/kallithea/controllers/admin/permissions.py @@ -36,7 +36,7 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPFound -from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired from kallithea.lib.base import BaseController, render from kallithea.lib.webutils import url @@ -113,7 +113,7 @@ class PermissionsController(BaseControll form_result.update({'perm_user_name': 'default'}) PermissionModel().update(form_result) meta.Session().commit() - h.flash(_('Global permissions updated successfully'), + webutils.flash(_('Global permissions updated successfully'), category='success') except formencode.Invalid as errors: @@ -128,7 +128,7 @@ class PermissionsController(BaseControll force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of permissions'), + webutils.flash(_('Error occurred during update of permissions'), category='error') raise HTTPFound(location=url('admin_permissions')) diff --git a/kallithea/controllers/admin/repo_groups.py b/kallithea/controllers/admin/repo_groups.py --- a/kallithea/controllers/admin/repo_groups.py +++ b/kallithea/controllers/admin/repo_groups.py @@ -37,6 +37,7 @@ from tg.i18n import ungettext from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoGroupPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseController, render from kallithea.lib.utils2 import safe_int @@ -118,7 +119,7 @@ class RepoGroupsController(BaseControlle repo_groups_data.append({ "raw_name": repo_gr.group_name, "group_name": repo_group_name(repo_gr.group_name, children_groups), - "desc": h.escape(repo_gr.group_description), + "desc": webutils.escape(repo_gr.group_description), "repos": repo_count, "owner": h.person(repo_gr.owner), "action": repo_group_actions(repo_gr.group_id, repo_gr.group_name, @@ -161,14 +162,14 @@ class RepoGroupsController(BaseControlle force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during creation of repository group %s') + webutils.flash(_('Error occurred during creation of repository group %s') % request.POST.get('group_name'), category='error') if form_result is None: raise parent_group_id = form_result['parent_group_id'] # TODO: maybe we should get back to the main view, not the admin one raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id)) - h.flash(_('Created repository group %s') % gr.group_name, + webutils.flash(_('Created repository group %s') % gr.group_name, category='success') raise HTTPFound(location=url('repos_group_home', group_name=gr.group_name)) @@ -215,7 +216,7 @@ class RepoGroupsController(BaseControlle new_gr = RepoGroupModel().update(group_name, form_result) meta.Session().commit() - h.flash(_('Updated repository group %s') + webutils.flash(_('Updated repository group %s') % form_result['group_name'], category='success') # we now have new name ! group_name = new_gr.group_name @@ -231,7 +232,7 @@ class RepoGroupsController(BaseControlle force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of repository group %s') + webutils.flash(_('Error occurred during update of repository group %s') % request.POST.get('group_name'), category='error') raise HTTPFound(location=url('edit_repo_group', group_name=group_name)) @@ -241,25 +242,25 @@ class RepoGroupsController(BaseControlle gr = c.repo_group = db.RepoGroup.guess_instance(group_name) repos = gr.repositories.all() if repos: - h.flash(_('This group contains %s repositories and cannot be ' + webutils.flash(_('This group contains %s repositories and cannot be ' 'deleted') % len(repos), category='warning') raise HTTPFound(location=url('repos_groups')) children = gr.children.all() if children: - h.flash(_('This group contains %s subgroups and cannot be deleted' + webutils.flash(_('This group contains %s subgroups and cannot be deleted' % (len(children))), category='warning') raise HTTPFound(location=url('repos_groups')) try: RepoGroupModel().delete(group_name) meta.Session().commit() - h.flash(_('Removed repository group %s') % group_name, + webutils.flash(_('Removed repository group %s') % group_name, category='success') # TODO: in future action_logger(, '', '', '') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during deletion of repository group %s') + webutils.flash(_('Error occurred during deletion of repository group %s') % group_name, category='error') if gr.parent_group: @@ -344,7 +345,7 @@ class RepoGroupsController(BaseControlle if not request.authuser.is_admin: if self._revoke_perms_on_yourself(form_result): msg = _('Cannot revoke permission for yourself as admin') - h.flash(msg, category='warning') + webutils.flash(msg, category='warning') raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name)) recursive = form_result['recursive'] # iterate over all members(if in recursive mode) of this groups and @@ -358,7 +359,7 @@ class RepoGroupsController(BaseControlle #action_logger(request.authuser, 'admin_changed_repo_permissions', # repo_name, request.ip_addr) meta.Session().commit() - h.flash(_('Repository group permissions updated'), category='success') + webutils.flash(_('Repository group permissions updated'), category='success') raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name)) @HasRepoGroupPermissionLevelDecorator('admin') @@ -374,7 +375,7 @@ class RepoGroupsController(BaseControlle if not request.authuser.is_admin: if obj_type == 'user' and request.authuser.user_id == obj_id: msg = _('Cannot revoke permission for yourself as admin') - h.flash(msg, category='warning') + webutils.flash(msg, category='warning') raise Exception('revoke admin permission on self') recursive = request.POST.get('recursive', 'none') if obj_type == 'user': @@ -390,6 +391,6 @@ class RepoGroupsController(BaseControlle meta.Session().commit() except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during revoking of permission'), + webutils.flash(_('An error occurred during revoking of permission'), category='error') raise HTTPInternalServerError() diff --git a/kallithea/controllers/admin/repos.py b/kallithea/controllers/admin/repos.py --- a/kallithea/controllers/admin/repos.py +++ b/kallithea/controllers/admin/repos.py @@ -37,7 +37,6 @@ from tg.i18n import ugettext as _ from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound import kallithea -from kallithea.lib import helpers as h from kallithea.lib import webutils from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired, NotAnonymous from kallithea.lib.base import BaseRepoController, jsonify, render @@ -125,7 +124,7 @@ class ReposController(BaseRepoController log.error(traceback.format_exc()) msg = (_('Error creating repository %s') % form_result.get('repo_name')) - h.flash(msg, category='error') + webutils.flash(msg, category='error') raise HTTPFound(location=url('home')) raise HTTPFound(location=webutils.url('repo_creating_home', @@ -179,19 +178,19 @@ class ReposController(BaseRepoController repo = db.Repository.get_by_repo_name(repo_name) if repo and repo.repo_state == db.Repository.STATE_CREATED: if repo.clone_uri: - h.flash(_('Created repository %s from %s') + webutils.flash(_('Created repository %s from %s') % (repo.repo_name, repo.clone_uri_hidden), category='success') else: - repo_url = h.link_to(repo.repo_name, + repo_url = webutils.link_to(repo.repo_name, webutils.url('summary_home', repo_name=repo.repo_name)) fork = repo.fork if fork is not None: fork_name = fork.repo_name - h.flash(h.HTML(_('Forked repository %s as %s')) + webutils.flash(webutils.HTML(_('Forked repository %s as %s')) % (fork_name, repo_url), category='success') else: - h.flash(h.HTML(_('Created repository %s')) % repo_url, + webutils.flash(webutils.HTML(_('Created repository %s')) % repo_url, category='success') return {'result': True} return {'result': False} @@ -220,7 +219,7 @@ class ReposController(BaseRepoController form_result = _form.to_python(dict(request.POST)) repo = repo_model.update(repo_name, **form_result) ScmModel().mark_for_invalidation(repo_name) - h.flash(_('Repository %s updated successfully') % repo_name, + webutils.flash(_('Repository %s updated successfully') % repo_name, category='success') changed_name = repo.repo_name action_logger(request.authuser, 'admin_updated_repo', @@ -240,7 +239,7 @@ class ReposController(BaseRepoController except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of repository %s') + webutils.flash(_('Error occurred during update of repository %s') % repo_name, category='error') raise HTTPFound(location=url('edit_repo', repo_name=changed_name)) @@ -257,23 +256,23 @@ class ReposController(BaseRepoController do = request.POST['forks'] if do == 'detach_forks': handle_forks = 'detach' - h.flash(_('Detached %s forks') % _forks, category='success') + webutils.flash(_('Detached %s forks') % _forks, category='success') elif do == 'delete_forks': handle_forks = 'delete' - h.flash(_('Deleted %s forks') % _forks, category='success') + webutils.flash(_('Deleted %s forks') % _forks, category='success') repo_model.delete(repo, forks=handle_forks) action_logger(request.authuser, 'admin_deleted_repo', repo_name, request.ip_addr) ScmModel().mark_for_invalidation(repo_name) - h.flash(_('Deleted repository %s') % repo_name, category='success') + webutils.flash(_('Deleted repository %s') % repo_name, category='success') meta.Session().commit() except AttachedForksError: - h.flash(_('Cannot delete repository %s which still has forks') + webutils.flash(_('Cannot delete repository %s which still has forks') % repo_name, category='warning') except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during deletion of %s') % repo_name, + webutils.flash(_('An error occurred during deletion of %s') % repo_name, category='error') if repo.group: @@ -313,7 +312,7 @@ class ReposController(BaseRepoController #action_logger(request.authuser, 'admin_changed_repo_permissions', # repo_name, request.ip_addr) meta.Session().commit() - h.flash(_('Repository permissions updated'), category='success') + webutils.flash(_('Repository permissions updated'), category='success') raise HTTPFound(location=url('edit_repo_perms', repo_name=repo_name)) @HasRepoPermissionLevelDecorator('admin') @@ -342,7 +341,7 @@ class ReposController(BaseRepoController meta.Session().commit() except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during revoking of permission'), + webutils.flash(_('An error occurred during revoking of permission'), category='error') raise HTTPInternalServerError() return [] @@ -372,10 +371,10 @@ class ReposController(BaseRepoController meta.Session().add(new_field) meta.Session().commit() except formencode.Invalid as e: - h.flash(_('Field validation error: %s') % e.msg, category='error') + webutils.flash(_('Field validation error: %s') % e.msg, category='error') except Exception as e: log.error(traceback.format_exc()) - h.flash(_('An error occurred during creation of field: %r') % e, category='error') + webutils.flash(_('An error occurred during creation of field: %r') % e, category='error') raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) @HasRepoPermissionLevelDecorator('admin') @@ -387,7 +386,7 @@ class ReposController(BaseRepoController except Exception as e: log.error(traceback.format_exc()) msg = _('An error occurred during removal of field') - h.flash(msg, category='error') + webutils.flash(msg, category='error') raise HTTPFound(location=url('edit_repo_fields', repo_name=repo_name)) @HasRepoPermissionLevelDecorator('admin') @@ -432,11 +431,11 @@ class ReposController(BaseRepoController repo_id = db.Repository.get_by_repo_name(repo_name).repo_id user_id = kallithea.DEFAULT_USER_ID self.scm_model.toggle_following_repo(repo_id, user_id) - h.flash(_('Updated repository visibility in public journal'), + webutils.flash(_('Updated repository visibility in public journal'), category='success') meta.Session().commit() except Exception: - h.flash(_('An error occurred during setting this' + webutils.flash(_('An error occurred during setting this' ' repository in public journal'), category='error') raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) @@ -454,14 +453,14 @@ class ReposController(BaseRepoController request.authuser.username) fork = repo.fork.repo_name if repo.fork else _('Nothing') meta.Session().commit() - h.flash(_('Marked repository %s as fork of %s') % (repo_name, fork), + webutils.flash(_('Marked repository %s as fork of %s') % (repo_name, fork), category='success') except RepositoryError as e: log.error(traceback.format_exc()) - h.flash(e, category='error') + webutils.flash(e, category='error') except Exception as e: log.error(traceback.format_exc()) - h.flash(_('An error occurred during this operation'), + webutils.flash(_('An error occurred during this operation'), category='error') raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) @@ -473,10 +472,10 @@ class ReposController(BaseRepoController if request.POST: try: ScmModel().pull_changes(repo_name, request.authuser.username, request.ip_addr) - h.flash(_('Pulled from remote location'), category='success') + webutils.flash(_('Pulled from remote location'), category='success') except Exception as e: log.error(traceback.format_exc()) - h.flash(_('An error occurred during pull from remote location'), + webutils.flash(_('An error occurred during pull from remote location'), category='error') raise HTTPFound(location=url('edit_repo_remote', repo_name=c.repo_name)) return render('admin/repos/repo_edit.html') @@ -507,7 +506,7 @@ class ReposController(BaseRepoController meta.Session().commit() except Exception as e: log.error(traceback.format_exc()) - h.flash(_('An error occurred during deletion of repository stats'), + webutils.flash(_('An error occurred during deletion of repository stats'), category='error') raise HTTPFound(location=url('edit_repo_statistics', repo_name=c.repo_name)) diff --git a/kallithea/controllers/admin/settings.py b/kallithea/controllers/admin/settings.py --- a/kallithea/controllers/admin/settings.py +++ b/kallithea/controllers/admin/settings.py @@ -35,7 +35,6 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPFound -from kallithea.lib import helpers as h from kallithea.lib import webutils from kallithea.lib.auth import HasPermissionAnyDecorator, LoginRequired from kallithea.lib.base import BaseController, render @@ -114,11 +113,11 @@ class SettingsController(BaseController) meta.Session().commit() - h.flash(_('Updated VCS settings'), category='success') + webutils.flash(_('Updated VCS settings'), category='success') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred while updating ' + webutils.flash(_('Error occurred while updating ' 'application settings'), category='error') defaults = db.Setting.get_app_settings() @@ -147,13 +146,13 @@ class SettingsController(BaseController) install_git_hooks=install_git_hooks, user=request.authuser.username, overwrite_git_hooks=overwrite_git_hooks) - added_msg = h.HTML(', ').join( - h.link_to(safe_str(repo_name), webutils.url('summary_home', repo_name=repo_name)) for repo_name in added + added_msg = webutils.HTML(', ').join( + webutils.link_to(safe_str(repo_name), webutils.url('summary_home', repo_name=repo_name)) for repo_name in added ) or '-' - removed_msg = h.HTML(', ').join( + removed_msg = webutils.HTML(', ').join( safe_str(repo_name) for repo_name in removed ) or '-' - h.flash(h.HTML(_('Repositories successfully rescanned. Added: %s. Removed: %s.')) % + webutils.flash(webutils.HTML(_('Repositories successfully rescanned. Added: %s. Removed: %s.')) % (added_msg, removed_msg), category='success') if invalidate_cache: @@ -165,7 +164,7 @@ class SettingsController(BaseController) i += 1 except VCSError as e: log.warning('VCS error invalidating %s: %s', repo.repo_name, e) - h.flash(_('Invalidated %s repositories') % i, category='success') + webutils.flash(_('Invalidated %s repositories') % i, category='success') raise HTTPFound(location=url('admin_settings_mapping')) @@ -206,11 +205,11 @@ class SettingsController(BaseController) meta.Session().commit() set_app_settings(config) - h.flash(_('Updated application settings'), category='success') + webutils.flash(_('Updated application settings'), category='success') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred while updating ' + webutils.flash(_('Error occurred while updating ' 'application settings'), category='error') @@ -260,12 +259,12 @@ class SettingsController(BaseController) meta.Session().commit() set_app_settings(config) - h.flash(_('Updated visualisation settings'), + webutils.flash(_('Updated visualisation settings'), category='success') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during updating ' + webutils.flash(_('Error occurred during updating ' 'visualisation settings'), category='error') @@ -289,7 +288,7 @@ class SettingsController(BaseController) test_body = ('Kallithea Email test, ' 'Kallithea version: %s' % c.kallithea_version) if not test_email: - h.flash(_('Please enter email address'), category='error') + webutils.flash(_('Please enter email address'), category='error') raise HTTPFound(location=url('admin_settings_email')) test_email_txt_body = EmailNotificationModel() \ @@ -304,7 +303,7 @@ class SettingsController(BaseController) tasks.send_email(recipients, test_email_subj, test_email_txt_body, test_email_html_body) - h.flash(_('Send email task created'), category='success') + webutils.flash(_('Send email task created'), category='success') raise HTTPFound(location=url('admin_settings_email')) defaults = db.Setting.get_app_settings() @@ -332,12 +331,12 @@ class SettingsController(BaseController) try: ui_key = ui_key and ui_key.strip() if ui_key in (x.ui_key for x in db.Ui.get_custom_hooks()): - h.flash(_('Hook already exists'), category='error') + webutils.flash(_('Hook already exists'), category='error') elif ui_key in (x.ui_key for x in db.Ui.get_builtin_hooks()): - h.flash(_('Builtin hooks are read-only. Please use another hook name.'), category='error') + webutils.flash(_('Builtin hooks are read-only. Please use another hook name.'), category='error') elif ui_value and ui_key: db.Ui.create_or_update_hook(ui_key, ui_value) - h.flash(_('Added new hook'), category='success') + webutils.flash(_('Added new hook'), category='success') elif hook_id: db.Ui.delete(hook_id) meta.Session().commit() @@ -353,11 +352,11 @@ class SettingsController(BaseController) update = True if update: - h.flash(_('Updated hooks'), category='success') + webutils.flash(_('Updated hooks'), category='success') meta.Session().commit() except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during hook creation'), + webutils.flash(_('Error occurred during hook creation'), category='error') raise HTTPFound(location=url('admin_settings_hooks')) @@ -381,7 +380,7 @@ class SettingsController(BaseController) repo_location = self._get_hg_ui_settings()['paths_root_path'] full_index = request.POST.get('full_index', False) tasks.whoosh_index(repo_location, full_index) - h.flash(_('Whoosh reindex task scheduled'), category='success') + webutils.flash(_('Whoosh reindex task scheduled'), category='success') raise HTTPFound(location=url('admin_settings_search')) defaults = db.Setting.get_app_settings() diff --git a/kallithea/controllers/admin/user_groups.py b/kallithea/controllers/admin/user_groups.py --- a/kallithea/controllers/admin/user_groups.py +++ b/kallithea/controllers/admin/user_groups.py @@ -38,6 +38,7 @@ from tg.i18n import ugettext as _ from webob.exc import HTTPFound, HTTPInternalServerError from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.auth import HasPermissionAnyDecorator, HasUserGroupPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseController, render from kallithea.lib.exceptions import RepoGroupAssignmentError, UserGroupsAssignedException @@ -100,7 +101,7 @@ class UserGroupsController(BaseControlle "raw_name": user_gr.users_group_name, "group_name": user_group_name(user_gr.users_group_id, user_gr.users_group_name), - "desc": h.escape(user_gr.user_group_description), + "desc": webutils.escape(user_gr.user_group_description), "members": len(user_gr.members), "active": h.boolicon(user_gr.users_group_active), "owner": h.person(user_gr.owner.username), @@ -129,7 +130,7 @@ class UserGroupsController(BaseControlle action_logger(request.authuser, 'admin_created_users_group:%s' % gr, None, request.ip_addr) - h.flash(h.HTML(_('Created user group %s')) % h.link_to(gr, url('edit_users_group', id=ug.users_group_id)), + webutils.flash(webutils.HTML(_('Created user group %s')) % webutils.link_to(gr, url('edit_users_group', id=ug.users_group_id)), category='success') meta.Session().commit() except formencode.Invalid as errors: @@ -142,7 +143,7 @@ class UserGroupsController(BaseControlle force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during creation of user group %s') + webutils.flash(_('Error occurred during creation of user group %s') % request.POST.get('users_group_name'), category='error') raise HTTPFound(location=url('users_groups')) @@ -170,7 +171,7 @@ class UserGroupsController(BaseControlle action_logger(request.authuser, 'admin_updated_users_group:%s' % gr, None, request.ip_addr) - h.flash(_('Updated user group %s') % gr, category='success') + webutils.flash(_('Updated user group %s') % gr, category='success') meta.Session().commit() except formencode.Invalid as errors: ug_model = UserGroupModel() @@ -192,7 +193,7 @@ class UserGroupsController(BaseControlle force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of user group %s') + webutils.flash(_('Error occurred during update of user group %s') % request.POST.get('users_group_name'), category='error') raise HTTPFound(location=url('edit_users_group', id=id)) @@ -203,12 +204,12 @@ class UserGroupsController(BaseControlle try: UserGroupModel().delete(usr_gr) meta.Session().commit() - h.flash(_('Successfully deleted user group'), category='success') + webutils.flash(_('Successfully deleted user group'), category='success') except UserGroupsAssignedException as e: - h.flash(e, category='error') + webutils.flash(e, category='error') except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during deletion of user group'), + webutils.flash(_('An error occurred during deletion of user group'), category='error') raise HTTPFound(location=url('users_groups')) @@ -264,13 +265,13 @@ class UserGroupsController(BaseControlle UserGroupModel()._update_permissions(user_group, form['perms_new'], form['perms_updates']) except RepoGroupAssignmentError: - h.flash(_('Target group cannot be the same'), category='error') + webutils.flash(_('Target group cannot be the same'), category='error') raise HTTPFound(location=url('edit_user_group_perms', id=id)) # TODO: implement this #action_logger(request.authuser, 'admin_changed_repo_permissions', # repo_name, request.ip_addr) meta.Session().commit() - h.flash(_('User group permissions updated'), category='success') + webutils.flash(_('User group permissions updated'), category='success') raise HTTPFound(location=url('edit_user_group_perms', id=id)) @HasUserGroupPermissionLevelDecorator('admin') @@ -286,7 +287,7 @@ class UserGroupsController(BaseControlle if not request.authuser.is_admin: if obj_type == 'user' and request.authuser.user_id == obj_id: msg = _('Cannot revoke permission for yourself as admin') - h.flash(msg, category='warning') + webutils.flash(msg, category='warning') raise Exception('revoke admin permission on self') if obj_type == 'user': UserGroupModel().revoke_user_permission(user_group=id, @@ -297,7 +298,7 @@ class UserGroupsController(BaseControlle meta.Session().commit() except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during revoking of permission'), + webutils.flash(_('An error occurred during revoking of permission'), category='error') raise HTTPInternalServerError() @@ -379,11 +380,11 @@ class UserGroupsController(BaseControlle else: usergroup_model.grant_perm(id, 'hg.fork.none') - h.flash(_("Updated permissions"), category='success') + webutils.flash(_("Updated permissions"), category='success') meta.Session().commit() except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during permissions saving'), + webutils.flash(_('An error occurred during permissions saving'), category='error') raise HTTPFound(location=url('edit_user_group_default_perms', id=id)) diff --git a/kallithea/controllers/admin/users.py b/kallithea/controllers/admin/users.py --- a/kallithea/controllers/admin/users.py +++ b/kallithea/controllers/admin/users.py @@ -39,6 +39,7 @@ from webob.exc import HTTPFound, HTTPNot import kallithea from kallithea.lib import auth_modules from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator, LoginRequired from kallithea.lib.base import BaseController, IfSshEnabled, render from kallithea.lib.exceptions import DefaultUserException, UserCreationError, UserOwnsReposException @@ -87,8 +88,8 @@ class UsersController(BaseController): "gravatar": grav_tmpl % h.gravatar(user.email, size=20), "raw_name": user.username, "username": username(user.user_id, user.username), - "firstname": h.escape(user.name), - "lastname": h.escape(user.lastname), + "firstname": webutils.escape(user.name), + "lastname": webutils.escape(user.lastname), "last_login": h.fmt_date(user.last_login), "last_login_raw": datetime_to_time(user.last_login), "active": h.boolicon(user.active), @@ -116,7 +117,7 @@ class UsersController(BaseController): user = user_model.create(form_result) action_logger(request.authuser, 'admin_created_user:%s' % user.username, None, request.ip_addr) - h.flash(_('Created user %s') % user.username, + webutils.flash(_('Created user %s') % user.username, category='success') meta.Session().commit() except formencode.Invalid as errors: @@ -128,10 +129,10 @@ class UsersController(BaseController): encoding="UTF-8", force_defaults=False) except UserCreationError as e: - h.flash(e, 'error') + webutils.flash(e, 'error') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during creation of user %s') + webutils.flash(_('Error occurred during creation of user %s') % request.POST.get('username'), category='error') raise HTTPFound(location=url('edit_user', id=user.user_id)) @@ -155,7 +156,7 @@ class UsersController(BaseController): usr = form_result['username'] action_logger(request.authuser, 'admin_updated_user:%s' % usr, None, request.ip_addr) - h.flash(_('User updated successfully'), category='success') + webutils.flash(_('User updated successfully'), category='success') meta.Session().commit() except formencode.Invalid as errors: defaults = errors.value @@ -174,7 +175,7 @@ class UsersController(BaseController): force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during update of user %s') + webutils.flash(_('Error occurred during update of user %s') % form_result.get('username'), category='error') raise HTTPFound(location=url('edit_user', id=id)) @@ -184,12 +185,12 @@ class UsersController(BaseController): try: UserModel().delete(usr) meta.Session().commit() - h.flash(_('Successfully deleted user'), category='success') + webutils.flash(_('Successfully deleted user'), category='success') except (UserOwnsReposException, DefaultUserException) as e: - h.flash(e, category='warning') + webutils.flash(e, category='warning') except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during deletion of user'), + webutils.flash(_('An error occurred during deletion of user'), category='error') else: if has_ssh_keys: @@ -200,7 +201,7 @@ class UsersController(BaseController): try: return db.User.get_or_404(id, allow_default=False) except DefaultUserException: - h.flash(_("The default user cannot be edited"), category='warning') + webutils.flash(_("The default user cannot be edited"), category='warning') raise HTTPNotFound def _render_edit_profile(self, user): @@ -268,7 +269,7 @@ class UsersController(BaseController): description = request.POST.get('description') ApiKeyModel().create(c.user.user_id, description, lifetime) meta.Session().commit() - h.flash(_("API key successfully created"), category='success') + webutils.flash(_("API key successfully created"), category='success') raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id)) def delete_api_key(self, id): @@ -278,11 +279,11 @@ class UsersController(BaseController): if request.POST.get('del_api_key_builtin'): c.user.api_key = generate_api_key() meta.Session().commit() - h.flash(_("API key successfully reset"), category='success') + webutils.flash(_("API key successfully reset"), category='success') elif api_key: ApiKeyModel().delete(api_key, c.user.user_id) meta.Session().commit() - h.flash(_("API key successfully deleted"), category='success') + webutils.flash(_("API key successfully deleted"), category='success') raise HTTPFound(location=url('edit_user_api_keys', id=c.user.user_id)) @@ -335,11 +336,11 @@ class UsersController(BaseController): user_model.grant_perm(id, 'hg.fork.repository') else: user_model.grant_perm(id, 'hg.fork.none') - h.flash(_("Updated permissions"), category='success') + webutils.flash(_("Updated permissions"), category='success') meta.Session().commit() except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during permissions saving'), + webutils.flash(_('An error occurred during permissions saving'), category='error') raise HTTPFound(location=url('edit_user_perms', id=id)) @@ -364,13 +365,13 @@ class UsersController(BaseController): try: user_model.add_extra_email(id, email) meta.Session().commit() - h.flash(_("Added email %s to user") % email, category='success') + webutils.flash(_("Added email %s to user") % email, category='success') except formencode.Invalid as error: msg = error.error_dict['email'] - h.flash(msg, category='error') + webutils.flash(msg, category='error') except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during email saving'), + webutils.flash(_('An error occurred during email saving'), category='error') raise HTTPFound(location=url('edit_user_emails', id=id)) @@ -380,7 +381,7 @@ class UsersController(BaseController): user_model = UserModel() user_model.delete_extra_email(id, email_id) meta.Session().commit() - h.flash(_("Removed email from user"), category='success') + webutils.flash(_("Removed email from user"), category='success') raise HTTPFound(location=url('edit_user_emails', id=id)) def edit_ips(self, id): @@ -406,13 +407,13 @@ class UsersController(BaseController): try: user_model.add_extra_ip(id, ip) meta.Session().commit() - h.flash(_("Added IP address %s to user whitelist") % ip, category='success') + webutils.flash(_("Added IP address %s to user whitelist") % ip, category='success') except formencode.Invalid as error: msg = error.error_dict['ip'] - h.flash(msg, category='error') + webutils.flash(msg, category='error') except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred while adding IP address'), + webutils.flash(_('An error occurred while adding IP address'), category='error') if 'default_user' in request.POST: @@ -424,7 +425,7 @@ class UsersController(BaseController): user_model = UserModel() user_model.delete_extra_ip(id, ip_id) meta.Session().commit() - h.flash(_("Removed IP address from user whitelist"), category='success') + webutils.flash(_("Removed IP address from user whitelist"), category='success') if 'default_user' in request.POST: raise HTTPFound(location=url('admin_permissions_ips')) @@ -453,9 +454,9 @@ class UsersController(BaseController): description, public_key) meta.Session().commit() SshKeyModel().write_authorized_keys() - h.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success') + webutils.flash(_("SSH key %s successfully added") % new_ssh_key.fingerprint, category='success') except SshKeyModelException as e: - h.flash(e.args[0], category='error') + webutils.flash(e.args[0], category='error') raise HTTPFound(location=url('edit_user_ssh_keys', id=c.user.user_id)) @IfSshEnabled @@ -467,7 +468,7 @@ class UsersController(BaseController): SshKeyModel().delete(fingerprint, c.user.user_id) meta.Session().commit() SshKeyModel().write_authorized_keys() - h.flash(_("SSH key successfully deleted"), category='success') + webutils.flash(_("SSH key successfully deleted"), category='success') except SshKeyModelException as e: - h.flash(e.args[0], category='error') + webutils.flash(e.args[0], category='error') raise HTTPFound(location=url('edit_user_ssh_keys', id=c.user.user_id)) diff --git a/kallithea/controllers/changelog.py b/kallithea/controllers/changelog.py --- a/kallithea/controllers/changelog.py +++ b/kallithea/controllers/changelog.py @@ -33,7 +33,6 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPBadRequest, HTTPFound, HTTPNotFound -import kallithea.lib.helpers as h from kallithea.lib import webutils from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseRepoController, render @@ -65,10 +64,10 @@ class ChangelogController(BaseRepoContro try: return c.db_repo_scm_instance.get_changeset(rev) except EmptyRepositoryError as e: - h.flash(_('There are no changesets yet'), category='error') + webutils.flash(_('There are no changesets yet'), category='error') except RepositoryError as e: log.error(traceback.format_exc()) - h.flash(e, category='error') + webutils.flash(e, category='error') raise HTTPBadRequest() @LoginRequired(allow_default_user=True) @@ -112,7 +111,7 @@ class ChangelogController(BaseRepoContro cs = self.__get_cs(revision, repo_name) collection = cs.get_file_history(f_path) except RepositoryError as e: - h.flash(e, category='warning') + webutils.flash(e, category='warning') raise HTTPFound(location=webutils.url('changelog_home', repo_name=repo_name)) else: collection = c.db_repo_scm_instance.get_changesets(start=0, end=revision, @@ -126,11 +125,11 @@ class ChangelogController(BaseRepoContro c.cs_comments = c.db_repo.get_comments(page_revisions) c.cs_statuses = c.db_repo.statuses(page_revisions) except EmptyRepositoryError as e: - h.flash(e, category='warning') + webutils.flash(e, category='warning') raise HTTPFound(location=url('summary_home', repo_name=c.repo_name)) except (RepositoryError, ChangesetDoesNotExistError, Exception) as e: log.error(traceback.format_exc()) - h.flash(e, category='error') + webutils.flash(e, category='error') raise HTTPFound(location=url('changelog_home', repo_name=c.repo_name)) c.branch_name = branch_name diff --git a/kallithea/controllers/changeset.py b/kallithea/controllers/changeset.py --- a/kallithea/controllers/changeset.py +++ b/kallithea/controllers/changeset.py @@ -86,7 +86,7 @@ def create_cs_pr_comment(repo_name, revi if not allowed_to_change_status: if status or close_pr: - h.flash(_('No permission to change status'), 'error') + webutils.flash(_('No permission to change status'), 'error') raise HTTPForbidden() if pull_request and delete == "delete": @@ -97,7 +97,7 @@ def create_cs_pr_comment(repo_name, revi ) and not pull_request.is_closed(): PullRequestModel().delete(pull_request) meta.Session().commit() - h.flash(_('Successfully deleted pull request %s') % pull_request_id, + webutils.flash(_('Successfully deleted pull request %s') % pull_request_id, category='success') return { 'location': webutils.url('my_pullrequests'), # or repo pr list? @@ -143,7 +143,7 @@ def create_cs_pr_comment(repo_name, revi meta.Session().commit() data = { - 'target_id': h.safeid(request.POST.get('f_path')), + 'target_id': webutils.safeid(request.POST.get('f_path')), } if comment is not None: c.comment = comment @@ -199,7 +199,7 @@ class ChangesetController(BaseRepoContro except (ChangesetDoesNotExistError, EmptyRepositoryError): log.debug(traceback.format_exc()) msg = _('Such revision does not exist for this repository') - h.flash(msg, category='error') + webutils.flash(msg, category='error') raise HTTPNotFound() c.changes = OrderedDict() diff --git a/kallithea/controllers/compare.py b/kallithea/controllers/compare.py --- a/kallithea/controllers/compare.py +++ b/kallithea/controllers/compare.py @@ -63,13 +63,13 @@ class CompareController(BaseRepoControll c.cs_repo = db.Repository.get_by_repo_name(other_repo) if c.cs_repo is None: msg = _('Could not find other repository %s') % other_repo - h.flash(msg, category='error') + webutils.flash(msg, category='error') raise HTTPFound(location=url('compare_home', repo_name=c.a_repo.repo_name)) # Verify that it's even possible to compare these two repositories. if c.a_repo.scm_instance.alias != c.cs_repo.scm_instance.alias: msg = _('Cannot compare repositories of different types') - h.flash(msg, category='error') + webutils.flash(msg, category='error') raise HTTPFound(location=url('compare_home', repo_name=c.a_repo.repo_name)) @LoginRequired(allow_default_user=True) @@ -146,7 +146,7 @@ class CompareController(BaseRepoControll else: msg = _('Multiple merge ancestors found for merge compare') if rev1 is None: - h.flash(msg, category='error') + webutils.flash(msg, category='error') log.error(msg) raise HTTPNotFound @@ -160,7 +160,7 @@ class CompareController(BaseRepoControll if org_repo != other_repo: # TODO: we could do this by using hg unionrepo log.error('cannot compare across repos %s and %s', org_repo, other_repo) - h.flash(_('Cannot compare repositories without using common ancestor'), category='error') + webutils.flash(_('Cannot compare repositories without using common ancestor'), category='error') raise HTTPBadRequest rev1 = c.a_rev diff --git a/kallithea/controllers/files.py b/kallithea/controllers/files.py --- a/kallithea/controllers/files.py +++ b/kallithea/controllers/files.py @@ -83,15 +83,15 @@ class FilesController(BaseRepoController url_ = url('files_add_home', repo_name=c.repo_name, revision=0, f_path='', anchor='edit') - add_new = h.link_to(_('Click here to add new file'), url_, class_="alert-link") - h.flash(_('There are no files yet.') + ' ' + add_new, category='warning') + add_new = webutils.link_to(_('Click here to add new file'), url_, class_="alert-link") + webutils.flash(_('There are no files yet.') + ' ' + add_new, category='warning') raise HTTPNotFound() except (ChangesetDoesNotExistError, LookupError): msg = _('Such revision does not exist for this repository') - h.flash(msg, category='error') + webutils.flash(msg, category='error') raise HTTPNotFound() except RepositoryError as e: - h.flash(e, category='error') + webutils.flash(e, category='error') raise HTTPNotFound() def __get_filenode(self, cs, path): @@ -108,10 +108,10 @@ class FilesController(BaseRepoController raise RepositoryError('given path is a directory') except ChangesetDoesNotExistError: msg = _('Such revision does not exist for this repository') - h.flash(msg, category='error') + webutils.flash(msg, category='error') raise HTTPNotFound() except RepositoryError as e: - h.flash(e, category='error') + webutils.flash(e, category='error') raise HTTPNotFound() return file_node @@ -176,7 +176,7 @@ class FilesController(BaseRepoController else: c.authors = c.file_history = [] except RepositoryError as e: - h.flash(e, category='error') + webutils.flash(e, category='error') raise HTTPNotFound() if request.environ.get('HTTP_X_PARTIAL_XHR'): @@ -293,7 +293,7 @@ class FilesController(BaseRepoController _branches = repo.scm_instance.branches # check if revision is a branch name or branch hash if revision not in _branches and revision not in _branches.values(): - h.flash(_('You can only delete files with revision ' + webutils.flash(_('You can only delete files with revision ' 'being a valid branch'), category='warning') raise HTTPFound(location=webutils.url('files_home', repo_name=repo_name, revision='tip', @@ -328,11 +328,11 @@ class FilesController(BaseRepoController author=author, ) - h.flash(_('Successfully deleted file %s') % f_path, + webutils.flash(_('Successfully deleted file %s') % f_path, category='success') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during commit'), category='error') + webutils.flash(_('Error occurred during commit'), category='error') raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) @@ -347,7 +347,7 @@ class FilesController(BaseRepoController _branches = repo.scm_instance.branches # check if revision is a branch name or branch hash if revision not in _branches and revision not in _branches.values(): - h.flash(_('You can only edit files with revision ' + webutils.flash(_('You can only edit files with revision ' 'being a valid branch'), category='warning') raise HTTPFound(location=webutils.url('files_home', repo_name=repo_name, revision='tip', @@ -376,7 +376,7 @@ class FilesController(BaseRepoController author = request.authuser.full_contact if content == old_content: - h.flash(_('No changes'), category='warning') + webutils.flash(_('No changes'), category='warning') raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) try: @@ -386,11 +386,11 @@ class FilesController(BaseRepoController ip_addr=request.ip_addr, author=author, message=message, content=content, f_path=f_path) - h.flash(_('Successfully committed to %s') % f_path, + webutils.flash(_('Successfully committed to %s') % f_path, category='success') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during commit'), category='error') + webutils.flash(_('Error occurred during commit'), category='error') raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) @@ -426,11 +426,11 @@ class FilesController(BaseRepoController content = content.file if not content: - h.flash(_('No content'), category='warning') + webutils.flash(_('No content'), category='warning') raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) if not filename: - h.flash(_('No filename'), category='warning') + webutils.flash(_('No filename'), category='warning') raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) # strip all crap out of file, just leave the basename @@ -454,18 +454,18 @@ class FilesController(BaseRepoController author=author, ) - h.flash(_('Successfully committed to %s') % node_path, + webutils.flash(_('Successfully committed to %s') % node_path, category='success') except NonRelativePathError as e: - h.flash(_('Location must be relative path and must not ' + webutils.flash(_('Location must be relative path and must not ' 'contain .. in path'), category='warning') raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) except (NodeError, NodeAlreadyExistsError) as e: - h.flash(_(e), category='error') + webutils.flash(_(e), category='error') except Exception: log.error(traceback.format_exc()) - h.flash(_('Error occurred during commit'), category='error') + webutils.flash(_('Error occurred during commit'), category='error') raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name, revision='tip')) @@ -687,7 +687,7 @@ class FilesController(BaseRepoController node2 = FileNode(f_path, '', changeset=c.changeset_2) except ChangesetDoesNotExistError as e: msg = _('Such revision does not exist for this repository') - h.flash(msg, category='error') + webutils.flash(msg, category='error') raise HTTPNotFound() c.node1 = node1 c.node2 = node2 diff --git a/kallithea/controllers/forks.py b/kallithea/controllers/forks.py --- a/kallithea/controllers/forks.py +++ b/kallithea/controllers/forks.py @@ -36,7 +36,6 @@ from tg.i18n import ugettext as _ from webob.exc import HTTPFound, HTTPNotFound import kallithea -import kallithea.lib.helpers as h from kallithea.lib import webutils from kallithea.lib.auth import HasPermissionAnyDecorator, HasRepoPermissionLevel, HasRepoPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseRepoController, render @@ -166,7 +165,7 @@ class ForksController(BaseRepoController force_defaults=False) except Exception: log.error(traceback.format_exc()) - h.flash(_('An error occurred during repository forking %s') % + webutils.flash(_('An error occurred during repository forking %s') % repo_name, category='error') raise HTTPFound(location=webutils.url('repo_creating_home', diff --git a/kallithea/controllers/login.py b/kallithea/controllers/login.py --- a/kallithea/controllers/login.py +++ b/kallithea/controllers/login.py @@ -36,7 +36,7 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPBadRequest, HTTPFound -import kallithea.lib.helpers as h +from kallithea.lib import webutils from kallithea.lib.auth import AuthUser, HasPermissionAnyDecorator from kallithea.lib.base import BaseController, log_in_user, render from kallithea.lib.exceptions import UserCreationError @@ -99,13 +99,13 @@ class LoginController(BaseController): # the fly can throw this exception signaling that there's issue # with user creation, explanation should be provided in # Exception itself - h.flash(e, 'error') + webutils.flash(e, 'error') else: # login_form already validated the password - now set the session cookie accordingly auth_user = log_in_user(user, c.form_result['remember'], is_external_auth=False, ip_addr=request.ip_addr) if auth_user: raise HTTPFound(location=c.came_from) - h.flash(_('Authentication failed.'), 'error') + webutils.flash(_('Authentication failed.'), 'error') else: # redirect if already logged in if not request.authuser.is_anonymous: @@ -144,7 +144,7 @@ class LoginController(BaseController): error_dict=error_dict) UserModel().create_registration(form_result) - h.flash(_('You have successfully registered with %s') % (c.site_name or 'Kallithea'), + webutils.flash(_('You have successfully registered with %s') % (c.site_name or 'Kallithea'), category='success') meta.Session().commit() raise HTTPFound(location=url('login_home')) @@ -162,7 +162,7 @@ class LoginController(BaseController): # the fly can throw this exception signaling that there's issue # with user creation, explanation should be provided in # Exception itself - h.flash(e, 'error') + webutils.flash(e, 'error') return render('/register.html') @@ -188,7 +188,7 @@ class LoginController(BaseController): raise formencode.Invalid(_msg, _value, None, error_dict=error_dict) redirect_link = UserModel().send_reset_password_email(form_result) - h.flash(_('A password reset confirmation code has been sent'), + webutils.flash(_('A password reset confirmation code has been sent'), category='success') raise HTTPFound(location=redirect_link) @@ -240,7 +240,7 @@ class LoginController(BaseController): encoding='UTF-8') UserModel().reset_password(form_result['email'], form_result['password']) - h.flash(_('Successfully updated password'), category='success') + webutils.flash(_('Successfully updated password'), category='success') raise HTTPFound(location=url('login_home')) def logout(self): @@ -254,4 +254,4 @@ class LoginController(BaseController): Only intended for testing but might also be useful for other kinds of automation. """ - return h.session_csrf_secret_token() + return webutils.session_csrf_secret_token() diff --git a/kallithea/controllers/pullrequests.py b/kallithea/controllers/pullrequests.py --- a/kallithea/controllers/pullrequests.py +++ b/kallithea/controllers/pullrequests.py @@ -35,9 +35,9 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPBadRequest, HTTPForbidden, HTTPFound, HTTPNotFound +import kallithea.lib.helpers as h from kallithea.controllers.changeset import create_cs_pr_comment, delete_cs_pr_comment -from kallithea.lib import auth, diffs -from kallithea.lib import helpers as h +from kallithea.lib import auth, diffs, webutils from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseRepoController, jsonify, render from kallithea.lib.graphmod import graph_data @@ -63,7 +63,7 @@ def _get_reviewer(user_id): user = None if user is None or user.is_default_user: - h.flash(_('Invalid reviewer "%s" specified') % user_id, category='error') + webutils.flash(_('Invalid reviewer "%s" specified') % user_id, category='error') raise HTTPBadRequest() return user @@ -245,7 +245,7 @@ class PullrequestsController(BaseRepoCon try: org_scm_instance.get_changeset() except EmptyRepositoryError as e: - h.flash(_('There are no changesets yet'), + webutils.flash(_('There are no changesets yet'), category='warning') raise HTTPFound(location=url('summary_home', repo_name=org_repo.repo_name)) @@ -314,7 +314,7 @@ class PullrequestsController(BaseRepoCon log.error(traceback.format_exc()) log.error(str(errors)) msg = _('Error creating pull request: %s') % errors.msg - h.flash(msg, 'error') + webutils.flash(msg, 'error') raise HTTPBadRequest # heads up: org and other might seem backward here ... @@ -333,19 +333,19 @@ class PullrequestsController(BaseRepoCon try: cmd = CreatePullRequestAction(org_repo, other_repo, org_ref, other_ref, title, description, owner, reviewers) except CreatePullRequestAction.ValidationError as e: - h.flash(e, category='error', logf=log.error) + webutils.flash(e, category='error', logf=log.error) raise HTTPNotFound try: pull_request = cmd.execute() meta.Session().commit() except Exception: - h.flash(_('Error occurred while creating pull request'), + webutils.flash(_('Error occurred while creating pull request'), category='error') log.error(traceback.format_exc()) raise HTTPFound(location=url('pullrequest_home', repo_name=repo_name)) - h.flash(_('Successfully opened new pull request'), + webutils.flash(_('Successfully opened new pull request'), category='success') raise HTTPFound(location=pull_request.url()) @@ -356,19 +356,19 @@ class PullrequestsController(BaseRepoCon try: cmd = CreatePullRequestIterationAction(old_pull_request, new_org_rev, new_other_rev, title, description, owner, reviewers) except CreatePullRequestAction.ValidationError as e: - h.flash(e, category='error', logf=log.error) + webutils.flash(e, category='error', logf=log.error) raise HTTPNotFound try: pull_request = cmd.execute() meta.Session().commit() except Exception: - h.flash(_('Error occurred while creating pull request'), + webutils.flash(_('Error occurred while creating pull request'), category='error') log.error(traceback.format_exc()) raise HTTPFound(location=old_pull_request.url()) - h.flash(_('New pull request iteration created'), + webutils.flash(_('New pull request iteration created'), category='success') raise HTTPFound(location=pull_request.url()) @@ -396,11 +396,11 @@ class PullrequestsController(BaseRepoCon other_removed = old_reviewers - cur_reviewers if other_added: - h.flash(_('Meanwhile, the following reviewers have been added: %s') % + webutils.flash(_('Meanwhile, the following reviewers have been added: %s') % (', '.join(u.username for u in other_added)), category='warning') if other_removed: - h.flash(_('Meanwhile, the following reviewers have been removed: %s') % + webutils.flash(_('Meanwhile, the following reviewers have been removed: %s') % (', '.join(u.username for u in other_removed)), category='warning') @@ -425,7 +425,7 @@ class PullrequestsController(BaseRepoCon PullRequestModel().remove_reviewers(user, pull_request, removed_reviewers) meta.Session().commit() - h.flash(_('Pull request updated'), category='success') + webutils.flash(_('Pull request updated'), category='success') raise HTTPFound(location=pull_request.url()) @@ -438,7 +438,7 @@ class PullrequestsController(BaseRepoCon if pull_request.owner_id == request.authuser.user_id: PullRequestModel().delete(pull_request) meta.Session().commit() - h.flash(_('Successfully deleted pull request'), + webutils.flash(_('Successfully deleted pull request'), category='success') raise HTTPFound(location=url('my_pullrequests')) raise HTTPForbidden() @@ -474,7 +474,7 @@ class PullrequestsController(BaseRepoCon c.cs_ranges.append(org_scm_instance.get_changeset(x)) except ChangesetDoesNotExistError: c.cs_ranges = [] - h.flash(_('Revision %s not found in %s') % (x, c.cs_repo.repo_name), + webutils.flash(_('Revision %s not found in %s') % (x, c.cs_repo.repo_name), 'error') break c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ... diff --git a/kallithea/controllers/summary.py b/kallithea/controllers/summary.py --- a/kallithea/controllers/summary.py +++ b/kallithea/controllers/summary.py @@ -38,8 +38,7 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ from webob.exc import HTTPBadRequest -import kallithea.lib.helpers as h -from kallithea.lib import ext_json +from kallithea.lib import ext_json, webutils from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseRepoController, jsonify, render from kallithea.lib.celerylib.tasks import get_commits_stats @@ -108,7 +107,7 @@ class SummaryController(BaseRepoControll try: collection = c.db_repo_scm_instance.get_changesets(reverse=True) except EmptyRepositoryError as e: - h.flash(e, category='warning') + webutils.flash(e, category='warning') collection = [] c.cs_pagination = Page(collection, page=p, items_per_page=size) page_revisions = [x.raw_id for x in list(c.cs_pagination)] diff --git a/kallithea/lib/auth.py b/kallithea/lib/auth.py --- a/kallithea/lib/auth.py +++ b/kallithea/lib/auth.py @@ -40,6 +40,7 @@ from tg.i18n import ugettext as _ from webob.exc import HTTPForbidden, HTTPFound import kallithea +from kallithea.lib import webutils from kallithea.lib.utils import get_repo_group_slug, get_repo_slug, get_user_group_slug from kallithea.lib.utils2 import ascii_bytes, ascii_str, safe_bytes from kallithea.lib.vcs.utils.lazy import LazyProperty @@ -544,9 +545,8 @@ def _redirect_to_login(message=None): """Return an exception that must be raised. It will redirect to the login page which will redirect back to the current URL after authentication. The optional message will be shown in a flash message.""" - from kallithea.lib import helpers as h if message: - h.flash(message, category='warning') + webutils.flash(message, category='warning') p = request.path_qs log.debug('Redirecting to login page, origin: %s', p) return HTTPFound(location=url('login_home', came_from=p)) diff --git a/kallithea/lib/base.py b/kallithea/lib/base.py --- a/kallithea/lib/base.py +++ b/kallithea/lib/base.py @@ -44,7 +44,7 @@ from tg import tmpl_context as c from tg.i18n import ugettext as _ import kallithea -from kallithea.lib import auth_modules, ext_json +from kallithea.lib import auth_modules, ext_json, webutils from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware from kallithea.lib.exceptions import UserCreationError from kallithea.lib.utils import get_repo_slug, is_valid_repo @@ -361,9 +361,8 @@ class BaseController(TGController): # guaranteed to be side effect free. In practice, the only situation # where we allow side effects without ambient authority is when the # authority comes from an API key; and that is handled above. - from kallithea.lib import helpers as h - token = request.POST.get(h.session_csrf_secret_name) - if not token or token != h.session_csrf_secret_token(): + token = request.POST.get(webutils.session_csrf_secret_name) + if not token or token != webutils.session_csrf_secret_token(): log.error('CSRF check failed') raise webob.exc.HTTPForbidden() @@ -444,8 +443,7 @@ class BaseController(TGController): try: user_info = auth_modules.authenticate('', '', request.environ) except UserCreationError as e: - from kallithea.lib import helpers as h - h.flash(e, 'error', logf=log.error) + webutils.flash(e, 'error', logf=log.error) else: if user_info is not None: username = user_info['username'] @@ -474,12 +472,11 @@ class BaseController(TGController): raise webob.exc.HTTPMethodNotAllowed() # Make sure CSRF token never appears in the URL. If so, invalidate it. - from kallithea.lib import helpers as h - if h.session_csrf_secret_name in request.GET: + if webutils.session_csrf_secret_name in request.GET: log.error('CSRF key leak detected') - session.pop(h.session_csrf_secret_name, None) + session.pop(webutils.session_csrf_secret_name, None) session.save() - h.flash(_('CSRF token leak has been detected - all form tokens have been expired'), + webutils.flash(_('CSRF token leak has been detected - all form tokens have been expired'), category='error') # WebOb already ignores request payload parameters for anything other @@ -575,8 +572,7 @@ class BaseRepoController(BaseController) if c.db_repo_scm_instance is None: log.error('%s this repository is present in database but it ' 'cannot be created as an scm instance', c.repo_name) - from kallithea.lib import helpers as h - h.flash(_('Repository not found in the filesystem'), + webutils.flash(_('Repository not found in the filesystem'), category='error') raise webob.exc.HTTPNotFound() @@ -592,22 +588,21 @@ class BaseRepoController(BaseController) """ Safe way to get changeset. If error occurs show error. """ - from kallithea.lib import helpers as h try: return repo.scm_instance.get_ref_revision(ref_type, ref_name) except EmptyRepositoryError as e: if returnempty: return repo.scm_instance.EMPTY_CHANGESET - h.flash(_('There are no changesets yet'), category='error') + webutils.flash(_('There are no changesets yet'), category='error') raise webob.exc.HTTPNotFound() except ChangesetDoesNotExistError as e: - h.flash(_('Changeset for %s %s not found in %s') % + webutils.flash(_('Changeset for %s %s not found in %s') % (ref_type, ref_name, repo.repo_name), category='error') raise webob.exc.HTTPNotFound() except RepositoryError as e: log.error(traceback.format_exc()) - h.flash(e, category='error') + webutils.flash(e, category='error') raise webob.exc.HTTPBadRequest() @@ -642,7 +637,6 @@ def IfSshEnabled(func, *args, **kwargs): If SSH access is disabled in the configuration file, HTTPNotFound is raised. """ if not c.ssh_enabled: - from kallithea.lib import helpers as h - h.flash(_("SSH access is disabled."), category='warning') + webutils.flash(_("SSH access is disabled."), category='warning') raise webob.exc.HTTPNotFound() return func(*args, **kwargs) diff --git a/kallithea/lib/diffs.py b/kallithea/lib/diffs.py --- a/kallithea/lib/diffs.py +++ b/kallithea/lib/diffs.py @@ -31,7 +31,7 @@ import re from tg.i18n import ugettext as _ -from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.utils2 import safe_str from kallithea.lib.vcs.backends.base import EmptyChangeset from kallithea.lib.vcs.exceptions import VCSError @@ -207,7 +207,7 @@ def wrapped_diff(filenode_old, filenode_ if not html_diff: submodules = [o for o in [filenode_new, filenode_old] if isinstance(o, SubModuleNode)] if submodules: - html_diff = wrap_to_table(h.escape('Submodule %r' % submodules[0])) + html_diff = wrap_to_table(webutils.escape('Submodule %r' % submodules[0])) else: html_diff = wrap_to_table(_('No changes detected')) @@ -249,7 +249,7 @@ def get_diff(scm_instance, rev1, rev2, p return scm_instance.get_diff(rev1, rev2, path=path, ignore_whitespace=ignore_whitespace, context=context) except MemoryError: - h.flash('MemoryError: Diff is too big', category='error') + webutils.flash('MemoryError: Diff is too big', category='error') return b'' diff --git a/kallithea/lib/helpers.py b/kallithea/lib/helpers.py --- a/kallithea/lib/helpers.py +++ b/kallithea/lib/helpers.py @@ -20,7 +20,6 @@ available to Controllers. This module is import hashlib import json import logging -import random import re import textwrap import urllib.parse @@ -28,16 +27,7 @@ import urllib.parse from beaker.cache import cache_region from pygments import highlight as code_highlight from pygments.formatters.html import HtmlFormatter -from tg import session from tg.i18n import ugettext as _ -from webhelpers2.html import HTML, escape, literal -from webhelpers2.html.tags import NotGiven, Option, Options, _input, _make_safe_id_component, checkbox, end_form -from webhelpers2.html.tags import form as insecure_form -from webhelpers2.html.tags import hidden, link_to, password, radio -from webhelpers2.html.tags import select as webhelpers2_select -from webhelpers2.html.tags import submit, text, textarea -from webhelpers2.number import format_byte_size -from webhelpers2.text import chop_at, truncate, wrap_paragraphs import kallithea from kallithea.lib.annotate import annotate_highlight @@ -55,47 +45,49 @@ from kallithea.lib.vcs.exceptions import # SCM FILTERS available via h. #============================================================================== from kallithea.lib.vcs.utils import author_email, author_name -from kallithea.lib.webutils import canonical_url, url +from kallithea.lib.webutils import (HTML, Option, canonical_url, checkbox, chop_at, end_form, escape, form, format_byte_size, hidden, html_escape, link_to, + literal, password, pop_flash_messages, radio, reset, safeid, select, session_csrf_secret_name, session_csrf_secret_token, + submit, text, textarea, truncate, url, wrap_paragraphs) from kallithea.model import db from kallithea.model.changeset_status import ChangesetStatusModel # mute pyflakes "imported but unused" +# from webutils assert Option +assert canonical_url assert checkbox +assert chop_at assert end_form +assert form +assert format_byte_size +assert hidden assert password +assert pop_flash_messages assert radio +assert reset +assert safeid +assert select +assert session_csrf_secret_name +assert session_csrf_secret_token assert submit assert text assert textarea -assert format_byte_size -assert chop_at assert wrap_paragraphs +# from kallithea.lib.auth assert HasPermissionAny assert HasRepoGroupPermissionLevel assert HasRepoPermissionLevel +# from utils2 assert age assert time_to_datetime +# from vcs assert EmptyChangeset -assert canonical_url log = logging.getLogger(__name__) -def html_escape(s): - """Return string with all html escaped. - This is also safe for javascript in html but not necessarily correct. - """ - return (s - .replace('&', '&') - .replace(">", ">") - .replace("<", "<") - .replace('"', """) - .replace("'", "'") # Note: this is HTML5 not HTML4 and might not work in mails - ) - def js(value): """Convert Python value to the corresponding JavaScript representation. @@ -152,44 +144,6 @@ def shorter(s, size=20, firstline=False, return s -def reset(name, value, id=NotGiven, **attrs): - """Create a reset button, similar to webhelpers2.html.tags.submit .""" - return _input("reset", name, value, id, attrs) - - -def select(name, selected_values, options, id=NotGiven, **attrs): - """Convenient wrapper of webhelpers2 to let it accept options as a tuple list""" - if isinstance(options, list): - option_list = options - # Handle old value,label lists ... where value also can be value,label lists - options = Options() - for x in option_list: - if isinstance(x, tuple) and len(x) == 2: - value, label = x - elif isinstance(x, str): - value = label = x - else: - log.error('invalid select option %r', x) - raise - if isinstance(value, list): - og = options.add_optgroup(label) - for x in value: - if isinstance(x, tuple) and len(x) == 2: - group_value, group_label = x - elif isinstance(x, str): - group_value = group_label = x - else: - log.error('invalid select option %r', x) - raise - og.add_option(group_label, group_value) - else: - options.add_option(label, value) - return webhelpers2_select(name, selected_values, options, id=id, **attrs) - - -safeid = _make_safe_id_component - - def FID(raw_id, path): """ Creates a unique ID for filenode based on it's hash of path and revision @@ -448,76 +402,6 @@ def pygmentize_annotation(repo_name, fil return literal(markup_whitespace(annotate_highlight(filenode, url_func, **kwargs))) -class _Message(object): - """A message returned by ``pop_flash_messages()``. - - Converting the message to a string returns the message text. Instances - also have the following attributes: - - * ``category``: the category specified when the message was created. - * ``message``: the html-safe message text. - """ - - def __init__(self, category, message): - self.category = category - self.message = message - - -def _session_flash_messages(append=None, clear=False): - """Manage a message queue in tg.session: return the current message queue - after appending the given message, and possibly clearing the queue.""" - key = 'flash' - if key in session: - flash_messages = session[key] - else: - if append is None: # common fast path - also used for clearing empty queue - return [] # don't bother saving - flash_messages = [] - session[key] = flash_messages - if append is not None and append not in flash_messages: - flash_messages.append(append) - if clear: - session.pop(key, None) - session.save() - return flash_messages - - -def flash(message, category, logf=None): - """ - Show a message to the user _and_ log it through the specified function - - category: notice (default), warning, error, success - logf: a custom log function - such as log.debug - - logf defaults to log.info, unless category equals 'success', in which - case logf defaults to log.debug. - """ - assert category in ('error', 'success', 'warning'), category - if hasattr(message, '__html__'): - # render to HTML for storing in cookie - safe_message = str(message) - else: - # Apply str - the message might be an exception with __str__ - # Escape, so we can trust the result without further escaping, without any risk of injection - safe_message = html_escape(str(message)) - if logf is None: - logf = log.info - if category == 'success': - logf = log.debug - - logf('Flash %s: %s', category, safe_message) - - _session_flash_messages(append=(category, safe_message)) - - -def pop_flash_messages(): - """Return all accumulated messages and delete them from the session. - - The return value is a list of ``Message`` objects. - """ - return [_Message(category, message) for category, message in _session_flash_messages(clear=True)] - - def capitalize(x): return x.capitalize() @@ -1317,23 +1201,3 @@ def journal_filter_help(): def ip_range(ip_addr): s, e = db.UserIpMap._get_ip_range(ip_addr) return '%s - %s' % (s, e) - - -session_csrf_secret_name = "_session_csrf_secret_token" - -def session_csrf_secret_token(): - """Return (and create) the current session's CSRF protection token.""" - if not session_csrf_secret_name in session: - session[session_csrf_secret_name] = str(random.getrandbits(128)) - session.save() - return session[session_csrf_secret_name] - -def form(url, method="post", **attrs): - """Like webhelpers.html.tags.form , but automatically adding - session_csrf_secret_token for POST. The secret is thus never leaked in GET - URLs. - """ - form = insecure_form(url, method, **attrs) - if method.lower() == 'get': - return form - return form + HTML.div(hidden(session_csrf_secret_name, session_csrf_secret_token()), style="display: none;") diff --git a/kallithea/lib/hooks.py b/kallithea/lib/hooks.py --- a/kallithea/lib/hooks.py +++ b/kallithea/lib/hooks.py @@ -32,7 +32,7 @@ import time import mercurial.scmutil import kallithea -from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.exceptions import UserCreationError from kallithea.lib.utils import action_logger, make_ui from kallithea.lib.utils2 import HookEnvironmentError, ascii_str, get_hook_environment, safe_bytes, safe_str @@ -59,9 +59,9 @@ def _get_scm_size(alias, root_path): except OSError: pass - size_scm_f = h.format_byte_size(size_scm) - size_root_f = h.format_byte_size(size_root) - size_total_f = h.format_byte_size(size_root + size_scm) + size_scm_f = webutils.format_byte_size(size_scm) + size_root_f = webutils.format_byte_size(size_root) + size_total_f = webutils.format_byte_size(size_root + size_scm) return size_scm_f, size_root_f, size_total_f diff --git a/kallithea/lib/page.py b/kallithea/lib/page.py --- a/kallithea/lib/page.py +++ b/kallithea/lib/page.py @@ -19,9 +19,8 @@ import logging import paginate import paginate_sqlalchemy import sqlalchemy.orm -from webhelpers2.html import literal -from kallithea.lib.webutils import url +from kallithea.lib import webutils log = logging.getLogger(__name__) @@ -35,10 +34,10 @@ class Page(paginate.Page): if isinstance(collection, sqlalchemy.orm.query.Query): collection = paginate_sqlalchemy.SqlalchemyOrmWrapper(collection) paginate.Page.__init__(self, collection, page=page, items_per_page=items_per_page, item_count=item_count, - url_maker=lambda page: url.current(page=page, **kwargs)) + url_maker=lambda page: webutils.url.current(page=page, **kwargs)) def pager(self): - return literal( + return webutils.literal( paginate.Page.pager(self, format='', link_attr={'class': 'pager_link'}, diff --git a/kallithea/lib/webutils.py b/kallithea/lib/webutils.py --- a/kallithea/lib/webutils.py +++ b/kallithea/lib/webutils.py @@ -20,11 +20,46 @@ thread-local "global" variables. It shou imported anywhere - just like the global variables can be used everywhere. """ -from tg import request +import logging +import random + +from tg import request, session +from webhelpers2.html import HTML, escape, literal +from webhelpers2.html.tags import NotGiven, Option, Options, _input +from webhelpers2.html.tags import _make_safe_id_component as safeid +from webhelpers2.html.tags import checkbox, end_form +from webhelpers2.html.tags import form as insecure_form +from webhelpers2.html.tags import hidden, link_to, password, radio +from webhelpers2.html.tags import select as webhelpers2_select +from webhelpers2.html.tags import submit, text, textarea +from webhelpers2.number import format_byte_size +from webhelpers2.text import chop_at, truncate, wrap_paragraphs import kallithea +log = logging.getLogger(__name__) + + +# mute pyflakes "imported but unused" +assert Option +assert checkbox +assert chop_at +assert end_form +assert escape +assert format_byte_size +assert link_to +assert literal +assert password +assert radio +assert safeid +assert submit +assert text +assert textarea +assert truncate +assert wrap_paragraphs + + # # General Kallithea URL handling # @@ -75,3 +110,149 @@ def canonical_hostname(): except IndexError: parts = url('home', qualified=True).split('://', 1) return parts[1].split('/', 1)[0] + + +# +# Custom Webhelpers2 stuff +# + +def html_escape(s): + """Return string with all html escaped. + This is also safe for javascript in html but not necessarily correct. + """ + return (s + .replace('&', '&') + .replace(">", ">") + .replace("<", "<") + .replace('"', """) + .replace("'", "'") # Note: this is HTML5 not HTML4 and might not work in mails + ) + + +def reset(name, value, id=NotGiven, **attrs): + """Create a reset button, similar to webhelpers2.html.tags.submit .""" + return _input("reset", name, value, id, attrs) + + +def select(name, selected_values, options, id=NotGiven, **attrs): + """Convenient wrapper of webhelpers2 to let it accept options as a tuple list""" + if isinstance(options, list): + option_list = options + # Handle old value,label lists ... where value also can be value,label lists + options = Options() + for x in option_list: + if isinstance(x, tuple) and len(x) == 2: + value, label = x + elif isinstance(x, str): + value = label = x + else: + log.error('invalid select option %r', x) + raise + if isinstance(value, list): + og = options.add_optgroup(label) + for x in value: + if isinstance(x, tuple) and len(x) == 2: + group_value, group_label = x + elif isinstance(x, str): + group_value = group_label = x + else: + log.error('invalid select option %r', x) + raise + og.add_option(group_label, group_value) + else: + options.add_option(label, value) + return webhelpers2_select(name, selected_values, options, id=id, **attrs) + + +session_csrf_secret_name = "_session_csrf_secret_token" + +def session_csrf_secret_token(): + """Return (and create) the current session's CSRF protection token.""" + if not session_csrf_secret_name in session: + session[session_csrf_secret_name] = str(random.getrandbits(128)) + session.save() + return session[session_csrf_secret_name] + +def form(url, method="post", **attrs): + """Like webhelpers.html.tags.form , but automatically adding + session_csrf_secret_token for POST. The secret is thus never leaked in GET + URLs. + """ + form = insecure_form(url, method, **attrs) + if method.lower() == 'get': + return form + return form + HTML.div(hidden(session_csrf_secret_name, session_csrf_secret_token()), style="display: none;") + + +# +# Flash messages, stored in cookie +# + +class _Message(object): + """A message returned by ``pop_flash_messages()``. + + Converting the message to a string returns the message text. Instances + also have the following attributes: + + * ``category``: the category specified when the message was created. + * ``message``: the html-safe message text. + """ + + def __init__(self, category, message): + self.category = category + self.message = message + + +def _session_flash_messages(append=None, clear=False): + """Manage a message queue in tg.session: return the current message queue + after appending the given message, and possibly clearing the queue.""" + key = 'flash' + if key in session: + flash_messages = session[key] + else: + if append is None: # common fast path - also used for clearing empty queue + return [] # don't bother saving + flash_messages = [] + session[key] = flash_messages + if append is not None and append not in flash_messages: + flash_messages.append(append) + if clear: + session.pop(key, None) + session.save() + return flash_messages + + +def flash(message, category, logf=None): + """ + Show a message to the user _and_ log it through the specified function + + category: notice (default), warning, error, success + logf: a custom log function - such as log.debug + + logf defaults to log.info, unless category equals 'success', in which + case logf defaults to log.debug. + """ + assert category in ('error', 'success', 'warning'), category + if hasattr(message, '__html__'): + # render to HTML for storing in cookie + safe_message = str(message) + else: + # Apply str - the message might be an exception with __str__ + # Escape, so we can trust the result without further escaping, without any risk of injection + safe_message = html_escape(str(message)) + if logf is None: + logf = log.info + if category == 'success': + logf = log.debug + + logf('Flash %s: %s', category, safe_message) + + _session_flash_messages(append=(category, safe_message)) + + +def pop_flash_messages(): + """Return all accumulated messages and delete them from the session. + + The return value is a list of ``Message`` objects. + """ + return [_Message(category, message) for category, message in _session_flash_messages(clear=True)] diff --git a/kallithea/model/comment.py b/kallithea/model/comment.py --- a/kallithea/model/comment.py +++ b/kallithea/model/comment.py @@ -81,7 +81,7 @@ class ChangesetCommentsModel(object): repo_name=repo.repo_name, revision=revision, anchor='comment-%s' % comment.comment_id) - subj = h.link_to( + subj = webutils.link_to( 'Re changeset: %(desc)s %(line)s' % {'desc': desc, 'line': line}, comment_url) @@ -127,7 +127,7 @@ class ChangesetCommentsModel(object): webutils.canonical_hostname())) comment_url = pull_request.url(canonical=True, anchor='comment-%s' % comment.comment_id) - subj = h.link_to( + subj = webutils.link_to( 'Re pull request %(pr_nice_id)s: %(desc)s %(line)s' % {'desc': desc, 'pr_nice_id': comment.pull_request.nice_id(), diff --git a/kallithea/model/db.py b/kallithea/model/db.py --- a/kallithea/model/db.py +++ b/kallithea/model/db.py @@ -1306,9 +1306,8 @@ class Repository(meta.Base, BaseDbModel) return grouped def _repo_size(self): - from kallithea.lib import helpers as h log.debug('calculating repository size...') - return h.format_byte_size(self.scm_instance.size) + return webutils.format_byte_size(self.scm_instance.size) #========================================================================== # SCM CACHE INSTANCE @@ -1397,10 +1396,9 @@ class RepoGroup(meta.Base, BaseDbModel): @classmethod def _generate_choice(cls, repo_group): """Return tuple with group_id and name as html literal""" - from webhelpers2.html import literal if repo_group is None: return (-1, '-- %s --' % _('top level')) - return repo_group.group_id, literal(cls.SEP.join(repo_group.full_path_splitted)) + return repo_group.group_id, webutils.literal(cls.SEP.join(repo_group.full_path_splitted)) @classmethod def groups_choices(cls, groups): diff --git a/kallithea/model/pull_request.py b/kallithea/model/pull_request.py --- a/kallithea/model/pull_request.py +++ b/kallithea/model/pull_request.py @@ -82,7 +82,7 @@ class PullRequestModel(object): threading = ['%s-pr-%s@%s' % (pr.other_repo.repo_name, pr.pull_request_id, webutils.canonical_hostname())] - subject = h.link_to( + subject = webutils.link_to( _('%(user)s wants you to review pull request %(pr_nice_id)s: %(pr_title)s') % {'user': user.username, 'pr_title': pr.title, diff --git a/kallithea/model/user.py b/kallithea/model/user.py --- a/kallithea/model/user.py +++ b/kallithea/model/user.py @@ -314,7 +314,6 @@ class UserModel(object): allowing users to copy-paste or manually enter the token from the email. """ - import kallithea.lib.helpers as h from kallithea.lib.celerylib import tasks from kallithea.model.notification import EmailNotificationModel @@ -326,7 +325,7 @@ class UserModel(object): log.debug('password reset user %s found', user) token = self.get_reset_password_token(user, timestamp, - h.session_csrf_secret_token()) + webutils.session_csrf_secret_token()) # URL must be fully qualified; but since the token is locked to # the current browser session, we must provide a URL with the # current scheme and hostname, rather than the canonical_url. @@ -359,7 +358,6 @@ class UserModel(object): timestamp=timestamp) def verify_reset_password_token(self, email, timestamp, token): - import kallithea.lib.helpers as h user = db.User.get_by_email(email) if user is None: log.debug("user with email %s not found", email) @@ -377,7 +375,7 @@ class UserModel(object): expected_token = self.get_reset_password_token(user, timestamp, - h.session_csrf_secret_token()) + webutils.session_csrf_secret_token()) log.debug('computed password reset token: %s', expected_token) log.debug('received password reset token: %s', token) return expected_token == token diff --git a/kallithea/tests/functional/test_admin_users.py b/kallithea/tests/functional/test_admin_users.py --- a/kallithea/tests/functional/test_admin_users.py +++ b/kallithea/tests/functional/test_admin_users.py @@ -19,7 +19,7 @@ from webob.exc import HTTPNotFound import kallithea from kallithea.controllers.admin.users import UsersController -from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.auth import check_password from kallithea.model import db, meta, validators from kallithea.model.user import UserModel @@ -112,7 +112,7 @@ class TestAdminUsersController(base.Test with test_context(self.app): msg = validators.ValidUsername(False, {})._messages['system_invalid_username'] - msg = h.html_escape(msg % {'username': 'new_user'}) + msg = webutils.html_escape(msg % {'username': 'new_user'}) response.mustcontain("""%s""" % msg) response.mustcontain("""Please enter a value""") response.mustcontain("""An email address must contain a single @""") @@ -569,7 +569,7 @@ class TestAdminUsersController_unittest( # flash complains about an non-existing session def flash_mock(*args, **kwargs): pass - monkeypatch.setattr(h, 'flash', flash_mock) + monkeypatch.setattr(webutils, 'flash', flash_mock) u = UsersController() # a regular user should work correctly diff --git a/kallithea/tests/functional/test_login.py b/kallithea/tests/functional/test_login.py --- a/kallithea/tests/functional/test_login.py +++ b/kallithea/tests/functional/test_login.py @@ -7,7 +7,7 @@ import mock from tg.util.webtest import test_context import kallithea.lib.celerylib.tasks -from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.lib.auth import check_password from kallithea.lib.utils2 import generate_api_key from kallithea.model import db, meta, validators @@ -238,7 +238,7 @@ class TestLoginController(base.TestContr with test_context(self.app): msg = validators.ValidUsername()._messages['username_exists'] - msg = h.html_escape(msg % {'username': uname}) + msg = webutils.html_escape(msg % {'username': uname}) response.mustcontain(msg) def test_register_err_same_email(self): @@ -311,7 +311,7 @@ class TestLoginController(base.TestContr response.mustcontain('An email address must contain a single @') with test_context(self.app): msg = validators.ValidUsername()._messages['username_exists'] - msg = h.html_escape(msg % {'username': usr}) + msg = webutils.html_escape(msg % {'username': usr}) response.mustcontain(msg) def test_register_special_chars(self): diff --git a/kallithea/tests/functional/test_my_account.py b/kallithea/tests/functional/test_my_account.py --- a/kallithea/tests/functional/test_my_account.py +++ b/kallithea/tests/functional/test_my_account.py @@ -2,7 +2,7 @@ from tg.util.webtest import test_context -from kallithea.lib import helpers as h +from kallithea.lib import webutils from kallithea.model import db, meta from kallithea.model.user import UserModel from kallithea.tests import base @@ -186,7 +186,7 @@ class TestMyAccountController(base.TestC with test_context(self.app): msg = validators.ValidUsername(edit=False, old_data={}) \ ._messages['username_exists'] - msg = h.html_escape(msg % {'username': base.TEST_USER_ADMIN_LOGIN}) + msg = webutils.html_escape(msg % {'username': base.TEST_USER_ADMIN_LOGIN}) response.mustcontain(msg) def test_my_account_api_keys(self):