def test_delete_namespace_via_marker(initialized_db): def create_transaction(db): return db.transaction() # Create a user and then mark it for deletion. user = create_user_noverify("foobar", "*****@*****.**", email_required=False) # Add some repositories. create_repository("foobar", "somerepo", user) create_repository("foobar", "anotherrepo", user) # Mark the user for deletion. queue = WorkQueue("testgcnamespace", create_transaction) marker_id = mark_namespace_for_deletion(user, [], queue) # Delete the user. with check_transitive_modifications(): delete_namespace_via_marker(marker_id, []) # Ensure the user was actually deleted. with pytest.raises(User.DoesNotExist): User.get(id=user.id) with pytest.raises(DeletedNamespace.DoesNotExist): DeletedNamespace.get(id=marker_id)
def get_organizations(deleted=False): query = User.select().where(User.organization == True, User.robot == False) if not deleted: query = query.where(User.id.not_in(DeletedNamespace.select(DeletedNamespace.namespace))) return query
def mark_namespace_for_deletion(user, queues, namespace_gc_queue, force=False): """ Marks a namespace (as referenced by the given user) for deletion. A queue item will be added to delete the namespace's repositories and storage, while the namespace itself will be renamed, disabled, and delinked from other tables. """ if not user.enabled: return None 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 non-repository related items. This operation is very quick, so we can do so here. _delete_user_linked_data(user) with db_transaction(): original_username = user.username user = db_for_update(User.select().where(User.id == user.id)).get() # Mark the namespace as deleted and ready for GC. try: marker = DeletedNamespace.create( namespace=user, original_username=original_username, original_email=user.email) except IntegrityError: return # Disable the namespace itself, and replace its various unique fields with UUIDs. user.enabled = False user.username = str(uuid4()) user.email = str(uuid4()) user.save() # Add a queueitem to delete the namespace. marker.queue_id = namespace_gc_queue.put( [str(user.id)], json.dumps({ "marker_id": marker.id, "original_username": original_username, }), ) marker.save() return marker.id
def delete_namespace_via_marker(marker_id, queues): """ Deletes a namespace referenced by the given DeletedNamespace marker ID. """ try: marker = DeletedNamespace.get(id=marker_id) except DeletedNamespace.DoesNotExist: return delete_user(marker.namespace, queues)
def get_active_users(disabled=True, deleted=False): query = User.select().where(User.organization == False, User.robot == False) if not disabled: query = query.where(User.enabled == True) if not deleted: query = query.where(User.id.not_in(DeletedNamespace.select(DeletedNamespace.namespace))) return query
def get_organizations(disabled=True, deleted=False): query = User.select().where(User.organization == True, User.robot == False) if not disabled: query = query.where(User.enabled == True) else: # NOTE: Deleted users are already disabled, so we don't need this extra check. if not deleted: query = query.where(User.id.not_in(DeletedNamespace.select(DeletedNamespace.namespace))) return query