diff --git a/seahub/base/management/commands/repo_transfer.py b/seahub/base/management/commands/repo_transfer.py new file mode 100644 index 00000000000..e260f809cb1 --- /dev/null +++ b/seahub/base/management/commands/repo_transfer.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +import logging +from datetime import datetime + +from django.core.management.base import BaseCommand +from seaserv import seafile_api, ccnet_api + +from seahub.base.accounts import User +from seahub.share.models import UploadLinkShare, FileShare +from seahub.utils.db_api import SeafileDB + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = 'Transfer a repo to a new owner' + label = "repo_transfer" + + def add_arguments(self, parser): + parser.add_argument('-r', '--repo_id', help='Repo ID') + parser.add_argument('-o', '--new_owner', help='New owner of the repo') + + def handle(self, *args, **options): + repo_id = options.get('repo_id') + new_owner = options.get('new_owner') + if not repo_id: + self._pring_msg('repo_id is required', 'error') + return + if not new_owner: + self._pring_msg('new_owner is required', 'error') + return + + logger.debug('Start transfer_repos.') + self.stdout.write('[%s] Start transfer repos.' % datetime.now()) + self.transfer_repo(repo_id, new_owner) + self.stdout.write('[%s] Finish transfer repos.\n' % datetime.now()) + logger.debug('Finish transfer repos.\n') + + def _pring_msg(self, msg, msg_type='info'): + self.stdout.write('[%s][%s] %s' % (datetime.now(),msg_type.upper(), msg)) + + def _get_repo_owner(self, repo_id, org_id): + if org_id: + repo_owner = seafile_api.get_org_repo_owner(repo_id) + else: + repo_owner = seafile_api.get_repo_owner(repo_id) + + return repo_owner + + def is_dept(self, group): + return group.creator_name == 'system admin' + + + def transfer_repo(self, repo_id, new_owner, org_id=None): + + try: + int(new_owner) + new_owner = '%s@seafile_group' % new_owner + except: + pass + + # 1. check repo_owner + repo_owner = self._get_repo_owner(repo_id, org_id) + if repo_owner == new_owner: + error_msg = 'Cannot transfer repo to its owner' + self._pring_msg(error_msg, 'error') + return + + group_id = None + if '@seafile_group' in new_owner: + group_id = int(new_owner.split('@')[0]) + + # 2. transfer repo + seafile_db_api = SeafileDB() + if group_id: + group = ccnet_api.get_group(int(group_id)) + + if not group: + error_msg = 'Group %s not found' % group_id + self._pring_msg(error_msg, 'error') + return + + if not self.is_dept(group): + error_msg = 'Group %s is not a department' % group_id + self._pring_msg(error_msg, 'error') + return + + seafile_db_api.set_repo_group_owner(repo_id, group_id, org_id) + else: + try: + User.objects.get(email=new_owner) + except User.DoesNotExist: + error_msg = 'User %s not found.' % new_owner + self._pring_msg(error_msg, 'error') + return + + seafile_db_api.set_repo_owner(repo_id, new_owner, org_id) + + # 3. update the share relations + try: + seafile_db_api.update_repo_user_shares(repo_id, new_owner, org_id) + seafile_db_api.update_repo_group_shares(repo_id, new_owner, org_id) + seafile_db_api.delete_repo_user_token(repo_id, repo_owner) + + UploadLinkShare.objects.filter(repo_id=repo_id).update(username=new_owner) + FileShare.objects.filter(repo_id=repo_id).update(username=new_owner) + except Exception as error_msg: + self._pring_msg(error_msg, 'error') diff --git a/seahub/utils/db_api.py b/seahub/utils/db_api.py index d373b93a841..1bda52c12a6 100644 --- a/seahub/utils/db_api.py +++ b/seahub/utils/db_api.py @@ -357,3 +357,86 @@ def add_repos_to_org_user(self, org_id, username, repo_ids): """ with connection.cursor() as cursor: cursor.execute(sql) + + + def get_repo_ids_in_repo(self, repo_id): + repo_ids_sql = f""" + SELECT repo_id from `{self.db_name}`.`VirtualRepo` where origin_repo="{repo_id}" + """ + repo_ids = [repo_id, ] + with connection.cursor() as cursor: + cursor.execute(repo_ids_sql) + for item in cursor.fetchall(): + repo_id = item[0] + repo_ids.append(repo_id) + + return repo_ids + + def set_repo_owner(self, repo_id, new_owner, org_id=None): + # transfert repo to user + repo_ids = self.get_repo_ids_in_repo(repo_id) + repo_ids_str = ','.join(["'%s'" % str(rid) for rid in repo_ids]) + if org_id: + sql = f""" + UPDATE `{self.db_name}`.`OrgRepo` SET user="{new_owner}" WHERE org_id ={org_id} AND repo_id IN ({repo_ids_str}) + """ + else: + sql = f""" + UPDATE `{self.db_name}`.`RepoOwner` SET owner_id="{new_owner}" WHERE repo_id IN ({repo_ids_str}) + """ + with connection.cursor() as cursor: + cursor.execute(sql) + + def set_repo_group_owner(self, repo_id, group_id, org_id=None): + # transfer repo to department + group_username = "%s@seafile_group" % group_id + if org_id: + sql = f""" + INSERT INTO `{self.db_name}`.`OrgGroupRepo` (org_id, repo_id, group_id, owner, permission) VALUES ({org_id}, "{repo_id}", {group_id}, "{group_username}", "rw") + ON DUPLICATE KEY UPDATE owner="{group_username}" + """ + else: + sql = f""" + INSERT INTO `{self.db_name}`.`RepoGroup` (repo_id, group_id, user_name, permission) VALUES ("{repo_id}", {group_id}, "{group_username}", "rw") + ON DUPLICATE KEY UPDATE user_name="{group_username}" + """ + with connection.cursor() as cursor: + cursor.execute(sql) + + self.set_repo_owner(repo_id, group_username, org_id) + + def update_repo_user_shares(self, repo_id, new_owner, org_id=None): + repo_ids = self.get_repo_ids_in_repo(repo_id) + repo_ids_str = ','.join(["'%s'" % str(rid) for rid in repo_ids]) + if org_id: + sql = f""" + UPDATE `{self.db_name}`.`OrgSharedRepo` SET from_email="{new_owner}" WHERE org_id={org_id} AND repo_id IN ({repo_ids_str}) + """ + else: + sql = f""" + UPDATE `{self.db_name}`.`SharedRepo` SET from_email="{new_owner}" WHERE repo_id IN ({repo_ids_str}) + """ + with connection.cursor() as cursor: + cursor.execute(sql) + + def update_repo_group_shares(self, repo_id, new_owner, org_id=None): + repo_ids = self.get_repo_ids_in_repo(repo_id) + repo_ids_str = ','.join(["'%s'" % str(rid) for rid in repo_ids]) + if org_id: + sql = f""" + UPDATE `{self.db_name}`.`OrgGroupRepo` SET owner="{new_owner}" WHERE org_id={org_id} AND repo_id IN ({repo_ids_str}) + """ + else: + sql = f""" + UPDATE `{self.db_name}`.`RepoGroup` SET user_name="{new_owner}" WHERE repo_id IN ({repo_ids_str}) + """ + with connection.cursor() as cursor: + cursor.execute(sql) + + def delete_repo_user_token(self, repo_id, owner): + sql = f""" + DELETE FROM `{self.db_name}`.`RepoUserToken` where repo_id="{repo_id}" AND email="{owner}" + """ + with connection.cursor() as cursor: + cursor.execute(sql) +