-
Notifications
You must be signed in to change notification settings - Fork 32
🎨 Allows guest users to run a project form a template with outputs pushing enabled #8555
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
base: master
Are you sure you want to change the base?
Changes from 8 commits
f75b69a
1b9ebdd
b5cc9e8
f5d29fe
2184e6a
7eb489a
36115e1
952afa4
e49f75f
b2fdef8
5f93549
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| """add_projects_optionals | ||
|
|
||
| Revision ID: a85557c02d71 | ||
| Revises: 5756d9282a0a | ||
| Create Date: 2025-10-24 15:03:32.846288+00:00 | ||
|
|
||
| """ | ||
|
|
||
| import sqlalchemy as sa | ||
| from alembic import op | ||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision = "a85557c02d71" | ||
| down_revision = "5756d9282a0a" | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade(): | ||
| # ### commands auto generated by Alembic - please adjust! ### | ||
| op.create_table( | ||
| "projects_optionals", | ||
| sa.Column("project_uuid", sa.String(), nullable=False), | ||
| sa.Column( | ||
| "allow_guests_to_push_states_and_output_ports", | ||
| sa.Boolean(), | ||
| server_default=sa.text("false"), | ||
| nullable=False, | ||
| ), | ||
| sa.ForeignKeyConstraint( | ||
| ["project_uuid"], | ||
| ["projects.uuid"], | ||
| name="fk_projects_optionals_project_uuid_projects", | ||
| onupdate="CASCADE", | ||
| ondelete="CASCADE", | ||
| ), | ||
| sa.PrimaryKeyConstraint("project_uuid"), | ||
| ) | ||
| # ### end Alembic commands ### | ||
|
|
||
|
|
||
| def downgrade(): | ||
| # ### commands auto generated by Alembic - please adjust! ### | ||
| op.drop_table("projects_optionals") | ||
| # ### end Alembic commands ### |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import sqlalchemy as sa | ||
|
|
||
| from ._common import RefActions | ||
| from .base import metadata | ||
| from .projects import projects | ||
|
|
||
| projects_optionals = sa.Table( | ||
| "projects_optionals", | ||
| metadata, | ||
| sa.Column( | ||
| "project_uuid", | ||
| sa.String, | ||
| sa.ForeignKey( | ||
| projects.c.uuid, | ||
| name="fk_projects_optionals_project_uuid_projects", | ||
| ondelete=RefActions.CASCADE, | ||
| onupdate=RefActions.CASCADE, | ||
| ), | ||
| primary_key=True, | ||
| doc="project reference and primary key for this table", | ||
| ), | ||
| sa.Column( | ||
| "allow_guests_to_push_states_and_output_ports", | ||
| sa.Boolean(), | ||
| nullable=False, | ||
| server_default=sa.sql.expression.false(), | ||
| doc=( | ||
| "When True, guest will save the state of a service " | ||
| "and also push the data to the output ports" | ||
| ), | ||
| ), | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import sqlalchemy as sa | ||
| from simcore_postgres_database.utils_repos import ( | ||
| pass_or_acquire_connection, | ||
| transaction_context, | ||
| ) | ||
| from sqlalchemy.ext.asyncio import AsyncEngine | ||
|
|
||
| from .models.projects_optionals import projects_optionals | ||
|
|
||
|
|
||
| class CouldNotCreateOrUpdateUserPreferenceError(Exception): ... | ||
|
|
||
|
|
||
| class BaseProjectOptionalsRepo: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Base? |
||
| model: sa.Table = projects_optionals | ||
|
|
||
| @classmethod | ||
| async def allows_guests_to_push_states_and_output_ports( | ||
| cls, async_engine: AsyncEngine, *, project_uuid: str | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so this is like a separate call to a separate database everytime one asks for the projects? can this not be made together with a join in one call? |
||
| ) -> bool: | ||
| async with pass_or_acquire_connection(async_engine) as connection: | ||
| result: bool | None = await connection.scalar( | ||
| sa.select( | ||
| cls.model.c.allow_guests_to_push_states_and_output_ports | ||
| ).where(cls.model.c.project_uuid == project_uuid) | ||
| ) | ||
| return result if result is not None else False | ||
|
|
||
| @classmethod | ||
| async def set_allow_guests_to_push_states_and_output_ports( | ||
| cls, async_engine: AsyncEngine, *, project_uuid: str | ||
| ) -> None: | ||
| async with transaction_context(async_engine) as connection: | ||
| await connection.execute( | ||
| sa.insert(projects_optionals).values( | ||
| project_uuid=project_uuid, | ||
| allow_guests_to_push_states_and_output_ports=True, | ||
| ) | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # pylint: disable=redefined-outer-name | ||
|
|
||
| from collections.abc import Awaitable, Callable | ||
|
|
||
| import pytest | ||
| from aiopg.sa.connection import SAConnection | ||
| from aiopg.sa.result import RowProxy | ||
| from simcore_postgres_database.utils_projects_optionals import BaseProjectOptionalsRepo | ||
| from sqlalchemy.ext.asyncio import AsyncEngine | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| async def fake_user( | ||
| connection: SAConnection, | ||
| create_fake_user: Callable[..., Awaitable[RowProxy]], | ||
| ) -> RowProxy: | ||
| user: RowProxy = await create_fake_user(connection, name=f"user.{__name__}") | ||
| return user | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| async def fake_project( | ||
| connection: SAConnection, | ||
| fake_user: RowProxy, | ||
| create_fake_project: Callable[..., Awaitable[RowProxy]], | ||
| create_fake_nodes: Callable[..., Awaitable[RowProxy]], | ||
| ) -> RowProxy: | ||
| project: RowProxy = await create_fake_project(connection, fake_user, hidden=True) | ||
| await create_fake_nodes(project) | ||
| return project | ||
|
|
||
|
|
||
| async def test_something( | ||
| asyncpg_engine: AsyncEngine, | ||
| connection: SAConnection, | ||
| create_fake_user: Callable[..., Awaitable[RowProxy]], | ||
| create_fake_project: Callable[..., Awaitable[RowProxy]], | ||
| ): | ||
| user: RowProxy = await create_fake_user(connection) | ||
| project: RowProxy = await create_fake_project(connection, user, hidden=True) | ||
|
|
||
| assert ( | ||
| await BaseProjectOptionalsRepo.allows_guests_to_push_states_and_output_ports( | ||
| asyncpg_engine, project_uuid=project["uuid"] | ||
| ) | ||
| is False | ||
| ) | ||
|
|
||
| # add the entry in the table | ||
| await BaseProjectOptionalsRepo.set_allow_guests_to_push_states_and_output_ports( | ||
| asyncpg_engine, project_uuid=project["uuid"] | ||
| ) | ||
|
|
||
| assert ( | ||
| await BaseProjectOptionalsRepo.allows_guests_to_push_states_and_output_ports( | ||
| asyncpg_engine, project_uuid=project["uuid"] | ||
| ) | ||
| is True | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this name very weird and very unclear. That could mean anything.
Also I wonder what is the point of pushing the states here? a guest user is only temporary, what is the point of saving the states?
The outputs I understand as this can be used in subsequent nodes, but the states?