async def get_project_states_for_user(user_id: int, project_uuid: str, app: web.Application) -> ProjectState: # for templates: the project is never locked and never opened. also the running state is always unknown lock_state = ProjectLocked(value=False, status=ProjectStatus.CLOSED) running_state = RunningState.UNKNOWN lock_state, computation_task = await logged_gather( _get_project_lock_state(user_id, project_uuid, app), director_v2_api.get_computation_task(app, user_id, UUID(project_uuid)), ) if computation_task: # get the running state running_state = computation_task.state return ProjectState(locked=lock_state, state=ProjectRunningState(value=running_state))
def mocks_on_projects_api(mocker) -> Dict: """ All projects in this module are UNLOCKED """ state = ProjectState( locked=ProjectLocked( value=False, owner=Owner(user_id=2, first_name="Speedy", last_name="Gonzalez"), ), state=ProjectRunningState(value=RunningState.NOT_STARTED), ).dict(by_alias=True, exclude_unset=True) mocker.patch( "simcore_service_webserver.projects.projects_api.get_project_state_for_user", return_value=future_with_result(state), )
async def add_project_states_for_user( user_id: int, project: Dict[str, Any], is_template: bool, app: web.Application, ) -> Dict[str, Any]: # for templates: the project is never locked and never opened. also the running state is always unknown lock_state = ProjectLocked(value=False, status=ProjectStatus.CLOSED) running_state = RunningState.UNKNOWN if not is_template: lock_state, computation_task = await logged_gather( _get_project_lock_state(user_id, project["uuid"], app), director_v2_api.get_computation_task(app, user_id, project["uuid"]), ) if computation_task: # get the running state running_state = computation_task.state # get the nodes individual states for ( node_id, node_state, ) in computation_task.pipeline_details.node_states.items(): prj_node = project["workbench"].get(str(node_id)) if prj_node is None: continue node_state_dict = json.loads( node_state.json(by_alias=True, exclude_unset=True) ) prj_node.setdefault("state", {}).update(node_state_dict) project["state"] = ProjectState( locked=lock_state, state=ProjectRunningState(value=running_state) ).dict(by_alias=True, exclude_unset=True) return project
def mocks_on_projects_api(mocker, logged_user) -> None: """ All projects in this module are UNLOCKED Emulates that it found logged_user as the SOLE user of this project and returns the ProjectState indicating his as owner """ nameparts = logged_user["name"].split(".") + [""] state = ProjectState( locked=ProjectLocked( value=False, owner=Owner( user_id=logged_user["id"], first_name=nameparts[0], last_name=nameparts[1], ), status=ProjectStatus.CLOSED, ), state=ProjectRunningState(value=RunningState.NOT_STARTED), ) mocker.patch( "simcore_service_webserver.projects.projects_api._get_project_lock_state", return_value=state, )
async def test_open_shared_project_2_users_locked( client: TestClient, client_on_running_server_factory: Callable, logged_user: Dict, shared_project: Dict, socketio_client_factory: Callable, client_session_id_factory: Callable, user_role: UserRole, expected: ExpectedResponse, mocker, disable_gc_manual_guest_users, ): # Use-case: user 1 opens a shared project, user 2 tries to open it as well mock_project_state_updated_handler = mocker.Mock() client_1 = client client_id1 = client_session_id_factory() client_2 = client_on_running_server_factory() client_id2 = client_session_id_factory() # 1. user 1 opens project sio_1 = await _connect_websocket( socketio_client_factory, user_role != UserRole.ANONYMOUS, client_1, client_id1, {SOCKET_IO_PROJECT_UPDATED_EVENT: mock_project_state_updated_handler}, ) # expected is that the project is closed and unlocked expected_project_state_client_1 = ProjectState( locked=ProjectLocked(value=False, status=ProjectStatus.CLOSED), state=ProjectRunningState(value=RunningState.NOT_STARTED), ) for client_id in [client_id1, None]: await _state_project( client_1, shared_project, expected.ok if user_role != UserRole.GUEST else web.HTTPOk, expected_project_state_client_1, ) await _open_project( client_1, client_id1, shared_project, expected.ok if user_role != UserRole.GUEST else web.HTTPOk, ) # now the expected result is that the project is locked and opened by client 1 owner1 = Owner( user_id=logged_user["id"], first_name=(logged_user["name"].split(".") + [""])[0], last_name=(logged_user["name"].split(".") + [""])[1], ) expected_project_state_client_1.locked.value = True expected_project_state_client_1.locked.status = ProjectStatus.OPENED expected_project_state_client_1.locked.owner = owner1 # NOTE: there are 2 calls since we are part of the primary group and the all group await _assert_project_state_updated( mock_project_state_updated_handler, shared_project, [expected_project_state_client_1] * (0 if user_role == UserRole.ANONYMOUS else 2), ) await _state_project( client_1, shared_project, expected.ok if user_role != UserRole.GUEST else web.HTTPOk, expected_project_state_client_1, ) # 2. create a separate client now and log in user2, try to open the same shared project user_2 = await log_client_in( client_2, {"role": user_role.name}, enable_check=user_role != UserRole.ANONYMOUS ) sio_2 = await _connect_websocket( socketio_client_factory, user_role != UserRole.ANONYMOUS, client_2, client_id2, {SOCKET_IO_PROJECT_UPDATED_EVENT: mock_project_state_updated_handler}, ) await _open_project( client_2, client_id2, shared_project, expected.locked if user_role != UserRole.GUEST else HTTPLocked, ) expected_project_state_client_2 = deepcopy(expected_project_state_client_1) expected_project_state_client_2.locked.status = ProjectStatus.OPENED await _state_project( client_2, shared_project, expected.ok if user_role != UserRole.GUEST else web.HTTPOk, expected_project_state_client_2, ) # 3. user 1 closes the project await _close_project(client_1, client_id1, shared_project, expected.no_content) if not any(user_role == role for role in [UserRole.ANONYMOUS, UserRole.GUEST]): # Guests cannot close projects expected_project_state_client_1 = ProjectState( locked=ProjectLocked(value=False, status=ProjectStatus.CLOSED), state=ProjectRunningState(value=RunningState.NOT_STARTED), ) # we should receive an event that the project lock state changed # NOTE: there are 2x3 calls since we are part of the primary group and the all group and user 2 is part of the all group # first CLOSING, then CLOSED await _assert_project_state_updated( mock_project_state_updated_handler, shared_project, [ expected_project_state_client_1.copy( update={ "locked": ProjectLocked( value=True, status=ProjectStatus.CLOSING, owner=owner1 ) } ) ] * ( 0 if any(user_role == role for role in [UserRole.ANONYMOUS, UserRole.GUEST]) else 3 ) + [expected_project_state_client_1] * ( 0 if any(user_role == role for role in [UserRole.ANONYMOUS, UserRole.GUEST]) else 3 ), ) await _state_project( client_1, shared_project, expected.ok if user_role != UserRole.GUEST else web.HTTPOk, expected_project_state_client_1, ) # 4. user 2 now should be able to open the project await _open_project( client_2, client_id2, shared_project, expected.ok if user_role != UserRole.GUEST else HTTPLocked, ) if not any(user_role == role for role in [UserRole.ANONYMOUS, UserRole.GUEST]): expected_project_state_client_2.locked.value = True expected_project_state_client_2.locked.status = ProjectStatus.OPENED owner2 = Owner( user_id=user_2["id"], first_name=(user_2["name"].split(".") + [""])[0], last_name=(user_2["name"].split(".") + [""])[1], ) expected_project_state_client_2.locked.owner = owner2 expected_project_state_client_1.locked.value = True expected_project_state_client_1.locked.status = ProjectStatus.OPENED expected_project_state_client_1.locked.owner = owner2 # NOTE: there are 3 calls since we are part of the primary group and the all group await _assert_project_state_updated( mock_project_state_updated_handler, shared_project, [expected_project_state_client_1] * ( 0 if any(user_role == role for role in [UserRole.ANONYMOUS, UserRole.GUEST]) else 3 ), ) await _state_project( client_1, shared_project, expected.ok if user_role != UserRole.GUEST else web.HTTPOk, expected_project_state_client_1, )
) # for templates: the project is never locked and never opened. also the running state is always unknown lock_state = ProjectLocked(value=False, status=ProjectStatus.CLOSED) running_state = RunningState.UNKNOWN if not is_template: lock_state = await _get_project_lock_state(user_id, project["uuid"], app) if computation_task := await director_v2_api.get_computation_task( app, user_id, project["uuid"]): # get the running state running_state = computation_task.state # get the nodes individual states for ( node_id, node_state, ) in computation_task.pipeline_details.node_states.items(): prj_node = project["workbench"].get(str(node_id)) if prj_node is None: continue node_state_dict = json.loads( node_state.json(by_alias=True, exclude_unset=True)) prj_node.setdefault("state", {}).update(node_state_dict) project["state"] = ProjectState( locked=lock_state, state=ProjectRunningState(value=running_state)).dict( by_alias=True, exclude_unset=True) return project
async def _get_project_running_state( user_id: PositiveInt, project_uuid: str, app: web.Application) -> ProjectRunningState: pipeline_state: RunningState = await get_pipeline_state( app, user_id, project_uuid) return ProjectRunningState(value=pipeline_state)