Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Create cli command to transfer applet ownership (M2-7719) #1575

Merged
merged 1 commit into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/apps/applets/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from apps.applets.commands.applet import app as applet_cli # noqa: F401
from apps.applets.commands.applet_ema import app as applet_ema_cli # noqa: F401
80 changes: 80 additions & 0 deletions src/apps/applets/commands/applet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import uuid

import typer
from rich import print

from apps.applets.service import AppletService
from apps.transfer_ownership.service import TransferService
from apps.users import User
from apps.users.cruds.user import UsersCRUD
from apps.users.errors import UserIsDeletedError, UserNotFound
from apps.workspaces.service.check_access import CheckAccessService
from infrastructure.commands.utils import coro
from infrastructure.database import atomic, session_manager

app = typer.Typer()


def error_msg(msg: str):
print(f"[bold red]Error: {msg}[/bold red]")


def error(msg: str):
error_msg(msg)
raise typer.Abort()


async def _validate_access(session, user: User, applet_ids: list[uuid.UUID]):
for applet_id in applet_ids:
try:
await AppletService(session, user.id).exist_by_id(applet_id)
await CheckAccessService(session, user.id).check_create_transfer_ownership_access(applet_id)
except Exception as e:
error_msg(f"Applet access error: {applet_id}")
error(str(e))


@app.command(help="Transfer ownership")
@coro
async def transfer_ownership(
applet_ids: list[uuid.UUID] = typer.Argument(..., help="A list of Applet IDs for data copying."),
source_owner_email: str = typer.Option(
...,
"--src-owner-email",
"-s",
help="Source owner email.",
),
target_owner_email: str = typer.Option(
...,
"--tgt-owner-email",
"-t",
help="Target owner email.",
),
) -> None:
source_owner_email = source_owner_email.lower()
target_owner_email = target_owner_email.lower()
if source_owner_email == target_owner_email:
error("Emails are the same.")

session_maker = session_manager.get_session()
async with session_maker() as session:
user_repo = UsersCRUD(session)
try:
source_user = await user_repo.get_by_email(source_owner_email)
except (UserNotFound, UserIsDeletedError):
error(f"User with email {source_owner_email} not found")
await _validate_access(session, source_user, applet_ids)

try:
target_user = await user_repo.get_by_email(target_owner_email)
except (UserNotFound, UserIsDeletedError):
error(f"User with email {target_owner_email} not found")

service_from = TransferService(session, source_user)
service_to = TransferService(session, target_user)
async with atomic(session):
for applet_id in applet_ids:
print(f"Transfer ownership for applet {applet_id}")
transfer = await service_from.save_transfer_request(applet_id, target_owner_email, target_user.id)
await service_to.accept_transfer(applet_id, transfer.key)
print(f"[green]Transfer ownership for applet {applet_id} finished[/green]")
22 changes: 13 additions & 9 deletions src/apps/transfer_ownership/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ def __init__(self, session, user: User):
self._user = user
self.session = session

async def save_transfer_request(self, applet_id: uuid.UUID, target_email: str, target_id: uuid.UUID) -> Transfer:
transfer = Transfer(
email=target_email,
applet_id=applet_id,
key=uuid.uuid4(),
status=TransferOwnershipStatus.PENDING,
from_user_id=self._user.id,
to_user_id=target_id,
)
await TransferCRUD(self.session).create(transfer)
return transfer

async def initiate_transfer(self, applet_id: uuid.UUID, transfer_request: InitiateTransfer):
"""Initiate a transfer of ownership of an applet."""
# check if user is owner of applet
Expand All @@ -44,15 +56,7 @@ async def initiate_transfer(self, applet_id: uuid.UUID, transfer_request: Initia
receiver_name = transfer_request.email
to_user_id = None

transfer = Transfer(
email=transfer_request.email,
applet_id=applet_id,
key=uuid.uuid4(),
status=TransferOwnershipStatus.PENDING,
from_user_id=self._user.id,
to_user_id=to_user_id,
)
await TransferCRUD(self.session).create(transfer)
transfer = await self.save_transfer_request(applet_id, transfer_request.email, to_user_id)

url = self._generate_transfer_url()

Expand Down
2 changes: 2 additions & 0 deletions src/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from apps.activities.commands import activities # noqa: E402
from apps.answers.commands import convert_assessments # noqa: E402
from apps.applets.commands import applet_cli # noqa: E402
from apps.applets.commands import applet_ema_cli # noqa: E402
from apps.shared.commands import encryption_cli, patch # noqa: E402
from apps.users.commands import token_cli # noqa: E402
Expand All @@ -22,6 +23,7 @@
cli.add_typer(patch, name="patch")
cli.add_typer(encryption_cli, name="encryption")
cli.add_typer(applet_ema_cli, name="applet-ema")
cli.add_typer(applet_cli, name="applet")

if __name__ == "__main__":
# with app context?
Expand Down
Loading