diff --git a/development.ini b/development.ini --- a/development.ini +++ b/development.ini @@ -219,10 +219,6 @@ issue_sub = ## handling that. Set this variable to 403 to return HTTPForbidden auth_ret_code = -## locking return code. When repository is locked return this HTTP code. 2XX -## codes don't break the transactions while 4XX codes do -lock_ret_code = 423 - ## allows to change the repository location in settings page allow_repo_location_change = True diff --git a/docs/api/api.rst b/docs/api/api.rst --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -162,37 +162,6 @@ OUTPUT:: result : "Caches of repository ``" error : null -lock -^^^^ - -Set the locking state on the given repository by the given user. -If the param ``userid`` is skipped, it is set to the ID of the user who is calling this method. -If param ``locked`` is skipped, the current lock state of the repository is returned. -This command can only be executed using the api_key of a user with admin rights, or that of a regular user with admin or write access to the repository. - -INPUT:: - - id : - api_key : "" - method : "lock" - args : { - "repoid" : "" - "userid" : "", - "locked" : "" - } - -OUTPUT:: - - id : - result : { - "repo": "", - "locked": "", - "locked_since": "", - "locked_by": "", - "msg": "User `` set lock state for repo `` to ``" - } - error : null - get_ip ^^^^^^ @@ -601,7 +570,6 @@ OUTPUT:: "repo_type" : "", "clone_uri" : "", "enable_downloads": "", - "enable_locking": "", "enable_statistics": "", "private": "", "created_on" : "", @@ -755,7 +723,6 @@ OUTPUT:: "owner": "", "fork_of": "", "enable_downloads": "", - "enable_locking": "", "enable_statistics": "", }, … @@ -820,7 +787,6 @@ INPUT:: "clone_uri" : " = Optional(None)", "landing_rev" : " = Optional('tip')", "enable_downloads": " = Optional(False)", - "enable_locking": " = Optional(False)", "enable_statistics": " = Optional(False)", } @@ -841,7 +807,6 @@ OUTPUT:: "owner": "", "fork_of": "", "enable_downloads": "", - "enable_locking": "", "enable_statistics": "", }, } @@ -870,7 +835,6 @@ INPUT:: "clone_uri" : " = Optional(None)", "landing_rev" : " = Optional('tip')", "enable_downloads": " = Optional(False)", - "enable_locking": " = Optional(False)", "enable_statistics": " = Optional(False)", } @@ -891,7 +855,6 @@ OUTPUT:: "owner": "", "fork_of": "", "enable_downloads": "", - "enable_locking": "", "enable_statistics": "", "last_changeset": { "author": "", @@ -901,8 +864,6 @@ OUTPUT:: "revision": "", "short_id": "" } - "locked_by": "", - "locked_date": "", }, } error: null diff --git a/docs/index.rst b/docs/index.rst --- a/docs/index.rst +++ b/docs/index.rst @@ -63,7 +63,6 @@ User guide usage/general usage/vcs_notes - usage/locking usage/statistics api/api diff --git a/docs/usage/locking.rst b/docs/usage/locking.rst deleted file mode 100644 --- a/docs/usage/locking.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _locking: - -================== -Repository locking -================== - -Kallithea has a *repository locking* feature, disabled by default. When -enabled, every initial clone and every pull gives users (with write permission) -the exclusive right to do a push. - -When repository locking is enabled, repositories get a ``locked`` flag. -The hg/git commands ``hg/git clone``, ``hg/git pull``, -and ``hg/git push`` influence this state: - -- A ``clone`` or ``pull`` action locks the target repository - if the user has write/admin permissions on this repository. - -- Kallithea will remember the user who locked the repository so only this - specific user can unlock the repo by performing a ``push`` - command. - -- Every other command on a locked repository from this user and every command - from any other user will result in an HTTP return code 423 (Locked). - Additionally, the HTTP error will mention the user that locked the repository - (e.g., “repository locked by user ”). - -Each repository can be manually unlocked by an administrator from the -repository settings menu. diff --git a/kallithea/alembic/versions/ad357ccd9521_drop_locking.py b/kallithea/alembic/versions/ad357ccd9521_drop_locking.py new file mode 100644 --- /dev/null +++ b/kallithea/alembic/versions/ad357ccd9521_drop_locking.py @@ -0,0 +1,59 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +"""Drop locking + +Revision ID: ad357ccd9521 +Revises: a020f7044fd6 +Create Date: 2019-01-08 + +""" + +# The following opaque hexadecimal identifiers ("revisions") are used +# by Alembic to track this migration script and its relations to others. +revision = 'ad357ccd9521' +down_revision = 'a020f7044fd6' +branch_labels = None +depends_on = None + +from alembic import op +import sqlalchemy as sa +from kallithea.model.db import Ui +from sqlalchemy import Table, MetaData + +meta = MetaData() + + +def upgrade(): + with op.batch_alter_table('groups', schema=None) as batch_op: + batch_op.drop_column('enable_locking') + + with op.batch_alter_table('repositories', schema=None) as batch_op: + batch_op.drop_column('locked') + batch_op.drop_column('enable_locking') + + meta.bind = op.get_bind() + ui = Table(Ui.__tablename__, meta, autoload=True) + ui.delete().where(ui.c.ui_key == 'prechangegroup.push_lock_handling').execute() + ui.delete().where(ui.c.ui_key == 'preoutgoing.pull_lock_handling').execute() + + +def downgrade(): + with op.batch_alter_table('repositories', schema=None) as batch_op: + batch_op.add_column(sa.Column('enable_locking', sa.BOOLEAN(), nullable=False, default=False)) + batch_op.add_column(sa.Column('locked', sa.VARCHAR(length=255), nullable=True, default=False)) + + with op.batch_alter_table('groups', schema=None) as batch_op: + batch_op.add_column(sa.Column('enable_locking', sa.BOOLEAN(), nullable=False, default=False)) + + # Note: not restoring hooks diff --git a/kallithea/config/routing.py b/kallithea/config/routing.py --- a/kallithea/config/routing.py +++ b/kallithea/config/routing.py @@ -533,13 +533,6 @@ def make_map(config): controller='admin/repos', action="edit_advanced", conditions=dict(method=["GET"], function=check_repo)) - rmap.connect("edit_repo_advanced_locking", "/{repo_name:.*?}/settings/advanced/locking", - controller='admin/repos', action="edit_advanced_locking", - conditions=dict(method=["POST"], function=check_repo)) - rmap.connect('toggle_locking', "/{repo_name:.*?}/settings/advanced/locking_toggle", - controller='admin/repos', action="toggle_locking", - conditions=dict(method=["GET"], function=check_repo)) - rmap.connect("edit_repo_advanced_journal", "/{repo_name:.*?}/settings/advanced/journal", controller='admin/repos', action="edit_advanced_journal", conditions=dict(method=["POST"], function=check_repo)) 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 @@ -478,46 +478,6 @@ class ReposController(BaseRepoController raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) @HasRepoPermissionLevelDecorator('admin') - def edit_advanced_locking(self, repo_name): - """ - Unlock repository when it is locked ! - - :param repo_name: - """ - try: - repo = Repository.get_by_repo_name(repo_name) - if request.POST.get('set_lock'): - Repository.lock(repo, request.authuser.user_id) - h.flash(_('Repository has been locked'), category='success') - elif request.POST.get('set_unlock'): - Repository.unlock(repo) - h.flash(_('Repository has been unlocked'), category='success') - except Exception as e: - log.error(traceback.format_exc()) - h.flash(_('An error occurred during unlocking'), - category='error') - raise HTTPFound(location=url('edit_repo_advanced', repo_name=repo_name)) - - @HasRepoPermissionLevelDecorator('write') - def toggle_locking(self, repo_name): - try: - repo = Repository.get_by_repo_name(repo_name) - - if repo.enable_locking: - if repo.locked[0]: - Repository.unlock(repo) - h.flash(_('Repository has been unlocked'), category='success') - else: - Repository.lock(repo, request.authuser.user_id) - h.flash(_('Repository has been locked'), category='success') - - except Exception as e: - log.error(traceback.format_exc()) - h.flash(_('An error occurred during unlocking'), - category='error') - raise HTTPFound(location=url('summary_home', repo_name=repo_name)) - - @HasRepoPermissionLevelDecorator('admin') def edit_caches(self, repo_name): c.repo_info = self._load_repo() c.active = 'caches' diff --git a/kallithea/controllers/api/api.py b/kallithea/controllers/api/api.py --- a/kallithea/controllers/api/api.py +++ b/kallithea/controllers/api/api.py @@ -303,168 +303,6 @@ class ApiController(JSONRPCController): 'Error occurred during cache invalidation action' ) - # permission check inside - def lock(self, repoid, locked=Optional(None), - userid=Optional(OAttr('apiuser'))): - """ - Set locking state on given repository by given user. If userid param - is skipped, then it is set to id of user who is calling this method. - If locked param is skipped then function shows current lock state of - given repo. This command can be executed only using api_key belonging - to user with admin rights or regular user that have admin or write - access to repository. - - :param repoid: repository name or repository id - :type repoid: str or int - :param locked: lock state to be set - :type locked: Optional(bool) - :param userid: set lock as user - :type userid: Optional(str or int) - - OUTPUT:: - - id : - result : { - 'repo': '', - 'locked': , - 'locked_since': , - 'locked_by': , - 'lock_state_changed': , - 'msg': 'Repo `` locked by `` on .' - or - 'msg': 'Repo `` not locked.' - or - 'msg': 'User `` set lock state for repo `` to ``' - } - error : null - - ERROR OUTPUT:: - - id : - result : null - error : { - 'Error occurred locking repository `` - } - - """ - repo = get_repo_or_error(repoid) - if HasPermissionAny('hg.admin')(): - pass - elif HasRepoPermissionLevel('write')(repo.repo_name): - # make sure normal user does not pass someone else userid, - # he is not allowed to do that - if not isinstance(userid, Optional) and userid != request.authuser.user_id: - raise JSONRPCError( - 'userid is not the same as your user' - ) - else: - raise JSONRPCError('repository `%s` does not exist' % (repoid,)) - - if isinstance(userid, Optional): - userid = request.authuser.user_id - - user = get_user_or_error(userid) - - if isinstance(locked, Optional): - lockobj = Repository.getlock(repo) - - if lockobj[0] is None: - _d = { - 'repo': repo.repo_name, - 'locked': False, - 'locked_since': None, - 'locked_by': None, - 'lock_state_changed': False, - 'msg': 'Repo `%s` not locked.' % repo.repo_name - } - return _d - else: - userid, time_ = lockobj - lock_user = get_user_or_error(userid) - _d = { - 'repo': repo.repo_name, - 'locked': True, - 'locked_since': time_, - 'locked_by': lock_user.username, - 'lock_state_changed': False, - 'msg': ('Repo `%s` locked by `%s` on `%s`.' - % (repo.repo_name, lock_user.username, - json.dumps(time_to_datetime(time_)))) - } - return _d - - # force locked state through a flag - else: - locked = str2bool(locked) - try: - if locked: - lock_time = time.time() - Repository.lock(repo, user.user_id, lock_time) - else: - lock_time = None - Repository.unlock(repo) - _d = { - 'repo': repo.repo_name, - 'locked': locked, - 'locked_since': lock_time, - 'locked_by': user.username, - 'lock_state_changed': True, - 'msg': ('User `%s` set lock state for repo `%s` to `%s`' - % (user.username, repo.repo_name, locked)) - } - return _d - except Exception: - log.error(traceback.format_exc()) - raise JSONRPCError( - 'Error occurred locking repository `%s`' % repo.repo_name - ) - - def get_locks(self, userid=Optional(OAttr('apiuser'))): - """ - Get all repositories with locks for given userid, if - this command is run by non-admin account userid is set to user - who is calling this method, thus returning locks for himself. - - :param userid: User to get locks for - :type userid: Optional(str or int) - - OUTPUT:: - - id : - result : { - [repo_object, repo_object,...] - } - error : null - """ - - if not HasPermissionAny('hg.admin')(): - # make sure normal user does not pass someone else userid, - # he is not allowed to do that - if not isinstance(userid, Optional) and userid != request.authuser.user_id: - raise JSONRPCError( - 'userid is not the same as your user' - ) - - ret = [] - if isinstance(userid, Optional): - user = None - else: - user = get_user_or_error(userid) - - # show all locks - for r in Repository.query(): - userid, time_ = r.locked - if time_: - _api_data = r.get_api_data() - # if we use userfilter just show the locks for this user - if user is not None: - if safe_int(userid) == user.user_id: - ret.append(_api_data) - else: - ret.append(_api_data) - - return ret - @HasPermissionAnyDecorator('hg.admin') def get_ip(self, userid=Optional(OAttr('apiuser'))): """ @@ -1155,7 +993,6 @@ class ApiController(JSONRPCController): "repo_type" : "", "clone_uri" : "", "enable_downloads": "", - "enable_locking": "", "enable_statistics": "", "private": "", "created_on" : "", @@ -1266,7 +1103,6 @@ class ApiController(JSONRPCController): "owner": "", "fork_of": "", "enable_downloads": "", - "enable_locking": "", "enable_statistics": "", }, … @@ -1346,7 +1182,6 @@ class ApiController(JSONRPCController): private=Optional(False), clone_uri=Optional(None), landing_rev=Optional('rev:tip'), enable_statistics=Optional(False), - enable_locking=Optional(False), enable_downloads=Optional(False), copy_permissions=Optional(False)): """ @@ -1371,8 +1206,6 @@ class ApiController(JSONRPCController): :type clone_uri: str :param landing_rev: : :type landing_rev: str - :param enable_locking: - :type enable_locking: bool :param enable_downloads: :type enable_downloads: bool :param enable_statistics: @@ -1421,8 +1254,6 @@ class ApiController(JSONRPCController): repo_type = defs.get('repo_type') if isinstance(enable_statistics, Optional): enable_statistics = defs.get('repo_enable_statistics') - if isinstance(enable_locking, Optional): - enable_locking = defs.get('repo_enable_locking') if isinstance(enable_downloads, Optional): enable_downloads = defs.get('repo_enable_downloads') @@ -1450,7 +1281,6 @@ class ApiController(JSONRPCController): repo_group=repo_group, repo_landing_rev=landing_rev, enable_statistics=enable_statistics, - enable_locking=enable_locking, enable_downloads=enable_downloads, repo_copy_permissions=copy_permissions, ) @@ -1476,7 +1306,6 @@ class ApiController(JSONRPCController): description=Optional(''), private=Optional(False), clone_uri=Optional(None), landing_rev=Optional('rev:tip'), enable_statistics=Optional(False), - enable_locking=Optional(False), enable_downloads=Optional(False)): """ @@ -1492,7 +1321,6 @@ class ApiController(JSONRPCController): :param clone_uri: :param landing_rev: :param enable_statistics: - :param enable_locking: :param enable_downloads: """ repo = get_repo_or_error(repoid) @@ -1525,7 +1353,6 @@ class ApiController(JSONRPCController): store_update(updates, clone_uri, 'clone_uri') store_update(updates, landing_rev, 'repo_landing_rev') store_update(updates, enable_statistics, 'repo_enable_statistics') - store_update(updates, enable_locking, 'repo_enable_locking') store_update(updates, enable_downloads, 'repo_enable_downloads') RepoModel().update(repo, **updates) @@ -2020,7 +1847,7 @@ class ApiController(JSONRPCController): def update_repo_group(self, repogroupid, group_name=Optional(''), description=Optional(''), owner=Optional(OAttr('apiuser')), - parent=Optional(None), enable_locking=Optional(False)): + parent=Optional(None)): repo_group = get_repo_group_or_error(repogroupid) updates = {} @@ -2029,7 +1856,6 @@ class ApiController(JSONRPCController): store_update(updates, description, 'group_description') store_update(updates, owner, 'owner') store_update(updates, parent, 'parent_group') - store_update(updates, enable_locking, 'enable_locking') repo_group = RepoGroupModel().update(repo_group, updates) Session().commit() return dict( diff --git a/kallithea/controllers/files.py b/kallithea/controllers/files.py --- a/kallithea/controllers/files.py +++ b/kallithea/controllers/files.py @@ -295,14 +295,6 @@ class FilesController(BaseRepoController @HasRepoPermissionLevelDecorator('write') def delete(self, repo_name, revision, f_path): repo = c.db_repo - if repo.enable_locking and repo.locked[0]: - h.flash(_('This repository has been locked by %s on %s') - % (h.person_by_id(repo.locked[0]), - h.fmt_date(h.time_to_datetime(repo.locked[1]))), - 'warning') - raise HTTPFound(location=h.url('files_home', - repo_name=repo_name, revision='tip')) - # check if revision is a branch identifier- basically we cannot # create multiple heads via file editing _branches = repo.scm_instance.branches @@ -355,14 +347,6 @@ class FilesController(BaseRepoController @HasRepoPermissionLevelDecorator('write') def edit(self, repo_name, revision, f_path): repo = c.db_repo - if repo.enable_locking and repo.locked[0]: - h.flash(_('This repository has been locked by %s on %s') - % (h.person_by_id(repo.locked[0]), - h.fmt_date(h.time_to_datetime(repo.locked[1]))), - 'warning') - raise HTTPFound(location=h.url('files_home', - repo_name=repo_name, revision='tip')) - # check if revision is a branch identifier- basically we cannot # create multiple heads via file editing _branches = repo.scm_instance.branches @@ -422,14 +406,6 @@ class FilesController(BaseRepoController def add(self, repo_name, revision, f_path): repo = c.db_repo - if repo.enable_locking and repo.locked[0]: - h.flash(_('This repository has been locked by %s on %s') - % (h.person_by_id(repo.locked[0]), - h.fmt_date(h.time_to_datetime(repo.locked[1]))), - 'warning') - raise HTTPFound(location=h.url('files_home', - repo_name=repo_name, revision='tip')) - r_post = request.POST c.cs = self.__get_cs(revision, silent_empty=True) if c.cs is None: diff --git a/kallithea/lib/base.py b/kallithea/lib/base.py --- a/kallithea/lib/base.py +++ b/kallithea/lib/base.py @@ -147,42 +147,6 @@ def log_in_user(user, remember, is_exter return auth_user -def check_locking_state(action, repo_name, user): - """ - Checks locking on this repository, if locking is enabled, and if lock - is present. Returns a tuple of make_lock, locked, locked_by. make_lock - can have 3 states: None (do nothing), True (make lock), and False - (release lock). This value is later propagated to hooks, telling them - what to do. - """ - locked = False # defines that locked error should be thrown to user - make_lock = None - repo = Repository.get_by_repo_name(repo_name) - locked_by = repo.locked - if repo and repo.enable_locking: - if action == 'push': - # Check if repo already is locked !, if it is compare users - user_id, _date = locked_by - if user.user_id == user_id: - log.debug('Got push from user %s, now unlocking', user) - # Unlock if we have push from the user who locked - make_lock = False - else: - # Another used tried to push - deny access with something like 423 Locked! - locked = True - if action == 'pull': - if repo.locked[0] and repo.locked[1]: - locked = True - else: - log.debug('Setting lock on repo %s by %s', repo, user) - make_lock = True - else: - log.debug('Repository %s does not have locking enabled', repo) - log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s', - make_lock, locked, locked_by) - return make_lock, locked, locked_by - - class BasicAuth(paste.auth.basic.AuthBasicAuthenticator): def __init__(self, realm, authfunc, auth_http_code=None): diff --git a/kallithea/lib/celerylib/tasks.py b/kallithea/lib/celerylib/tasks.py --- a/kallithea/lib/celerylib/tasks.py +++ b/kallithea/lib/celerylib/tasks.py @@ -349,7 +349,6 @@ def create_repo(form_data, cur_user): # repo creation defaults, private and repo_type are filled in form defs = Setting.get_default_repo_settings(strip_prefix=True) enable_statistics = defs.get('repo_enable_statistics') - enable_locking = defs.get('repo_enable_locking') enable_downloads = defs.get('repo_enable_downloads') try: @@ -366,7 +365,6 @@ def create_repo(form_data, cur_user): copy_fork_permissions=copy_fork_permissions, copy_group_permissions=copy_group_permissions, enable_statistics=enable_statistics, - enable_locking=enable_locking, enable_downloads=enable_downloads, state=state ) diff --git a/kallithea/lib/db_manage.py b/kallithea/lib/db_manage.py --- a/kallithea/lib/db_manage.py +++ b/kallithea/lib/db_manage.py @@ -240,7 +240,6 @@ class DbManage(object): """Creates default settings""" for k, v, t in [ - ('default_repo_enable_locking', False, 'bool'), ('default_repo_enable_downloads', False, 'bool'), ('default_repo_enable_statistics', False, 'bool'), ('default_repo_private', False, 'bool'), @@ -354,9 +353,7 @@ class DbManage(object): ('hooks', Ui.HOOK_UPDATE, 'hg update >&2', False), ('hooks', Ui.HOOK_REPO_SIZE, 'python:kallithea.lib.hooks.repo_size', True), ('hooks', Ui.HOOK_PUSH_LOG, 'python:kallithea.lib.hooks.log_push_action', True), - ('hooks', Ui.HOOK_PUSH_LOCK, 'python:kallithea.lib.hooks.push_lock_handling', True), ('hooks', Ui.HOOK_PULL_LOG, 'python:kallithea.lib.hooks.log_pull_action', True), - ('hooks', Ui.HOOK_PULL_LOCK, 'python:kallithea.lib.hooks.pull_lock_handling', True), ('extensions', 'largefiles', '', True), ('largefiles', 'usercache', os.path.join(path, '.cache', 'largefiles'), True), ('extensions', 'hgsubversion', '', False), diff --git a/kallithea/lib/exceptions.py b/kallithea/lib/exceptions.py --- a/kallithea/lib/exceptions.py +++ b/kallithea/lib/exceptions.py @@ -71,24 +71,6 @@ class NonRelativePathError(Exception): pass -class HTTPLockedRC(HTTPClientError): - """ - Special Exception For locked Repos in Kallithea, the return code can - be overwritten by _code keyword argument passed into constructors - """ - code = 423 - title = explanation = 'Repository Locked' - - def __init__(self, reponame, username, *args, **kwargs): - from kallithea import CONFIG - from kallithea.lib.utils2 import safe_int - _code = CONFIG.get('lock_ret_code') - self.code = safe_int(_code, self.code) - self.title = self.explanation = safe_str( - 'Repository `%s` locked by user `%s`' % (reponame, username)) - super(HTTPLockedRC, self).__init__(*args, **kwargs) - - class IMCCommitError(Exception): pass diff --git a/kallithea/lib/hooks.py b/kallithea/lib/hooks.py --- a/kallithea/lib/hooks.py +++ b/kallithea/lib/hooks.py @@ -33,7 +33,7 @@ from kallithea.lib.vcs.utils.hgcompat im from kallithea.lib import helpers as h from kallithea.lib.utils import action_logger from kallithea.lib.vcs.backends.base import EmptyChangeset -from kallithea.lib.exceptions import HTTPLockedRC, UserCreationError +from kallithea.lib.exceptions import UserCreationError from kallithea.lib.utils import make_ui, setup_cache_regions from kallithea.lib.utils2 import safe_str, safe_unicode, _extract_extras from kallithea.model.db import Repository, User, Ui @@ -78,44 +78,8 @@ def repo_size(ui, repo, hooktype=None, * ui.status(msg) -def push_lock_handling(ui, repo, **kwargs): - """Pre push function, currently used to ban pushing when repository is locked. - - Called as Mercurial hook prechangegroup.push_lock_handling or from the Git pre-receive hook calling handle_git_pre_receive. - """ - ex = _extract_extras() - - usr = User.get_by_username(ex.username) - if ex.locked_by[0] and usr.user_id != int(ex.locked_by[0]): - locked_by = User.get(ex.locked_by[0]).username - # this exception is interpreted in git/hg middlewares and based - # on that proper return code is server to client - _http_ret = HTTPLockedRC(ex.repository, locked_by) - if str(_http_ret.code).startswith('2'): - # 2xx Codes don't raise exceptions - ui.status(safe_str(_http_ret.title)) - else: - raise _http_ret - - -def pull_lock_handling(ui, repo, **kwargs): - """Called as Mercurial hook preoutgoing.pull_lock_handling or from Kallithea before invoking Git""" - # pre pull function ... - ex = _extract_extras() - if ex.locked_by[0]: - locked_by = User.get(ex.locked_by[0]).username - # this exception is interpreted in git/hg middlewares and based - # on that proper return code is server to client - _http_ret = HTTPLockedRC(ex.repository, locked_by) - if str(_http_ret.code).startswith('2'): - # 2xx Codes don't raise exceptions - ui.status(safe_str(_http_ret.title)) - else: - raise _http_ret - - def log_pull_action(ui, repo, **kwargs): - """Logs user last pull action, and also handle locking + """Logs user last pull action Called as Mercurial hook outgoing.pull_logger or from Kallithea before invoking Git. """ @@ -132,17 +96,6 @@ def log_pull_action(ui, repo, **kwargs): kw.update(ex) callback(**kw) - if ex.make_lock is not None and ex.make_lock: - Repository.lock(Repository.get_by_repo_name(ex.repository), user.user_id) - #msg = 'Made lock on repo `%s`' % repository - #ui.status(msg) - - if ex.locked_by[0]: - locked_by = User.get(ex.locked_by[0]).username - _http_ret = HTTPLockedRC(ex.repository, locked_by) - if str(_http_ret.code).startswith('2'): - # 2xx Codes don't raise exceptions - ui.status(safe_str(_http_ret.title)) return 0 @@ -196,17 +149,6 @@ def log_push_action(ui, repo, **kwargs): kw.update(ex) callback(**kw) - if ex.make_lock is not None and not ex.make_lock: - Repository.unlock(Repository.get_by_repo_name(ex.repository)) - ui.status(safe_str('Released lock on repo `%s`\n' % ex.repository)) - - if ex.locked_by[0]: - locked_by = User.get(ex.locked_by[0]).username - _http_ret = HTTPLockedRC(ex.repository, locked_by) - if str(_http_ret.code).startswith('2'): - # 2xx Codes don't raise exceptions - ui.status(safe_str(_http_ret.title)) - return 0 @@ -406,9 +348,6 @@ def _hook_environment(repo_path): def handle_git_pre_receive(repo_path, git_stdin_lines): """Called from Git pre-receive hook""" - baseui, repo = _hook_environment(repo_path) - scm_repo = repo.scm_instance - push_lock_handling(baseui, scm_repo) return 0 diff --git a/kallithea/lib/middleware/simplegit.py b/kallithea/lib/middleware/simplegit.py --- a/kallithea/lib/middleware/simplegit.py +++ b/kallithea/lib/middleware/simplegit.py @@ -39,10 +39,8 @@ from kallithea.model.db import Ui from kallithea.lib.utils2 import safe_str, safe_unicode, fix_PATH, get_server_url, \ _set_extras -from kallithea.lib.base import BaseVCSController, check_locking_state +from kallithea.lib.base import BaseVCSController from kallithea.lib.utils import make_ui, is_valid_repo -from kallithea.lib.exceptions import HTTPLockedRC -from kallithea.lib.hooks import pull_lock_handling log = logging.getLogger(__name__) @@ -110,8 +108,6 @@ class SimpleGit(BaseVCSController): 'scm': 'git', 'config': CONFIG['__file__'], 'server_url': server_url, - 'make_lock': None, - 'locked_by': [None, None] } #=================================================================== @@ -120,13 +116,6 @@ class SimpleGit(BaseVCSController): repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s', repo_path) - if not user.is_default_user: - log.debug('Checking locking on repository') - make_lock, locked, locked_by = check_locking_state(action, repo_name, user) - # store the make_lock for later evaluation in hooks - extras.update({'make_lock': make_lock, - 'locked_by': locked_by}) - fix_PATH() log.debug('HOOKS extras is %s', extras) baseui = make_ui('db') @@ -138,9 +127,6 @@ class SimpleGit(BaseVCSController): action, str_repo_name, safe_str(user.username), ip_addr) app = self.__make_app(repo_name, repo_path, extras) return app(environ, start_response) - except HTTPLockedRC as e: - log.debug('Locked, response %s: %s', e.code, e.title) - return e(environ, start_response) except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) @@ -211,8 +197,5 @@ class SimpleGit(BaseVCSController): _repo = _repo.scm_instance _hooks = dict(baseui.configitems('hooks')) or {} - if action == 'pull': - # stupid git, emulate pre-pull hook ! - pull_lock_handling(ui=baseui, repo=_repo._repo) if action == 'pull' and _hooks.get(Ui.HOOK_PULL_LOG): log_pull_action(ui=baseui, repo=_repo._repo) diff --git a/kallithea/lib/middleware/simplehg.py b/kallithea/lib/middleware/simplehg.py --- a/kallithea/lib/middleware/simplehg.py +++ b/kallithea/lib/middleware/simplehg.py @@ -38,10 +38,9 @@ from webob.exc import HTTPNotFound, HTTP from kallithea.lib.utils2 import safe_str, safe_unicode, fix_PATH, get_server_url, \ _set_extras -from kallithea.lib.base import BaseVCSController, check_locking_state +from kallithea.lib.base import BaseVCSController from kallithea.lib.utils import make_ui, is_valid_repo, ui_sections from kallithea.lib.vcs.utils.hgcompat import RepoError, hgweb_mod -from kallithea.lib.exceptions import HTTPLockedRC log = logging.getLogger(__name__) @@ -134,8 +133,6 @@ class SimpleHg(BaseVCSController): 'scm': 'hg', 'config': CONFIG['__file__'], 'server_url': server_url, - 'make_lock': None, - 'locked_by': [None, None] } #====================================================================== # MERCURIAL REQUEST HANDLING @@ -143,19 +140,6 @@ class SimpleHg(BaseVCSController): repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s', repo_path) - # A Mercurial HTTP server will see listkeys operations (bookmarks, - # phases and obsolescence marker) in a different request - we don't - # want to check locking on those - if environ['QUERY_STRING'] == 'cmd=listkeys': - pass - # CHECK LOCKING only if it's not ANONYMOUS USER - elif not user.is_default_user: - log.debug('Checking locking on repository') - make_lock, locked, locked_by = check_locking_state(action, repo_name, user) - # store the make_lock for later evaluation in hooks - extras.update({'make_lock': make_lock, - 'locked_by': locked_by}) - fix_PATH() log.debug('HOOKS extras is %s', extras) baseui = make_ui('db') @@ -171,10 +155,6 @@ class SimpleHg(BaseVCSController): except RepoError as e: if str(e).find('not found') != -1: return HTTPNotFound()(environ, start_response) - except HTTPLockedRC as e: - # Before Mercurial 3.6, lock exceptions were caught here - log.debug('Locked, response %s: %s', e.code, e.title) - return e(environ, start_response) except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) @@ -184,26 +164,7 @@ class SimpleHg(BaseVCSController): Make an wsgi application using hgweb, and inject generated baseui instance, additionally inject some extras into ui object """ - class HgWebWrapper(hgweb_mod.hgweb): - # Work-around for Mercurial 3.6+ causing lock exceptions to be - # thrown late - def _runwsgi(self, *args): - try: - return super(HgWebWrapper, self)._runwsgi(*args) - except HTTPLockedRC as e: - log.debug('Locked, response %s: %s', e.code, e.title) - try: - req, res, repo = args - res.status = e.status - res.headers['Content-Type'] = 'text/plain' - res.setbodybytes('') - return res.sendresponse() - except ValueError: # wsgiresponse was introduced in Mercurial 4.6 (a88d68dc3ee8) - req, repo = args - req.respond(e.status, 'text/plain') - return '' - - return HgWebWrapper(repo_name, name=repo_name, baseui=baseui) + return hgweb_mod.hgweb(repo_name, name=repo_name, baseui=baseui) def __get_repository(self, environ): """ diff --git a/kallithea/lib/paster_commands/template.ini.mako b/kallithea/lib/paster_commands/template.ini.mako --- a/kallithea/lib/paster_commands/template.ini.mako +++ b/kallithea/lib/paster_commands/template.ini.mako @@ -316,10 +316,6 @@ issue_sub = <%text>## handling that. Set this variable to 403 to return HTTPForbidden auth_ret_code = -<%text>## locking return code. When repository is locked return this HTTP code. 2XX -<%text>## codes don't break the transactions while 4XX codes do -lock_ret_code = 423 - <%text>## allows to change the repository location in settings page allow_repo_location_change = True diff --git a/kallithea/lib/utils.py b/kallithea/lib/utils.py --- a/kallithea/lib/utils.py +++ b/kallithea/lib/utils.py @@ -481,7 +481,6 @@ def repo2db_mapper(initial_repo_list, re # creation defaults defs = Setting.get_default_repo_settings(strip_prefix=True) enable_statistics = defs.get('repo_enable_statistics') - enable_locking = defs.get('repo_enable_locking') enable_downloads = defs.get('repo_enable_downloads') private = defs.get('repo_private') @@ -503,7 +502,6 @@ def repo2db_mapper(initial_repo_list, re description=desc, repo_group=getattr(group, 'group_id', None), owner=user, - enable_locking=enable_locking, enable_downloads=enable_downloads, enable_statistics=enable_statistics, private=private, diff --git a/kallithea/lib/utils2.py b/kallithea/lib/utils2.py --- a/kallithea/lib/utils2.py +++ b/kallithea/lib/utils2.py @@ -549,8 +549,7 @@ def _extract_extras(): raise Exception("Environment variable KALLITHEA_EXTRAS not found") try: - for k in ['username', 'repository', 'locked_by', 'scm', 'make_lock', - 'action', 'ip']: + for k in ['username', 'repository', 'scm', 'action', 'ip']: extras[k] except KeyError: raise Exception('Missing key %s in KALLITHEA_EXTRAS %s' % (k, extras)) diff --git a/kallithea/model/db.py b/kallithea/model/db.py --- a/kallithea/model/db.py +++ b/kallithea/model/db.py @@ -352,9 +352,7 @@ class Ui(Base, BaseDbModel): HOOK_UPDATE = 'changegroup.update' HOOK_REPO_SIZE = 'changegroup.repo_size' HOOK_PUSH_LOG = 'changegroup.push_logger' - HOOK_PUSH_LOCK = 'prechangegroup.push_lock_handling' HOOK_PULL_LOG = 'outgoing.pull_logger' - HOOK_PULL_LOCK = 'preoutgoing.pull_lock_handling' ui_id = Column(Integer(), primary_key=True) ui_section = Column(String(255), nullable=False) @@ -380,8 +378,7 @@ class Ui(Base, BaseDbModel): def get_builtin_hooks(cls): q = cls.query() q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE, - cls.HOOK_PUSH_LOG, cls.HOOK_PUSH_LOCK, - cls.HOOK_PULL_LOG, cls.HOOK_PULL_LOCK])) + cls.HOOK_PUSH_LOG, cls.HOOK_PULL_LOG])) q = q.filter(cls.ui_section == 'hooks') return q.all() @@ -389,8 +386,7 @@ class Ui(Base, BaseDbModel): def get_custom_hooks(cls): q = cls.query() q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE, - cls.HOOK_PUSH_LOG, cls.HOOK_PUSH_LOCK, - cls.HOOK_PULL_LOG, cls.HOOK_PULL_LOCK])) + cls.HOOK_PUSH_LOG, cls.HOOK_PULL_LOG])) q = q.filter(cls.ui_section == 'hooks') return q.all() @@ -994,8 +990,6 @@ class Repository(Base, BaseDbModel): created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now) updated_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now) _landing_revision = Column("landing_revision", String(255), nullable=False) - enable_locking = Column(Boolean(), nullable=False, default=False) - _locked = Column("locked", String(255), nullable=True) # FIXME: not nullable? _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) # JSON data # FIXME: not nullable? fork_id = Column(Integer(), ForeignKey('repositories.repo_id'), nullable=True) @@ -1047,21 +1041,6 @@ class Repository(Base, BaseDbModel): self._landing_revision = val @hybrid_property - def locked(self): - # always should return [user_id, timelocked] - if self._locked: - _lock_info = self._locked.split(':') - return int(_lock_info[0]), _lock_info[1] - return [None, None] - - @locked.setter - def locked(self, val): - if val and isinstance(val, (list, tuple)): - self._locked = ':'.join(map(str, val)) - else: - self._locked = None - - @hybrid_property def changeset_cache(self): try: cs_cache = json.loads(self._changeset_cache) # might raise on bad data @@ -1254,13 +1233,8 @@ class Repository(Base, BaseDbModel): owner=repo.owner.username, fork_of=repo.fork.repo_name if repo.fork else None, enable_statistics=repo.enable_statistics, - enable_locking=repo.enable_locking, enable_downloads=repo.enable_downloads, last_changeset=repo.changeset_cache, - locked_by=User.get(self.locked[0]).get_api_data() \ - if self.locked[0] else None, - locked_date=time_to_datetime(self.locked[1]) \ - if self.locked[1] else None ) if with_revision_names: scm_repo = repo.scm_instance_no_cache() @@ -1279,22 +1253,6 @@ class Repository(Base, BaseDbModel): return data - @classmethod - def lock(cls, repo, user_id, lock_time=None): - if lock_time is not None: - lock_time = time.time() - repo.locked = [user_id, lock_time] - Session().commit() - - @classmethod - def unlock(cls, repo): - repo.locked = None - Session().commit() - - @classmethod - def getlock(cls, repo): - return repo.locked - @property def last_db_change(self): return self.updated_on @@ -1524,7 +1482,6 @@ class RepoGroup(Base, BaseDbModel): group_name = Column(Unicode(255), nullable=False, unique=True) # full path parent_group_id = Column('group_parent_id', Integer(), ForeignKey('groups.group_id'), nullable=True) group_description = Column(Unicode(10000), nullable=False) - enable_locking = Column(Boolean(), nullable=False, default=False) owner_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False) created_on = Column(DateTime(timezone=False), nullable=False, default=datetime.datetime.now) diff --git a/kallithea/model/forms.py b/kallithea/model/forms.py --- a/kallithea/model/forms.py +++ b/kallithea/model/forms.py @@ -182,7 +182,6 @@ def RepoGroupForm(edit=False, old_data=N testValueList=True, if_missing=None, not_empty=True), v.Int(min=-1, not_empty=True)) - enable_locking = v.StringBoolean(if_missing=False) chained_validators = [v.ValidRepoGroup(edit, old_data)] return _RepoGroupForm @@ -264,7 +263,6 @@ def RepoForm(edit=False, old_data=None, repo_enable_statistics = v.StringBoolean(if_missing=False) repo_enable_downloads = v.StringBoolean(if_missing=False) - repo_enable_locking = v.StringBoolean(if_missing=False) if edit: owner = All(v.UnicodeString(not_empty=True), v.ValidRepoUser()) @@ -447,7 +445,6 @@ def DefaultsForm(edit=False, old_data=No default_repo_private = v.StringBoolean(if_missing=False) default_repo_enable_statistics = v.StringBoolean(if_missing=False) default_repo_enable_downloads = v.StringBoolean(if_missing=False) - default_repo_enable_locking = v.StringBoolean(if_missing=False) return _DefaultsForm diff --git a/kallithea/model/repo.py b/kallithea/model/repo.py --- a/kallithea/model/repo.py +++ b/kallithea/model/repo.py @@ -236,7 +236,7 @@ class RepoModel(object): defaults['repo_group'] = repo_info.group_id for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'), - (1, 'repo_description'), (1, 'repo_enable_locking'), + (1, 'repo_description'), (1, 'repo_landing_rev'), (0, 'clone_uri'), (1, 'repo_private'), (1, 'repo_enable_statistics')]: attr = k @@ -284,7 +284,6 @@ class RepoModel(object): log.debug('Updating repo %s with params:%s', cur_repo, kwargs) for k in ['repo_enable_downloads', 'repo_description', - 'repo_enable_locking', 'repo_landing_rev', 'repo_private', 'repo_enable_statistics', @@ -332,7 +331,7 @@ class RepoModel(object): private=False, clone_uri=None, repo_group=None, landing_rev='rev:tip', fork_of=None, copy_fork_permissions=False, enable_statistics=False, - enable_locking=False, enable_downloads=False, + enable_downloads=False, copy_group_permissions=False, state=Repository.STATE_PENDING): """ Create repository inside database with PENDING state. This should only be @@ -371,12 +370,8 @@ class RepoModel(object): new_repo.landing_rev = landing_rev new_repo.enable_statistics = enable_statistics - new_repo.enable_locking = enable_locking new_repo.enable_downloads = enable_downloads - if repo_group: - new_repo.enable_locking = repo_group.enable_locking - if fork_of: parent_repo = fork_of new_repo.fork = parent_repo diff --git a/kallithea/model/repo_group.py b/kallithea/model/repo_group.py --- a/kallithea/model/repo_group.py +++ b/kallithea/model/repo_group.py @@ -287,8 +287,6 @@ class RepoGroupModel(object): repo_group.group_description = repo_group_args['group_description'] if 'parent_group_id' in repo_group_args: repo_group.parent_group_id = repo_group_args['parent_group_id'] - if 'enable_locking' in repo_group_args: - repo_group.enable_locking = repo_group_args['enable_locking'] if 'parent_group_id' in repo_group_args: assert repo_group_args['parent_group_id'] != u'-1', repo_group_args # RepoGroupForm should have converted to None @@ -302,14 +300,12 @@ class RepoGroupModel(object): Session().add(repo_group) # iterate over all members of this groups and do fixes - # set locking if given # if obj is a repoGroup also fix the name of the group according # to the parent # if obj is a Repo fix it's name # this can be potentially heavy operation for obj in repo_group.recursive_groups_and_repos(): # set the value from it's parent - obj.enable_locking = repo_group.enable_locking if isinstance(obj, RepoGroup): new_name = obj.get_new_name(obj.name) log.debug('Fixing group %s to new name %s' \ diff --git a/kallithea/model/scm.py b/kallithea/model/scm.py --- a/kallithea/model/scm.py +++ b/kallithea/model/scm.py @@ -348,8 +348,6 @@ class ScmModel(object): 'scm': repo_alias, 'config': CONFIG['__file__'], 'server_url': get_server_url(environ), - 'make_lock': None, - 'locked_by': [None, None] } _set_extras(extras) diff --git a/kallithea/model/validators.py b/kallithea/model/validators.py --- a/kallithea/model/validators.py +++ b/kallithea/model/validators.py @@ -625,7 +625,7 @@ def ValidSettings(): # with forms forbidden_params = [ - 'user', 'repo_type', 'repo_enable_locking', + 'user', 'repo_type', 'repo_enable_downloads', 'repo_enable_statistics' ] diff --git a/kallithea/templates/admin/defaults/defaults.html b/kallithea/templates/admin/defaults/defaults.html --- a/kallithea/templates/admin/defaults/defaults.html +++ b/kallithea/templates/admin/defaults/defaults.html @@ -55,14 +55,6 @@
- -
- ${h.checkbox('default_repo_enable_locking',value="True")} - ${_('Enable lock-by-pulling on repository.')} -
-
- -
${h.submit('save',_('Save'),class_="btn btn-default")}
diff --git a/kallithea/templates/admin/repo_groups/repo_group_edit_settings.html b/kallithea/templates/admin/repo_groups/repo_group_edit_settings.html --- a/kallithea/templates/admin/repo_groups/repo_group_edit_settings.html +++ b/kallithea/templates/admin/repo_groups/repo_group_edit_settings.html @@ -23,14 +23,6 @@ ${h.form(url('update_repos_group',group_
- -
- ${h.checkbox('enable_locking',value="True")} - ${_('Enable lock-by-pulling on group. This option will be applied to all other groups and repositories inside')} -
-
- -
${h.submit('save',_('Save'),class_="btn btn-default")} ${h.reset('reset',_('Reset'),class_="btn btn-default")} diff --git a/kallithea/templates/admin/repos/repo_edit_advanced.html b/kallithea/templates/admin/repos/repo_edit_advanced.html --- a/kallithea/templates/admin/repos/repo_edit_advanced.html +++ b/kallithea/templates/admin/repos/repo_edit_advanced.html @@ -39,32 +39,6 @@ ${h.form(url('edit_repo_advanced_journal
${h.end_form()} -

${_('Change Locking')}

-${h.form(url('edit_repo_advanced_locking', repo_name=c.repo_info.repo_name))} -
- %if c.repo_info.locked[0]: - ${h.hidden('set_unlock', '1')} - - ${_('Locked by %s on %s') % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))} - %else: - ${h.hidden('set_lock', '1')} - - ${_('Repository is not locked')} - %endif -
- ${_('Force locking on the repository. Works only when anonymous access is disabled. Triggering a pull locks the repository. The user who is pulling locks the repository; only the user who pulled and locked it can unlock it by doing a push.')} -
-
-${h.end_form()} -

${_('Delete')}

${h.form(url('delete_repo', repo_name=c.repo_name))}
diff --git a/kallithea/templates/admin/repos/repo_edit_settings.html b/kallithea/templates/admin/repos/repo_edit_settings.html --- a/kallithea/templates/admin/repos/repo_edit_settings.html +++ b/kallithea/templates/admin/repos/repo_edit_settings.html @@ -74,13 +74,6 @@ ${h.form(url('update_repo', repo_name=c. ${_('Enable download menu on summary page.')}
-
- -
- ${h.checkbox('repo_enable_locking',value="True")} - ${_('Enable lock-by-pulling on repository.')} -
-
%if c.visual.repository_fields: ## EXTRA FIELDS diff --git a/kallithea/templates/base/base.html b/kallithea/templates/base/base.html --- a/kallithea/templates/base/base.html +++ b/kallithea/templates/base/base.html @@ -159,13 +159,6 @@
  • ${_('Search')}
  • - %if h.HasRepoPermissionLevel('write')(c.repo_name) and c.db_repo.enable_locking: - %if c.db_repo.locked[0]: -
  • ${_('Unlock')}
  • - %else: -
  • ${_('Lock')}
  • - %endif - %endif ## TODO: this check feels wrong, it would be better to have a check for permissions ## also it feels like a job for the controller %if request.authuser.username != 'default': diff --git a/kallithea/templates/summary/summary.html b/kallithea/templates/summary/summary.html --- a/kallithea/templates/summary/summary.html +++ b/kallithea/templates/summary/summary.html @@ -8,15 +8,6 @@ <%def name="breadcrumbs_links()"> ${_('Summary')} - ## locking icon - %if c.db_repo.enable_locking: - %if c.db_repo.locked[0]: - - %else: - - %endif - %endif - ##FORK %if c.db_repo.fork: - ${_('Fork of')} "${c.db_repo.fork.repo_name}" diff --git a/kallithea/tests/api/api_base.py b/kallithea/tests/api/api_base.py --- a/kallithea/tests/api/api_base.py +++ b/kallithea/tests/api/api_base.py @@ -386,205 +386,6 @@ class _BaseTestApi(object): expected = "repository `%s` does not exist" % (self.REPO,) self._compare_error(id_, expected, given=response.body) - def test_api_lock_repo_lock_acquire(self): - try: - id_, params = _build_data(self.apikey, 'lock', - userid=TEST_USER_ADMIN_LOGIN, - repoid=self.REPO, - locked=True) - response = api_call(self, params) - expected = { - 'repo': self.REPO, 'locked': True, - 'locked_since': response.json['result']['locked_since'], - 'locked_by': TEST_USER_ADMIN_LOGIN, - 'lock_state_changed': True, - 'msg': ('User `%s` set lock state for repo `%s` to `%s`' - % (TEST_USER_ADMIN_LOGIN, self.REPO, True)) - } - self._compare_ok(id_, expected, given=response.body) - finally: - # cleanup - Repository.unlock(RepoModel().get_by_repo_name(self.REPO)) - - def test_api_lock_repo_lock_acquire_by_non_admin(self): - repo_name = u'api_delete_me' - fixture.create_repo(repo_name, repo_type=self.REPO_TYPE, - cur_user=self.TEST_USER_LOGIN) - try: - id_, params = _build_data(self.apikey_regular, 'lock', - repoid=repo_name, - locked=True) - response = api_call(self, params) - expected = { - 'repo': repo_name, - 'locked': True, - 'locked_since': response.json['result']['locked_since'], - 'locked_by': self.TEST_USER_LOGIN, - 'lock_state_changed': True, - 'msg': ('User `%s` set lock state for repo `%s` to `%s`' - % (self.TEST_USER_LOGIN, repo_name, True)) - } - self._compare_ok(id_, expected, given=response.body) - finally: - fixture.destroy_repo(repo_name) - - def test_api_lock_repo_lock_acquire_non_admin_with_userid(self): - repo_name = u'api_delete_me' - fixture.create_repo(repo_name, repo_type=self.REPO_TYPE, - cur_user=self.TEST_USER_LOGIN) - try: - id_, params = _build_data(self.apikey_regular, 'lock', - userid=TEST_USER_ADMIN_LOGIN, - repoid=repo_name, - locked=True) - response = api_call(self, params) - expected = 'userid is not the same as your user' - self._compare_error(id_, expected, given=response.body) - finally: - fixture.destroy_repo(repo_name) - - def test_api_lock_repo_lock_acquire_non_admin_not_his_repo(self): - id_, params = _build_data(self.apikey_regular, 'lock', - repoid=self.REPO, - locked=True) - response = api_call(self, params) - expected = 'repository `%s` does not exist' % (self.REPO) - self._compare_error(id_, expected, given=response.body) - - def test_api_lock_repo_lock_release(self): - id_, params = _build_data(self.apikey, 'lock', - userid=TEST_USER_ADMIN_LOGIN, - repoid=self.REPO, - locked=False) - response = api_call(self, params) - expected = { - 'repo': self.REPO, - 'locked': False, - 'locked_since': None, - 'locked_by': TEST_USER_ADMIN_LOGIN, - 'lock_state_changed': True, - 'msg': ('User `%s` set lock state for repo `%s` to `%s`' - % (TEST_USER_ADMIN_LOGIN, self.REPO, False)) - } - self._compare_ok(id_, expected, given=response.body) - - # test_api_lock_repo_lock_optional_not_locked(self): - id_, params = _build_data(self.apikey, 'lock', - repoid=self.REPO) - response = api_call(self, params) - expected = { - 'repo': self.REPO, - 'locked': False, - 'locked_since': None, - 'locked_by': None, - 'lock_state_changed': False, - 'msg': ('Repo `%s` not locked.' % (self.REPO,)) - } - self._compare_ok(id_, expected, given=response.body) - - def test_api_lock_repo_lock_acquire_optional_userid(self): - try: - id_, params = _build_data(self.apikey, 'lock', - repoid=self.REPO, - locked=True) - response = api_call(self, params) - time_ = response.json['result']['locked_since'] - expected = { - 'repo': self.REPO, - 'locked': True, - 'locked_since': time_, - 'locked_by': TEST_USER_ADMIN_LOGIN, - 'lock_state_changed': True, - 'msg': ('User `%s` set lock state for repo `%s` to `%s`' - % (TEST_USER_ADMIN_LOGIN, self.REPO, True)) - } - - self._compare_ok(id_, expected, given=response.body) - - # test_api_lock_repo_lock_optional_locked - id_, params = _build_data(self.apikey, 'lock', - repoid=self.REPO) - response = api_call(self, params) - time_ = response.json['result']['locked_since'] - expected = { - 'repo': self.REPO, - 'locked': True, - 'locked_since': time_, - 'locked_by': TEST_USER_ADMIN_LOGIN, - 'lock_state_changed': False, - 'msg': ('Repo `%s` locked by `%s` on `%s`.' - % (self.REPO, TEST_USER_ADMIN_LOGIN, - json.dumps(time_to_datetime(time_)))) - } - self._compare_ok(id_, expected, given=response.body) - finally: - # cleanup - Repository.unlock(RepoModel().get_by_repo_name(self.REPO)) - - @mock.patch.object(Repository, 'lock', crash) - def test_api_lock_error(self): - id_, params = _build_data(self.apikey, 'lock', - userid=TEST_USER_ADMIN_LOGIN, - repoid=self.REPO, - locked=True) - response = api_call(self, params) - - expected = 'Error occurred locking repository `%s`' % self.REPO - self._compare_error(id_, expected, given=response.body) - - def test_api_get_locks_regular_user(self): - id_, params = _build_data(self.apikey_regular, 'get_locks') - response = api_call(self, params) - expected = [] - self._compare_ok(id_, expected, given=response.body) - - def test_api_get_locks_with_userid_regular_user(self): - id_, params = _build_data(self.apikey_regular, 'get_locks', - userid=TEST_USER_ADMIN_LOGIN) - response = api_call(self, params) - expected = 'userid is not the same as your user' - self._compare_error(id_, expected, given=response.body) - - def test_api_get_locks(self): - id_, params = _build_data(self.apikey, 'get_locks') - response = api_call(self, params) - expected = [] - self._compare_ok(id_, expected, given=response.body) - - def test_api_get_locks_with_one_locked_repo(self): - repo_name = u'api_delete_me' - repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE, - cur_user=self.TEST_USER_LOGIN) - Repository.lock(repo, User.get_by_username(self.TEST_USER_LOGIN).user_id) - try: - id_, params = _build_data(self.apikey, 'get_locks') - response = api_call(self, params) - expected = [repo.get_api_data()] - self._compare_ok(id_, expected, given=response.body) - finally: - fixture.destroy_repo(repo_name) - - def test_api_get_locks_with_one_locked_repo_for_specific_user(self): - repo_name = u'api_delete_me' - repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE, - cur_user=self.TEST_USER_LOGIN) - Repository.lock(repo, User.get_by_username(self.TEST_USER_LOGIN).user_id) - try: - id_, params = _build_data(self.apikey, 'get_locks', - userid=self.TEST_USER_LOGIN) - response = api_call(self, params) - expected = [repo.get_api_data()] - self._compare_ok(id_, expected, given=response.body) - finally: - fixture.destroy_repo(repo_name) - - def test_api_get_locks_with_userid(self): - id_, params = _build_data(self.apikey, 'get_locks', - userid=TEST_USER_REGULAR_LOGIN) - response = api_call(self, params) - expected = [] - self._compare_ok(id_, expected, given=response.body) - def test_api_create_existing_user(self): id_, params = _build_data(self.apikey, 'create_user', username=TEST_USER_ADMIN_LOGIN, @@ -1259,7 +1060,6 @@ class _BaseTestApi(object): ('clone_uri', {'clone_uri': None}), ('landing_rev', {'landing_rev': 'branch:master'}), ('enable_statistics', {'enable_statistics': True}), - ('enable_locking', {'enable_locking': True}), ('enable_downloads', {'enable_downloads': True}), ('name', {'name': u'new_repo_name'}), ('repo_group', {'group': u'test_group_for_update'}), @@ -1300,7 +1100,6 @@ class _BaseTestApi(object): ('clone_uri', {'clone_uri': None}), ('landing_rev', {'landing_rev': 'branch:master'}), ('enable_statistics', {'enable_statistics': True}), - ('enable_locking', {'enable_locking': True}), ('enable_downloads', {'enable_downloads': True}), ('name', {'name': u'new_repo_name'}), ('repo_group', {'group': u'test_group_for_update'}), diff --git a/kallithea/tests/fixture.py b/kallithea/tests/fixture.py --- a/kallithea/tests/fixture.py +++ b/kallithea/tests/fixture.py @@ -117,7 +117,6 @@ class Fixture(object): parent_group_id=u'-1', perms_updates=[], perms_new=[], - enable_locking=False, recursive=False ) defs.update(custom) diff --git a/kallithea/tests/functional/test_admin_defaults.py b/kallithea/tests/functional/test_admin_defaults.py --- a/kallithea/tests/functional/test_admin_defaults.py +++ b/kallithea/tests/functional/test_admin_defaults.py @@ -10,12 +10,10 @@ class TestDefaultsController(TestControl response.mustcontain('default_repo_private') response.mustcontain('default_repo_enable_statistics') response.mustcontain('default_repo_enable_downloads') - response.mustcontain('default_repo_enable_locking') def test_update_params_true_hg(self): self.log_user() params = { - 'default_repo_enable_locking': True, 'default_repo_enable_downloads': True, 'default_repo_enable_statistics': True, 'default_repo_private': True, @@ -32,7 +30,6 @@ class TestDefaultsController(TestControl def test_update_params_false_git(self): self.log_user() params = { - 'default_repo_enable_locking': False, 'default_repo_enable_downloads': False, 'default_repo_enable_statistics': False, 'default_repo_private': False, diff --git a/kallithea/tests/other/test_vcs_operations.py b/kallithea/tests/other/test_vcs_operations.py --- a/kallithea/tests/other/test_vcs_operations.py +++ b/kallithea/tests/other/test_vcs_operations.py @@ -176,17 +176,6 @@ class TestVCSOperations(TestController): # DISABLE ANONYMOUS ACCESS set_anonymous_access(False) - def setup_method(self, method): - r = Repository.get_by_repo_name(GIT_REPO) - Repository.unlock(r) - r.enable_locking = False - Session().commit() - - r = Repository.get_by_repo_name(HG_REPO) - Repository.unlock(r) - r.enable_locking = False - Session().commit() - @pytest.fixture() def testhook_cleanup(self): yield @@ -434,157 +423,6 @@ class TestVCSOperations(TestController): assert 'not found' in stderr - def test_clone_and_create_lock_hg(self, webserver): - # enable locking - r = Repository.get_by_repo_name(HG_REPO) - r.enable_locking = True - Session().commit() - # clone - clone_url = webserver.repo_url(HG_REPO) - stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir()) - - # check if lock was made - r = Repository.get_by_repo_name(HG_REPO) - assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id - - def test_clone_and_create_lock_git(self, webserver): - # enable locking - r = Repository.get_by_repo_name(GIT_REPO) - r.enable_locking = True - Session().commit() - # clone - clone_url = webserver.repo_url(GIT_REPO) - stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir()) - - # check if lock was made - r = Repository.get_by_repo_name(GIT_REPO) - assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id - - def test_clone_after_repo_was_locked_hg(self, webserver): - # lock repo - r = Repository.get_by_repo_name(HG_REPO) - Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) - # pull fails since repo is locked - clone_url = webserver.repo_url(HG_REPO) - stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True) - msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`""" - % (HG_REPO, TEST_USER_ADMIN_LOGIN)) - assert msg in stderr - - def test_clone_after_repo_was_locked_git(self, webserver): - # lock repo - r = Repository.get_by_repo_name(GIT_REPO) - Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) - # pull fails since repo is locked - clone_url = webserver.repo_url(GIT_REPO) - stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True) - msg = ("""The requested URL returned error: 423""") - assert msg in stderr - - def test_push_on_locked_repo_by_other_user_hg(self, webserver): - # clone some temp - dest_dir = _get_tmp_dir() - clone_url = webserver.repo_url(HG_REPO) - stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, dest_dir) - - # lock repo - r = Repository.get_by_repo_name(HG_REPO) - # let this user actually push ! - RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, - perm='repository.write') - Session().commit() - Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) - - # push fails repo is locked by other user ! - stdout, stderr = _add_files_and_push(webserver, 'hg', dest_dir, - username=TEST_USER_REGULAR_LOGIN, - password=TEST_USER_REGULAR_PASS, - ignoreReturnCode=True) - msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`""" - % (HG_REPO, TEST_USER_ADMIN_LOGIN)) - assert msg in stderr - - def test_push_on_locked_repo_by_other_user_git(self, webserver): - # Note: Git hooks must be executable on unix. This test will thus fail - # for example on Linux if /tmp is mounted noexec. - - # clone some temp - dest_dir = _get_tmp_dir() - clone_url = webserver.repo_url(GIT_REPO) - stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, dest_dir) - - # lock repo - r = Repository.get_by_repo_name(GIT_REPO) - # let this user actually push ! - RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN, - perm='repository.write') - Session().commit() - Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id) - - # push fails repo is locked by other user ! - stdout, stderr = _add_files_and_push(webserver, 'git', dest_dir, - username=TEST_USER_REGULAR_LOGIN, - password=TEST_USER_REGULAR_PASS, - ignoreReturnCode=True) - err = 'Repository `%s` locked by user `%s`' % (GIT_REPO, TEST_USER_ADMIN_LOGIN) - assert err in stderr - - # TODO: fix this somehow later on Git, Git is stupid and even if we throw - # back 423 to it, it makes ANOTHER request and we fail there with 405 :/ - - msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`""" - % (GIT_REPO, TEST_USER_ADMIN_LOGIN)) - #msg = "405 Method Not Allowed" - #assert msg in stderr - - def test_push_unlocks_repository_hg(self, webserver, testfork): - # enable locking - r = Repository.get_by_repo_name(testfork['hg']) - r.enable_locking = True - Session().commit() - # clone some temp - dest_dir = _get_tmp_dir() - clone_url = webserver.repo_url(testfork['hg']) - stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, dest_dir) - - # check for lock repo after clone - r = Repository.get_by_repo_name(testfork['hg']) - uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id - assert r.locked[0] == uid - - # push is ok and repo is now unlocked - stdout, stderr = _add_files_and_push(webserver, 'hg', dest_dir, clone_url=clone_url) - assert str('remote: Released lock on repo `%s`' % testfork['hg']) in stdout - # we need to cleanup the Session Here ! - Session.remove() - r = Repository.get_by_repo_name(testfork['hg']) - assert r.locked == [None, None] - - # TODO: fix me ! somehow during tests hooks don't get called on Git - def test_push_unlocks_repository_git(self, webserver, testfork): - # enable locking - r = Repository.get_by_repo_name(testfork['git']) - r.enable_locking = True - Session().commit() - # clone some temp - dest_dir = _get_tmp_dir() - clone_url = webserver.repo_url(testfork['git']) - stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, dest_dir) - - # check for lock repo after clone - r = Repository.get_by_repo_name(testfork['git']) - assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id - - # push is ok and repo is now unlocked - stdout, stderr = _add_files_and_push(webserver, 'git', dest_dir, clone_url=clone_url) - _check_proper_git_push(stdout, stderr) - - assert ('remote: Released lock on repo `%s`' % testfork['git']) in stderr - # we need to cleanup the Session Here ! - Session.remove() - r = Repository.get_by_repo_name(testfork['git']) - assert r.locked == [None, None] - def test_ip_restriction_hg(self, webserver): user_model = UserModel() try: