~homeworkprod/byceps

354d9344e2c53dbc4fba84b117ed4c486b7e37b9 — Jochen Kupperschmidt 11 months ago 251c6e2
Extract user account deletion service
M byceps/blueprints/admin/user/views.py => byceps/blueprints/admin/user/views.py +5 -2
@@ 18,7 18,10 @@ from ....services.orga_team import service as orga_team_service
from ....services.shop.order import service as order_service
from ....services.shop.shop import service as shop_service
from ....services.site import service as site_service
from ....services.user import command_service as user_command_service
from ....services.user import (
    command_service as user_command_service,
    deletion_service as user_deletion_service,
)
from ....services.user import creation_service as user_creation_service
from ....services.user import service as user_service
from ....services.user import stats_service as user_stats_service


@@ 415,7 418,7 @@ def delete_account(user_id):
    initiator_id = g.current_user.id
    reason = form.reason.data.strip()

    event = user_command_service.delete_account(user.id, initiator_id, reason)
    event = user_deletion_service.delete_account(user.id, initiator_id, reason)

    user_signals.account_deleted.send(None, event=event)


M byceps/services/user/command_service.py => byceps/services/user/command_service.py +0 -60
@@ 11,7 11,6 @@ from typing import Any, Optional

from ...database import db
from ...events.user import (
    UserAccountDeleted,
    UserAccountSuspended,
    UserAccountUnsuspended,
    UserDetailsUpdated,


@@ 134,44 133,6 @@ def unsuspend_account(
    )


def delete_account(
    user_id: UserID, initiator_id: UserID, reason: str
) -> UserAccountDeleted:
    """Delete the user account."""
    user = _get_user(user_id)
    initiator = user_service.get_user(initiator_id)

    user_screen_name_before_anonymization = user.screen_name

    user.deleted = True
    _anonymize_account(user)

    event = event_service.build_event(
        'user-deleted',
        user.id,
        {
            'initiator_id': str(initiator.id),
            'reason': reason,
        },
    )
    db.session.add(event)

    # Deassign authorization roles.
    authorization_service.deassign_all_roles_from_user(
        user.id, initiator.id, commit=False
    )

    db.session.commit()

    return UserAccountDeleted(
        occurred_at=event.occurred_at,
        initiator_id=initiator.id,
        initiator_screen_name=initiator.screen_name,
        user_id=user.id,
        user_screen_name=user_screen_name_before_anonymization,
    )


def change_screen_name(
    user_id: UserID,
    new_screen_name: str,


@@ 353,27 314,6 @@ def remove_user_detail_extra(user_id: UserID, key: str) -> None:
    db.session.commit()


def _anonymize_account(user: DbUser) -> None:
    """Remove user details from the account."""
    user.screen_name = None
    user.email_address = None
    user.legacy_id = None

    # Remove details.
    user.detail.first_names = None
    user.detail.last_name = None
    user.detail.date_of_birth = None
    user.detail.country = None
    user.detail.zip_code = None
    user.detail.city = None
    user.detail.street = None
    user.detail.phone_number = None

    # Remove avatar association.
    if user.avatar_selection is not None:
        db.session.delete(user.avatar_selection)


def _get_user(user_id: UserID) -> DbUser:
    """Return the user with that ID, or raise an exception."""
    return user_service.get_db_user(user_id)

A byceps/services/user/deletion_service.py => byceps/services/user/deletion_service.py +78 -0
@@ 0,0 1,78 @@
"""
byceps.services.user.deletion_service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

User account anonymization and removal

:Copyright: 2006-2020 Jochen Kupperschmidt
:License: Revised BSD (see `LICENSE` file for details)
"""

from ...database import db
from ...events.user import UserAccountDeleted
from ...typing import UserID

from ..authorization import service as authorization_service

from . import event_service
from .models.user import User as DbUser
from . import service as user_service


def delete_account(
    user_id: UserID, initiator_id: UserID, reason: str
) -> UserAccountDeleted:
    """Delete the user account."""
    user = user_service.get_db_user(user_id)
    initiator = user_service.get_user(initiator_id)

    user_screen_name_before_anonymization = user.screen_name

    user.deleted = True
    _anonymize_account(user)

    event = event_service.build_event(
        'user-deleted',
        user.id,
        {
            'initiator_id': str(initiator.id),
            'reason': reason,
        },
    )
    db.session.add(event)

    # Deassign authorization roles.
    authorization_service.deassign_all_roles_from_user(
        user.id, initiator.id, commit=False
    )

    db.session.commit()

    return UserAccountDeleted(
        occurred_at=event.occurred_at,
        initiator_id=initiator.id,
        initiator_screen_name=initiator.screen_name,
        user_id=user.id,
        user_screen_name=user_screen_name_before_anonymization,
    )


def _anonymize_account(user: DbUser) -> None:
    """Remove user details from the account."""
    user.screen_name = None
    user.email_address = None
    user.legacy_id = None

    # Remove details.
    user.detail.first_names = None
    user.detail.last_name = None
    user.detail.date_of_birth = None
    user.detail.country = None
    user.detail.zip_code = None
    user.detail.city = None
    user.detail.street = None
    user.detail.phone_number = None

    # Remove avatar association.
    if user.avatar_selection is not None:
        db.session.delete(user.avatar_selection)

M tests/conftest.py => tests/conftest.py +3 -2
@@ 18,6 18,7 @@ from byceps.services.party import service as party_service
from byceps.services.site import service as site_service
from byceps.services.user import (
    command_service as user_command_service,
    deletion_service as user_deletion_service,
    service as user_service,
)
from byceps.typing import BrandID


@@ 111,7 112,7 @@ def make_user(admin_app):
    yield _wrapper

    for user_id in user_ids:
        user_command_service.delete_account(user_id, user_id, 'clean up')
        user_deletion_service.delete_account(user_id, user_id, 'clean up')


@pytest.fixture(scope='session')


@@ 127,7 128,7 @@ def make_user_with_detail(admin_app):
    yield _wrapper

    for user_id in user_ids:
        user_command_service.delete_account(user_id, user_id, 'clean up')
        user_deletion_service.delete_account(user_id, user_id, 'clean up')


@pytest.fixture(scope='session')

M tests/integration/announce/irc/test_user.py => tests/integration/announce/irc/test_user.py +2 -2
@@ 12,7 12,7 @@ from byceps.events.user import (
    UserEmailAddressInvalidated,
    UserScreenNameChanged,
)
from byceps.services.user import command_service as user_command_service
from byceps.services.user import deletion_service as user_deletion_service
from byceps.signals import user as user_signals

from .helpers import (


@@ 183,7 183,7 @@ def test_deleted_account_announced(app, make_user):
    admin = make_user('UberDude')
    user = make_user('Snake', user_id='76b0c57f-8909-4b02-90c9-96e0a817f738')

    event = user_command_service.delete_account(
    event = user_deletion_service.delete_account(
        user.id, admin.id, 'specious reason'
    )


M tests/integration/services/user/test_delete_account.py => tests/integration/services/user/test_delete_account.py +5 -2
@@ 7,7 7,10 @@ import pytest

from byceps.database import db
from byceps.services.authorization import service as authorization_service
from byceps.services.user import command_service as user_command_service
from byceps.services.user import (
    command_service as user_command_service,
    deletion_service as user_deletion_service,
)
from byceps.services.user import event_service




@@ 81,7 84,7 @@ def test_delete_account(

    # -------------------------------- #

    user_command_service.delete_account(user_id, admin_user.id, reason=reason)
    user_deletion_service.delete_account(user_id, admin_user.id, reason=reason)

    # -------------------------------- #