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

♻️ webserver: fixes mypy issues in users plugin #4230

Merged
merged 27 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from 25 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
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
from .studies_dispatcher.plugin import setup_studies_dispatcher
from .tags.plugin import setup_tags
from .tracing import setup_app_tracing
from .users import setup_users
from .users.plugin import setup_users
from .version_control.plugin import setup_version_control

_logger = logging.getLogger(__name__)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from ...projects.projects_api import get_project_for_user, submit_delete_project_task
from ...projects.projects_db import APP_PROJECT_DBAPI, ProjectDBAPI
from ...projects.projects_exceptions import ProjectsException
from ...users_api import get_user
from ...users.api import get_user
from ...utils import now_str
from ..exceptions import ExporterException
from ..file_downloader import ParallelDownloader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from ..projects.project_lock import lock_project
from ..projects.projects_api import retrieve_and_notify_project_locked_state
from ..security.decorators import permission_required
from ..users_api import get_user_name
from ..users.api import get_user_name
from .exceptions import ExporterException
from .export_import import study_duplicate, study_export, study_import
from .formatters import FormatterV1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from simcore_postgres_database.errors import DatabaseError
from simcore_postgres_database.models.users import UserRole

from . import users_exceptions
from .director.director_exceptions import DirectorException, ServiceNotFoundError
from .director_v2 import api
from .director_v2.exceptions import ServiceWaitingForManualIntervention
Expand All @@ -38,13 +37,14 @@
)
from .redis import get_redis_lock_manager_client
from .resource_manager.registry import RedisResourceRegistry, get_registry
from .users_api import (
delete_user,
from .users import exceptions
from .users.api import (
delete_user_without_projects,
get_guest_user_ids_and_names,
get_user,
get_user_role,
)
from .users_exceptions import UserNotFoundError
from .users.exceptions import UserNotFoundError

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -471,7 +471,7 @@ async def _delete_all_projects_for_user(app: web.Application, user_id: int) -> N
# recover user's primary_gid
try:
project_owner: dict = await get_user(app=app, user_id=user_id)
except users_exceptions.UserNotFoundError:
except exceptions.UserNotFoundError:
logger.warning(
"Could not recover user data for user '%s', stopping removal of projects!",
f"{user_id=}",
Expand Down Expand Up @@ -587,7 +587,7 @@ async def remove_guest_user_with_all_its_resources(
"Deleting user %s because it is a GUEST",
f"{user_id=}",
)
await delete_user(app, user_id)
await delete_user_without_projects(app, user_id)

except (
DatabaseError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from ._constants import APP_DB_ENGINE_KEY
from .login.utils import notify_user_logout
from .security.api import clean_auth_policy_cache
from .users_db import update_expired_users
from .users.api import update_expired_users

logger = logging.getLogger(__name__)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
from models_library.users import GroupID, UserID
from simcore_postgres_database.errors import DatabaseError

from . import users_exceptions
from .db_models import GroupType
from .groups.api import get_group_from_gid
from .projects.projects_db import APP_PROJECT_DBAPI, ProjectAccessRights
from .projects.projects_exceptions import ProjectNotFoundError
from .users_api import get_user, get_user_id_from_gid
from .users_exceptions import UserNotFoundError
from .users_to_groups_api import get_users_for_gid
from .users import exceptions
from .users.api import get_user, get_user_id_from_gid, get_users_in_group
from .users.exceptions import UserNotFoundError

logger = logging.getLogger(__name__)

Expand All @@ -29,15 +28,17 @@ async def _fetch_new_project_owner_from_groups(
# go through user_to_groups table and fetch all uid for matching gid
for group_gid in standard_groups.keys():
# remove the current owner from the bunch
target_group_users = await get_users_for_gid(app=app, gid=group_gid) - {user_id}
target_group_users = await get_users_in_group(app=app, gid=group_gid) - {
user_id
}
logger.info("Found group users '%s'", target_group_users)

for possible_user_id in target_group_users:
# check if the possible_user is still present in the db
try:
possible_user = await get_user(app=app, user_id=possible_user_id)
return int(possible_user["primary_gid"])
except users_exceptions.UserNotFoundError:
except exceptions.UserNotFoundError:
logger.warning(
"Could not find new owner '%s' will try a new one",
possible_user_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
from sqlalchemy.dialects.postgresql import insert

from ..db_models import GroupType, groups, user_to_groups, users
from ..users_exceptions import UserNotFoundError
from ..users.exceptions import UserNotFoundError
from ._users import convert_user_in_group_to_schema
from ._utils import (
AccessRightsDict,
check_group_permissions,
convert_groups_db_to_schema,
convert_groups_schema_to_db,
convert_user_in_group_to_schema,
)
from .exceptions import GroupNotFoundError, UserInGroupNotFoundError

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from ..scicrunch.models import ResearchResource, ResourceHit
from ..scicrunch.service_client import SciCrunch
from ..security.decorators import permission_required
from ..users_exceptions import UserNotFoundError
from ..users.exceptions import UserNotFoundError
from . import api
from ._classifiers import GroupClassifierRepository, build_rrids_tree_view
from .exceptions import (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
NOTE: Coupling with user's plugin api modules should be added here to avoid cyclic dependencies
"""

from typing import Any, Mapping

from ..users.schemas import convert_user_db_to_schema


def convert_user_in_group_to_schema(user: Mapping[str, Any]) -> dict[str, str]:
group_user = convert_user_db_to_schema(user)
group_user.pop("role")
group_user["accessRights"] = user["access_rights"]
group_user["gid"] = user["primary_gid"]
return group_user
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from typing import Any, Mapping, TypedDict
from typing import TypedDict

from aiopg.sa.result import RowProxy

from ..users_utils import convert_user_db_to_schema
from .exceptions import UserInsufficientRightsError

_GROUPS_SCHEMA_TO_DB = {
Expand Down Expand Up @@ -48,11 +47,3 @@ def convert_groups_schema_to_db(schema: dict) -> dict:
for k, v in _GROUPS_SCHEMA_TO_DB.items()
if k in schema and k != "gid"
}


def convert_user_in_group_to_schema(user: Mapping[str, Any]) -> dict[str, str]:
group_user = convert_user_db_to_schema(user)
group_user.pop("role")
group_user["accessRights"] = user["access_rights"]
group_user["gid"] = user["primary_gid"]
return group_user
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from models_library.users import GroupID, UserID

from ..db import get_database_engine
from ..users_api import get_user
from ..users.api import get_user
from . import _db
from ._utils import AccessRightsDict
from .exceptions import GroupsException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
__name__,
ModuleCategory.ADDON,
settings_name="WEBSERVER_GROUPS",
depends=["simcore_service_webserver.rest", "simcore_service_webserver.users"],
depends=["simcore_service_webserver.rest"],
logger=_logger,
)
def setup_groups(app: web.Application):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
copy_data_folders_from_project,
get_project_total_size_simcore_s3,
)
from ..users_api import get_user_name
from ..users.api import get_user_name
from . import projects_api
from ._permalink import update_or_pop_permalink_in_project
from ._rest_schemas import ProjectGet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

from ..director_v2 import api
from ..storage.api import delete_data_folders_of_project
from ..users_api import UserNameDict
from ..users_exceptions import UserNotFoundError
from ..users.api import UserNameDict
from ..users.exceptions import UserNotFoundError
from .projects_db import ProjectDBAPI
from .projects_exceptions import (
ProjectDeleteError,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime
from asyncio.log import logger
from contextlib import asynccontextmanager
from typing import Final, Optional, Union
from typing import Final

import redis
from aiohttp import web
Expand All @@ -11,7 +11,7 @@
from servicelib.background_task import periodic_task

from ..redis import get_redis_lock_manager_client
from ..users_api import UserNameDict
from ..users.api import UserNameDict
from .projects_exceptions import ProjectLockError

PROJECT_REDIS_LOCK_KEY: str = "project_lock:{}"
Expand All @@ -27,7 +27,7 @@ async def _auto_extend_project_lock(project_lock: Lock) -> None:
@asynccontextmanager
async def lock_project(
app: web.Application,
project_uuid: Union[str, ProjectID],
project_uuid: str | ProjectID,
status: ProjectStatus,
user_id: int,
user_name: UserNameDict,
Expand Down Expand Up @@ -81,7 +81,7 @@ async def lock_project(


async def is_project_locked(
app: web.Application, project_uuid: Union[str, ProjectID]
app: web.Application, project_uuid: str | ProjectID
) -> bool:
redis_lock = get_redis_lock_manager_client(app).lock(
PROJECT_REDIS_LOCK_KEY.format(project_uuid)
Expand All @@ -90,8 +90,8 @@ async def is_project_locked(


async def get_project_locked_state(
app: web.Application, project_uuid: Union[str, ProjectID]
) -> Optional[ProjectLocked]:
app: web.Application, project_uuid: str | ProjectID
) -> ProjectLocked | None:
"""returns the ProjectLocked object if the project is locked"""
if await is_project_locked(app, project_uuid):
redis_locks_client = get_redis_lock_manager_client(app)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from servicelib.json_serialization import json_dumps
from servicelib.logging_utils import get_log_record_extra, log_context
from servicelib.utils import fire_and_forget_task, logged_gather
from simcore_postgres_database.models.users import UserRole
from simcore_postgres_database.webserver_models import ProjectType

from .. import catalog_client
Expand All @@ -63,8 +64,8 @@
send_messages,
)
from ..storage import api as storage_api
from ..users_api import UserRole, get_user_name, get_user_role
from ..users_exceptions import UserNotFoundError
from ..users.api import get_user_name, get_user_role
from ..users.exceptions import UserNotFoundError
from . import _delete_utils, _nodes_utils
from .project_lock import (
UserNameDict,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from sqlalchemy.sql import select

from ..db_models import GroupType, groups, study_tags, user_to_groups, users
from ..users_exceptions import UserNotFoundError
from ..users.exceptions import UserNotFoundError
from ..utils import format_datetime
from .project_models import ProjectDict, ProjectProxy
from .projects_exceptions import ProjectInvalidRightsError, ProjectNotFoundError
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
from simcore_postgres_database.models.users import UserRole
from simcore_postgres_database.webserver_models import ProjectType

from .. import users_api
from .._meta import api_version_prefix as VTAG
from ..director_v2.exceptions import DirectorServiceError
from ..login.decorators import login_required
from ..notifications import project_logs
from ..products.plugin import Product, get_current_product
from ..security.decorators import permission_required
from ..users import api
from . import projects_api
from .projects_exceptions import (
ProjectInvalidRightsError,
Expand Down Expand Up @@ -69,9 +69,7 @@ async def open_project(request: web.Request) -> web.Response:
project_type: ProjectType = await projects_api.get_project_type(
request.app, path_params.project_id
)
user_role: UserRole = await users_api.get_user_role(
request.app, req_ctx.user_id
)
user_role: UserRole = await api.get_user_role(request.app, req_ctx.user_id)
if project_type is ProjectType.TEMPLATE and user_role < UserRole.USER:
# only USERS/TESTERS can do that
raise web.HTTPForbidden(reason="Wrong user role to open/edit a template")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from ..resource_manager.websocket_manager import PROJECT_ID_KEY, managed_resource
from ..security.api import check_permission
from ..security.decorators import permission_required
from ..users_api import get_user_name
from ..users.api import get_user_name
from . import _create_utils, _read_utils, projects_api
from ._permalink import update_or_pop_permalink_in_project
from ._rest_schemas import (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from ..login.decorators import login_required
from ..projects.projects_db import ProjectDBAPI
from ..security.decorators import permission_required
from ..users_api import get_user_role
from ..users.api import get_user_role
from . import projects_api
from .projects_exceptions import (
NodeNotFoundError,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
from ..login.utils import ACTIVE, GUEST, get_client_ip, get_random_string
from ..redis import get_redis_lock_manager_client
from ..security.api import authorized_userid, encrypt_password, is_anonymous, remember
from ..users_api import get_user
from ..users_exceptions import UserNotFoundError
from ..users.api import get_user
from ..users.exceptions import UserNotFoundError
from ._constants import MSG_GUESTS_NOT_ALLOWED
from .settings import StudiesDispatcherSettings, get_plugin_settings

Expand Down
Empty file.
36 changes: 36 additions & 0 deletions services/web/server/src/simcore_service_webserver/users/_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import sqlalchemy as sa
from aiopg.sa.connection import SAConnection
from aiopg.sa.result import ResultProxy
from models_library.users import GroupID, UserID
from simcore_postgres_database.models.users import UserStatus, users
from sqlalchemy.sql import func

from ..db_models import user_to_groups


async def do_update_expired_users(conn: SAConnection) -> list[UserID]:

result: ResultProxy = await conn.execute(
users.update()
.values(status=UserStatus.EXPIRED)
.where(
(users.c.expires_at != None)
& (users.c.status == UserStatus.ACTIVE)
& (users.c.expires_at < func.now())
)
.returning(users.c.id)
)
if rows := await result.fetchall():
expired = [r.id for r in rows]
return expired
return []


async def get_users_ids_in_group(conn: SAConnection, gid: GroupID) -> set[UserID]:
result: set[UserID] = set()
query_result = await conn.execute(
sa.select(user_to_groups.c.uid).where(user_to_groups.c.gid == gid)
)
async for entry in query_result:
result.add(entry[0])
return result
Loading