Merge pull request #1698 from coreos-inc/delete-namespace
Add support for deleting namespaces (users, organizations)
This commit is contained in:
commit
edc2bc8b93
23 changed files with 407 additions and 33 deletions
|
@ -9,7 +9,8 @@ from datetime import datetime, timedelta
|
|||
from data.database import (User, LoginService, FederatedLogin, RepositoryPermission, TeamMember,
|
||||
Team, Repository, TupleSelector, TeamRole, Namespace, Visibility,
|
||||
EmailConfirmation, Role, db_for_update, random_string_generator,
|
||||
UserRegion, ImageStorageLocation)
|
||||
UserRegion, ImageStorageLocation, QueueItem, TeamMemberInvite,
|
||||
ServiceKeyApproval, OAuthApplication, RepositoryBuildTrigger)
|
||||
from data.model import (DataModelException, InvalidPasswordException, InvalidRobotException,
|
||||
InvalidUsernameException, InvalidEmailAddressException,
|
||||
TooManyLoginAttemptsException, db_transaction,
|
||||
|
@ -647,11 +648,81 @@ def detach_external_login(user, service_name):
|
|||
FederatedLogin.service == service).execute()
|
||||
|
||||
|
||||
def delete_user(user):
|
||||
def get_solely_admined_organizations(user_obj):
|
||||
""" Returns the organizations admined solely by the given user. """
|
||||
orgs = (User.select()
|
||||
.where(User.organization == True)
|
||||
.join(Team)
|
||||
.join(TeamRole)
|
||||
.where(TeamRole.name == 'admin')
|
||||
.switch(Team)
|
||||
.join(TeamMember)
|
||||
.where(TeamMember.user == user_obj)
|
||||
.distinct())
|
||||
|
||||
# Filter to organizations where the user is the sole admin.
|
||||
solely_admined = []
|
||||
for org in orgs:
|
||||
admin_user_count = (TeamMember.select()
|
||||
.join(Team)
|
||||
.join(TeamRole)
|
||||
.where(Team.organization == org, TeamRole.name == 'admin')
|
||||
.switch(TeamMember)
|
||||
.join(User)
|
||||
.where(User.robot == False)
|
||||
.distinct()
|
||||
.count())
|
||||
|
||||
if admin_user_count == 1:
|
||||
solely_admined.append(org)
|
||||
|
||||
return solely_admined
|
||||
|
||||
|
||||
def delete_user(user, queues, force=False):
|
||||
if not force and not user.organization:
|
||||
# Ensure that the user is not the sole admin for any organizations. If so, then the user
|
||||
# cannot be deleted before those organizations are deleted or reassigned.
|
||||
organizations = get_solely_admined_organizations(user)
|
||||
if len(organizations) > 0:
|
||||
message = 'Cannot delete %s as you are the only admin for organizations: ' % user.username
|
||||
for index, org in enumerate(organizations):
|
||||
if index > 0:
|
||||
message = message + ', '
|
||||
|
||||
message = message + org.username
|
||||
|
||||
raise DataModelException(message)
|
||||
|
||||
# Delete all queue items for the user.
|
||||
for queue in queues:
|
||||
queue.delete_namespaced_items(user.username)
|
||||
|
||||
# Delete any repositories under the user's namespace.
|
||||
for repo in list(Repository.select().where(Repository.namespace_user == user)):
|
||||
repository.purge_repository(user.username, repo.name)
|
||||
|
||||
if user.organization:
|
||||
# Delete the organization's teams.
|
||||
for team in Team.select().where(Team.organization == user):
|
||||
team.delete_instance(recursive=True)
|
||||
|
||||
# Delete any OAuth approvals and tokens associated with the user.
|
||||
for app in OAuthApplication.select().where(OAuthApplication.organization == user):
|
||||
app.delete_instance(recursive=True)
|
||||
else:
|
||||
# Remove the user from any teams in which they are a member.
|
||||
TeamMember.delete().where(TeamMember.user == user).execute()
|
||||
|
||||
# Delete any repository buildtriggers where the user is the connected user.
|
||||
triggers = RepositoryBuildTrigger.select().where(RepositoryBuildTrigger.connected_user == user)
|
||||
for trigger in triggers:
|
||||
trigger.delete_instance(recursive=True, delete_nullable=False)
|
||||
|
||||
# Null out any service key approvals. We technically lose information here, but its better than
|
||||
# falling and only occurs if a superuser is being deleted.
|
||||
ServiceKeyApproval.update(approver=None).where(ServiceKeyApproval.approver == user).execute()
|
||||
|
||||
# Delete the user itself.
|
||||
user.delete_instance(recursive=True, delete_nullable=True)
|
||||
|
||||
|
|
Reference in a new issue