зеркало из https://github.com/microsoft/AzureTRE.git
Airlock manager can use user resources (#2649)
Co-authored-by: JaimieWi <92854957+JaimieWi@users.noreply.github.com>
This commit is contained in:
Родитель
9dc7b55810
Коммит
5067730259
|
@ -209,3 +209,4 @@ pytest_api_unit_failed
|
||||||
validation.txt
|
validation.txt
|
||||||
|
|
||||||
/index.html
|
/index.html
|
||||||
|
.DS_Store
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "0.4.40"
|
__version__ = "0.4.41"
|
||||||
|
|
|
@ -24,7 +24,10 @@ from models.schemas.resource_template import ResourceTemplateInformationInList
|
||||||
from resources import strings
|
from resources import strings
|
||||||
from services.access_service import AuthConfigValidationError
|
from services.access_service import AuthConfigValidationError
|
||||||
from services.authentication import get_current_admin_user, \
|
from services.authentication import get_current_admin_user, \
|
||||||
get_access_service, get_current_workspace_owner_user, get_current_workspace_owner_or_researcher_user, get_current_tre_user_or_tre_admin, get_current_workspace_owner_or_researcher_user_or_tre_admin, get_current_workspace_owner_or_tre_admin
|
get_access_service, get_current_workspace_owner_user, get_current_workspace_owner_or_researcher_user, get_current_tre_user_or_tre_admin, \
|
||||||
|
get_current_workspace_owner_or_tre_admin, \
|
||||||
|
get_current_workspace_owner_or_researcher_user_or_airlock_manager, \
|
||||||
|
get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin
|
||||||
from services.authentication import extract_auth_information
|
from services.authentication import extract_auth_information
|
||||||
from services.azure_resource_status import get_azure_resource_status
|
from services.azure_resource_status import get_azure_resource_status
|
||||||
from azure.cosmos.exceptions import CosmosAccessConditionFailedError
|
from azure.cosmos.exceptions import CosmosAccessConditionFailedError
|
||||||
|
@ -33,13 +36,13 @@ from .resource_helpers import get_identity_role_assignments, save_and_deploy_res
|
||||||
from models.domain.request_action import RequestAction
|
from models.domain.request_action import RequestAction
|
||||||
|
|
||||||
workspaces_core_router = APIRouter(dependencies=[Depends(get_current_tre_user_or_tre_admin)])
|
workspaces_core_router = APIRouter(dependencies=[Depends(get_current_tre_user_or_tre_admin)])
|
||||||
workspaces_shared_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_tre_admin)])
|
workspaces_shared_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin)])
|
||||||
workspace_services_workspace_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user)])
|
workspace_services_workspace_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)])
|
||||||
user_resources_workspace_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user)])
|
user_resources_workspace_router = APIRouter(dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)])
|
||||||
|
|
||||||
|
|
||||||
def validate_user_is_workspace_owner_or_resource_owner(user, user_resource):
|
def validate_user_has_valid_role_for_user_resource(user, user_resource):
|
||||||
if "WorkspaceOwner" in user.roles:
|
if "WorkspaceOwner" in user.roles or "AirlockManager" in user.roles:
|
||||||
return
|
return
|
||||||
|
|
||||||
if "WorkspaceResearcher" in user.roles and user_resource.ownerId == user.id:
|
if "WorkspaceResearcher" in user.roles and user_resource.ownerId == user.id:
|
||||||
|
@ -170,14 +173,21 @@ async def invoke_action_on_workspace(response: Response, action: str, user=Depen
|
||||||
# workspace operations
|
# workspace operations
|
||||||
# This method only returns templates that the authenticated user is authorized to use
|
# This method only returns templates that the authenticated user is authorized to use
|
||||||
@workspaces_shared_router.get("/workspace/{workspace_id}/workspace-service-templates", response_model=ResourceTemplateInformationInList, name=strings.API_GET_WORKSPACE_SERVICE_TEMPLATES_IN_WORKSPACE)
|
@workspaces_shared_router.get("/workspace/{workspace_id}/workspace-service-templates", response_model=ResourceTemplateInformationInList, name=strings.API_GET_WORKSPACE_SERVICE_TEMPLATES_IN_WORKSPACE)
|
||||||
async def get_workspace_service_templates(workspace=Depends(get_workspace_by_id_from_path), template_repo=Depends(get_repository(ResourceTemplateRepository)), user=Depends(get_current_workspace_owner_or_researcher_user_or_tre_admin)) -> ResourceTemplateInformationInList:
|
async def get_workspace_service_templates(
|
||||||
|
workspace=Depends(get_workspace_by_id_from_path),
|
||||||
|
template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin)) -> ResourceTemplateInformationInList:
|
||||||
template_infos = template_repo.get_templates_information(ResourceType.WorkspaceService, user.roles)
|
template_infos = template_repo.get_templates_information(ResourceType.WorkspaceService, user.roles)
|
||||||
return ResourceTemplateInformationInList(templates=template_infos)
|
return ResourceTemplateInformationInList(templates=template_infos)
|
||||||
|
|
||||||
|
|
||||||
# This method only returns templates that the authenticated user is authorized to use
|
# This method only returns templates that the authenticated user is authorized to use
|
||||||
@workspaces_shared_router.get("/workspace/{workspace_id}/workspace-service-templates/{service_template_name}/user-resource-templates", response_model=ResourceTemplateInformationInList, name=strings.API_GET_USER_RESOURCE_TEMPLATES_IN_WORKSPACE)
|
@workspaces_shared_router.get("/workspace/{workspace_id}/workspace-service-templates/{service_template_name}/user-resource-templates", response_model=ResourceTemplateInformationInList, name=strings.API_GET_USER_RESOURCE_TEMPLATES_IN_WORKSPACE)
|
||||||
async def get_user_resource_templates(service_template_name: str, workspace=Depends(get_workspace_by_id_from_path), template_repo=Depends(get_repository(ResourceTemplateRepository)), user=Depends(get_current_workspace_owner_or_researcher_user_or_tre_admin)) -> ResourceTemplateInformationInList:
|
async def get_user_resource_templates(
|
||||||
|
service_template_name: str,
|
||||||
|
workspace=Depends(get_workspace_by_id_from_path),
|
||||||
|
template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin)) -> ResourceTemplateInformationInList:
|
||||||
template_infos = template_repo.get_templates_information(ResourceType.UserResource, user.roles, service_template_name)
|
template_infos = template_repo.get_templates_information(ResourceType.UserResource, user.roles, service_template_name)
|
||||||
return ResourceTemplateInformationInList(templates=template_infos)
|
return ResourceTemplateInformationInList(templates=template_infos)
|
||||||
|
|
||||||
|
@ -193,13 +203,13 @@ async def retrieve_workspace_operation_by_workspace_id_and_operation_id(workspac
|
||||||
|
|
||||||
|
|
||||||
# WORKSPACE SERVICES ROUTES
|
# WORKSPACE SERVICES ROUTES
|
||||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services", response_model=WorkspaceServicesInList, name=strings.API_GET_ALL_WORKSPACE_SERVICES, dependencies=[Depends(get_current_workspace_owner_or_researcher_user)])
|
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services", response_model=WorkspaceServicesInList, name=strings.API_GET_ALL_WORKSPACE_SERVICES, dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)])
|
||||||
async def retrieve_users_active_workspace_services(workspace=Depends(get_workspace_by_id_from_path), workspace_services_repo=Depends(get_repository(WorkspaceServiceRepository))) -> WorkspaceServicesInList:
|
async def retrieve_users_active_workspace_services(workspace=Depends(get_workspace_by_id_from_path), workspace_services_repo=Depends(get_repository(WorkspaceServiceRepository))) -> WorkspaceServicesInList:
|
||||||
workspace_services = workspace_services_repo.get_active_workspace_services_for_workspace(workspace.id)
|
workspace_services = workspace_services_repo.get_active_workspace_services_for_workspace(workspace.id)
|
||||||
return WorkspaceServicesInList(workspaceServices=workspace_services)
|
return WorkspaceServicesInList(workspaceServices=workspace_services)
|
||||||
|
|
||||||
|
|
||||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}", response_model=WorkspaceServiceInResponse, name=strings.API_GET_WORKSPACE_SERVICE_BY_ID, dependencies=[Depends(get_current_workspace_owner_or_researcher_user), Depends(get_workspace_by_id_from_path)])
|
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}", response_model=WorkspaceServiceInResponse, name=strings.API_GET_WORKSPACE_SERVICE_BY_ID, dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager), Depends(get_workspace_by_id_from_path)])
|
||||||
async def retrieve_workspace_service_by_id(workspace_service=Depends(get_workspace_service_by_id_from_path)) -> WorkspaceServiceInResponse:
|
async def retrieve_workspace_service_by_id(workspace_service=Depends(get_workspace_service_by_id_from_path)) -> WorkspaceServiceInResponse:
|
||||||
return WorkspaceServiceInResponse(workspaceService=workspace_service)
|
return WorkspaceServiceInResponse(workspaceService=workspace_service)
|
||||||
|
|
||||||
|
@ -290,19 +300,23 @@ async def invoke_action_on_workspace_service(response: Response, action: str, us
|
||||||
|
|
||||||
|
|
||||||
# workspace service operations
|
# workspace service operations
|
||||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/operations", response_model=OperationInList, name=strings.API_GET_RESOURCE_OPERATIONS, dependencies=[Depends(get_current_workspace_owner_or_researcher_user), Depends(get_workspace_by_id_from_path)])
|
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/operations", response_model=OperationInList, name=strings.API_GET_RESOURCE_OPERATIONS, dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager), Depends(get_workspace_by_id_from_path)])
|
||||||
async def retrieve_workspace_service_operations_by_workspace_service_id(workspace_service=Depends(get_workspace_service_by_id_from_path), operations_repo=Depends(get_repository(OperationRepository))) -> OperationInList:
|
async def retrieve_workspace_service_operations_by_workspace_service_id(workspace_service=Depends(get_workspace_service_by_id_from_path), operations_repo=Depends(get_repository(OperationRepository))) -> OperationInList:
|
||||||
return OperationInList(operations=operations_repo.get_operations_by_resource_id(resource_id=workspace_service.id))
|
return OperationInList(operations=operations_repo.get_operations_by_resource_id(resource_id=workspace_service.id))
|
||||||
|
|
||||||
|
|
||||||
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/operations/{operation_id}", response_model=OperationInResponse, name=strings.API_GET_RESOURCE_OPERATION_BY_ID, dependencies=[Depends(get_current_workspace_owner_or_researcher_user), Depends(get_workspace_by_id_from_path)])
|
@workspace_services_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/operations/{operation_id}", response_model=OperationInResponse, name=strings.API_GET_RESOURCE_OPERATION_BY_ID, dependencies=[Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager), Depends(get_workspace_by_id_from_path)])
|
||||||
async def retrieve_workspace_service_operation_by_workspace_service_id_and_operation_id(workspace_service=Depends(get_workspace_service_by_id_from_path), operation=Depends(get_operation_by_id_from_path)) -> OperationInList:
|
async def retrieve_workspace_service_operation_by_workspace_service_id_and_operation_id(workspace_service=Depends(get_workspace_service_by_id_from_path), operation=Depends(get_operation_by_id_from_path)) -> OperationInList:
|
||||||
return OperationInResponse(operation=operation)
|
return OperationInResponse(operation=operation)
|
||||||
|
|
||||||
|
|
||||||
# USER RESOURCE ROUTES
|
# USER RESOURCE ROUTES
|
||||||
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources", response_model=UserResourcesInList, name=strings.API_GET_MY_USER_RESOURCES, dependencies=[Depends(get_workspace_by_id_from_path)])
|
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources", response_model=UserResourcesInList, name=strings.API_GET_MY_USER_RESOURCES, dependencies=[Depends(get_workspace_by_id_from_path)])
|
||||||
async def retrieve_user_resources_for_workspace_service(workspace_id: str, service_id: str, user=Depends(get_current_workspace_owner_or_researcher_user), user_resource_repo=Depends(get_repository(UserResourceRepository))) -> UserResourcesInList:
|
async def retrieve_user_resources_for_workspace_service(
|
||||||
|
workspace_id: str,
|
||||||
|
service_id: str,
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||||
|
user_resource_repo=Depends(get_repository(UserResourceRepository))) -> UserResourcesInList:
|
||||||
user_resources = user_resource_repo.get_user_resources_for_workspace_service(workspace_id, service_id)
|
user_resources = user_resource_repo.get_user_resources_for_workspace_service(workspace_id, service_id)
|
||||||
|
|
||||||
# filter only to the user - for researchers
|
# filter only to the user - for researchers
|
||||||
|
@ -317,8 +331,10 @@ async def retrieve_user_resources_for_workspace_service(workspace_id: str, servi
|
||||||
|
|
||||||
|
|
||||||
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", response_model=UserResourceInResponse, name=strings.API_GET_USER_RESOURCE, dependencies=[Depends(get_workspace_by_id_from_path)])
|
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", response_model=UserResourceInResponse, name=strings.API_GET_USER_RESOURCE, dependencies=[Depends(get_workspace_by_id_from_path)])
|
||||||
async def retrieve_user_resource_by_id(user_resource=Depends(get_user_resource_by_id_from_path), user=Depends(get_current_workspace_owner_or_researcher_user)) -> UserResourceInResponse:
|
async def retrieve_user_resource_by_id(
|
||||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)) -> UserResourceInResponse:
|
||||||
|
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||||
|
|
||||||
if 'azure_resource_id' in user_resource.properties:
|
if 'azure_resource_id' in user_resource.properties:
|
||||||
user_resource.azureStatus = get_azure_resource_status(user_resource.properties['azure_resource_id'])
|
user_resource.azureStatus = get_azure_resource_status(user_resource.properties['azure_resource_id'])
|
||||||
|
@ -333,7 +349,7 @@ async def create_user_resource(
|
||||||
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
||||||
resource_template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
resource_template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||||
operations_repo=Depends(get_repository(OperationRepository)),
|
operations_repo=Depends(get_repository(OperationRepository)),
|
||||||
user=Depends(get_current_workspace_owner_or_researcher_user),
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||||
workspace=Depends(get_deployed_workspace_by_id_from_path),
|
workspace=Depends(get_deployed_workspace_by_id_from_path),
|
||||||
workspace_service=Depends(get_deployed_workspace_service_by_id_from_path)) -> OperationInResponse:
|
workspace_service=Depends(get_deployed_workspace_service_by_id_from_path)) -> OperationInResponse:
|
||||||
|
|
||||||
|
@ -359,8 +375,15 @@ async def create_user_resource(
|
||||||
|
|
||||||
|
|
||||||
@user_resources_workspace_router.delete("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", response_model=OperationInResponse, name=strings.API_DELETE_USER_RESOURCE)
|
@user_resources_workspace_router.delete("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", response_model=OperationInResponse, name=strings.API_DELETE_USER_RESOURCE)
|
||||||
async def delete_user_resource(response: Response, user=Depends(get_current_workspace_owner_or_researcher_user), user_resource=Depends(get_user_resource_by_id_from_path), workspace_service=Depends(get_workspace_service_by_id_from_path), user_resource_repo=Depends(get_repository(UserResourceRepository)), operations_repo=Depends(get_repository(OperationRepository)), resource_template_repo=Depends(get_repository(ResourceTemplateRepository))) -> OperationInResponse:
|
async def delete_user_resource(
|
||||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
response: Response,
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||||
|
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||||
|
workspace_service=Depends(get_workspace_service_by_id_from_path),
|
||||||
|
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
||||||
|
operations_repo=Depends(get_repository(OperationRepository)),
|
||||||
|
resource_template_repo=Depends(get_repository(ResourceTemplateRepository))) -> OperationInResponse:
|
||||||
|
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||||
|
|
||||||
if user_resource.isEnabled:
|
if user_resource.isEnabled:
|
||||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=strings.USER_RESOURCE_NEEDS_TO_BE_DISABLED_BEFORE_DELETION)
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=strings.USER_RESOURCE_NEEDS_TO_BE_DISABLED_BEFORE_DELETION)
|
||||||
|
@ -382,8 +405,17 @@ async def delete_user_resource(response: Response, user=Depends(get_current_work
|
||||||
|
|
||||||
|
|
||||||
@user_resources_workspace_router.patch("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", status_code=status.HTTP_202_ACCEPTED, response_model=OperationInResponse, name=strings.API_UPDATE_USER_RESOURCE, dependencies=[Depends(get_workspace_by_id_from_path), Depends(get_workspace_service_by_id_from_path)])
|
@user_resources_workspace_router.patch("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}", status_code=status.HTTP_202_ACCEPTED, response_model=OperationInResponse, name=strings.API_UPDATE_USER_RESOURCE, dependencies=[Depends(get_workspace_by_id_from_path), Depends(get_workspace_service_by_id_from_path)])
|
||||||
async def patch_user_resource(user_resource_patch: ResourcePatch, response: Response, user=Depends(get_current_workspace_owner_or_researcher_user), user_resource=Depends(get_user_resource_by_id_from_path), workspace_service=Depends(get_workspace_service_by_id_from_path), user_resource_repo=Depends(get_repository(UserResourceRepository)), resource_template_repo=Depends(get_repository(ResourceTemplateRepository)), operations_repo=Depends(get_repository(OperationRepository)), etag: str = Header(...)) -> OperationInResponse:
|
async def patch_user_resource(
|
||||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
user_resource_patch: ResourcePatch,
|
||||||
|
response: Response,
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||||
|
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||||
|
workspace_service=Depends(get_workspace_service_by_id_from_path),
|
||||||
|
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
||||||
|
resource_template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||||
|
operations_repo=Depends(get_repository(OperationRepository)),
|
||||||
|
etag: str = Header(...)) -> OperationInResponse:
|
||||||
|
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
patched_user_resource, resource_template = user_resource_repo.patch_user_resource(user_resource, user_resource_patch, etag, resource_template_repo, workspace_service.templateName, user)
|
patched_user_resource, resource_template = user_resource_repo.patch_user_resource(user_resource, user_resource_patch, etag, resource_template_repo, workspace_service.templateName, user)
|
||||||
|
@ -406,8 +438,16 @@ async def patch_user_resource(user_resource_patch: ResourcePatch, response: Resp
|
||||||
|
|
||||||
# user resource actions
|
# user resource actions
|
||||||
@user_resources_workspace_router.post("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/invoke-action", status_code=status.HTTP_202_ACCEPTED, response_model=OperationInResponse, name=strings.API_INVOKE_ACTION_ON_USER_RESOURCE)
|
@user_resources_workspace_router.post("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/invoke-action", status_code=status.HTTP_202_ACCEPTED, response_model=OperationInResponse, name=strings.API_INVOKE_ACTION_ON_USER_RESOURCE)
|
||||||
async def invoke_action_on_user_resource(response: Response, action: str, user_resource=Depends(get_user_resource_by_id_from_path), workspace_service=Depends(get_workspace_service_by_id_from_path), resource_template_repo=Depends(get_repository(ResourceTemplateRepository)), user_resource_repo=Depends(get_repository(UserResourceRepository)), operations_repo=Depends(get_repository(OperationRepository)), user=Depends(get_current_workspace_owner_or_researcher_user)) -> OperationInResponse:
|
async def invoke_action_on_user_resource(
|
||||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
response: Response,
|
||||||
|
action: str,
|
||||||
|
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||||
|
workspace_service=Depends(get_workspace_service_by_id_from_path),
|
||||||
|
resource_template_repo=Depends(get_repository(ResourceTemplateRepository)),
|
||||||
|
user_resource_repo=Depends(get_repository(UserResourceRepository)),
|
||||||
|
operations_repo=Depends(get_repository(OperationRepository)),
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager)) -> OperationInResponse:
|
||||||
|
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||||
operation = await send_custom_action_message(
|
operation = await send_custom_action_message(
|
||||||
resource=user_resource,
|
resource=user_resource,
|
||||||
resource_repo=user_resource_repo,
|
resource_repo=user_resource_repo,
|
||||||
|
@ -425,12 +465,18 @@ async def invoke_action_on_user_resource(response: Response, action: str, user_r
|
||||||
|
|
||||||
# user resource operations
|
# user resource operations
|
||||||
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/operations", response_model=OperationInList, name=strings.API_GET_RESOURCE_OPERATIONS, dependencies=[Depends(get_workspace_by_id_from_path)])
|
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/operations", response_model=OperationInList, name=strings.API_GET_RESOURCE_OPERATIONS, dependencies=[Depends(get_workspace_by_id_from_path)])
|
||||||
async def retrieve_user_resource_operations_by_user_resource_id(user_resource=Depends(get_user_resource_by_id_from_path), user=Depends(get_current_workspace_owner_or_researcher_user), operations_repo=Depends(get_repository(OperationRepository))) -> OperationInList:
|
async def retrieve_user_resource_operations_by_user_resource_id(
|
||||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||||
|
operations_repo=Depends(get_repository(OperationRepository))) -> OperationInList:
|
||||||
|
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||||
return OperationInList(operations=operations_repo.get_operations_by_resource_id(resource_id=user_resource.id))
|
return OperationInList(operations=operations_repo.get_operations_by_resource_id(resource_id=user_resource.id))
|
||||||
|
|
||||||
|
|
||||||
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/operations/{operation_id}", response_model=OperationInResponse, name=strings.API_GET_RESOURCE_OPERATION_BY_ID, dependencies=[Depends(get_workspace_by_id_from_path)])
|
@user_resources_workspace_router.get("/workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}/operations/{operation_id}", response_model=OperationInResponse, name=strings.API_GET_RESOURCE_OPERATION_BY_ID, dependencies=[Depends(get_workspace_by_id_from_path)])
|
||||||
async def retrieve_user_resource_operations_by_user_resource_id_and_operation_id(user_resource=Depends(get_user_resource_by_id_from_path), user=Depends(get_current_workspace_owner_or_researcher_user), operation=Depends(get_operation_by_id_from_path)) -> OperationInList:
|
async def retrieve_user_resource_operations_by_user_resource_id_and_operation_id(
|
||||||
validate_user_is_workspace_owner_or_resource_owner(user, user_resource)
|
user_resource=Depends(get_user_resource_by_id_from_path),
|
||||||
|
user=Depends(get_current_workspace_owner_or_researcher_user_or_airlock_manager),
|
||||||
|
operation=Depends(get_operation_by_id_from_path)) -> OperationInList:
|
||||||
|
validate_user_has_valid_role_for_user_resource(user, user_resource)
|
||||||
return OperationInResponse(operation=operation)
|
return OperationInResponse(operation=operation)
|
||||||
|
|
|
@ -48,4 +48,7 @@ get_current_workspace_owner_or_researcher_user_or_airlock_manager = AzureADAutho
|
||||||
get_current_workspace_owner_or_researcher_user_or_tre_admin = AzureADAuthorization(require_one_of_roles=["TREAdmin", "WorkspaceOwner", "WorkspaceResearcher"])
|
get_current_workspace_owner_or_researcher_user_or_tre_admin = AzureADAuthorization(require_one_of_roles=["TREAdmin", "WorkspaceOwner", "WorkspaceResearcher"])
|
||||||
|
|
||||||
|
|
||||||
|
get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin = AzureADAuthorization(require_one_of_roles=["TREAdmin", "WorkspaceOwner", "WorkspaceResearcher", "AirlockManager"])
|
||||||
|
|
||||||
|
|
||||||
get_current_workspace_owner_or_tre_admin = AzureADAuthorization(require_one_of_roles=["TREAdmin", "WorkspaceOwner"])
|
get_current_workspace_owner_or_tre_admin = AzureADAuthorization(require_one_of_roles=["TREAdmin", "WorkspaceOwner"])
|
||||||
|
|
|
@ -20,7 +20,11 @@ from models.domain.workspace import Workspace, WorkspaceRole
|
||||||
from models.domain.workspace_service import WorkspaceService
|
from models.domain.workspace_service import WorkspaceService
|
||||||
from models.schemas.resource_template import ResourceTemplateInformation
|
from models.schemas.resource_template import ResourceTemplateInformation
|
||||||
from resources import strings
|
from resources import strings
|
||||||
from services.authentication import get_current_admin_user, get_current_tre_user_or_tre_admin, get_current_workspace_owner_user, get_current_workspace_owner_or_researcher_user, get_current_workspace_owner_or_researcher_user_or_tre_admin
|
from services.authentication import get_current_admin_user, \
|
||||||
|
get_current_tre_user_or_tre_admin, get_current_workspace_owner_user, \
|
||||||
|
get_current_workspace_owner_or_researcher_user, \
|
||||||
|
get_current_workspace_owner_or_researcher_user_or_airlock_manager, \
|
||||||
|
get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin
|
||||||
from azure.cosmos.exceptions import CosmosAccessConditionFailedError
|
from azure.cosmos.exceptions import CosmosAccessConditionFailedError
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,7 +219,8 @@ class TestWorkspaceRoutesThatDontRequireAdminRights:
|
||||||
def log_in_with_non_admin_user(self, app, non_admin_user):
|
def log_in_with_non_admin_user(self, app, non_admin_user):
|
||||||
with patch('services.aad_authentication.AzureADAuthorization._get_user_from_token', return_value=non_admin_user()):
|
with patch('services.aad_authentication.AzureADAuthorization._get_user_from_token', return_value=non_admin_user()):
|
||||||
app.dependency_overrides[get_current_tre_user_or_tre_admin] = non_admin_user
|
app.dependency_overrides[get_current_tre_user_or_tre_admin] = non_admin_user
|
||||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_tre_admin] = non_admin_user
|
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = non_admin_user
|
||||||
|
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager_or_tre_admin] = non_admin_user
|
||||||
yield
|
yield
|
||||||
app.dependency_overrides = {}
|
app.dependency_overrides = {}
|
||||||
|
|
||||||
|
@ -298,6 +303,7 @@ class TestWorkspaceRoutesThatRequireAdminRights:
|
||||||
def _prepare(self, app, admin_user):
|
def _prepare(self, app, admin_user):
|
||||||
with patch('services.aad_authentication.AzureADAuthorization._get_user_from_token', return_value=admin_user()):
|
with patch('services.aad_authentication.AzureADAuthorization._get_user_from_token', return_value=admin_user()):
|
||||||
app.dependency_overrides[get_current_tre_user_or_tre_admin] = admin_user
|
app.dependency_overrides[get_current_tre_user_or_tre_admin] = admin_user
|
||||||
|
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = admin_user
|
||||||
app.dependency_overrides[get_current_admin_user] = admin_user
|
app.dependency_overrides[get_current_admin_user] = admin_user
|
||||||
yield
|
yield
|
||||||
app.dependency_overrides = {}
|
app.dependency_overrides = {}
|
||||||
|
@ -503,6 +509,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerRights:
|
||||||
def log_in_with_owner_user(self, app, owner_user):
|
def log_in_with_owner_user(self, app, owner_user):
|
||||||
# The following ws services requires the WS app registration
|
# The following ws services requires the WS app registration
|
||||||
app.dependency_overrides[get_current_workspace_owner_user] = owner_user
|
app.dependency_overrides[get_current_workspace_owner_user] = owner_user
|
||||||
|
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = owner_user
|
||||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user] = owner_user
|
app.dependency_overrides[get_current_workspace_owner_or_researcher_user] = owner_user
|
||||||
yield
|
yield
|
||||||
app.dependency_overrides = {}
|
app.dependency_overrides = {}
|
||||||
|
@ -661,7 +668,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerRights:
|
||||||
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
||||||
@ patch("api.routes.workspaces.send_resource_request_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
@ patch("api.routes.workspaces.send_resource_request_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
||||||
@ patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=None)
|
@ patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=None)
|
||||||
@ patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
@ patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||||
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
||||||
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
||||||
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
||||||
|
@ -726,7 +733,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
||||||
@pytest.fixture(autouse=True, scope='class')
|
@pytest.fixture(autouse=True, scope='class')
|
||||||
def log_in_with_researcher_user(self, app, researcher_user):
|
def log_in_with_researcher_user(self, app, researcher_user):
|
||||||
# The following ws services requires the WS app registration
|
# The following ws services requires the WS app registration
|
||||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_tre_admin] = researcher_user
|
app.dependency_overrides[get_current_workspace_owner_or_researcher_user_or_airlock_manager] = researcher_user
|
||||||
app.dependency_overrides[get_current_workspace_owner_or_researcher_user] = researcher_user
|
app.dependency_overrides[get_current_workspace_owner_or_researcher_user] = researcher_user
|
||||||
yield
|
yield
|
||||||
app.dependency_overrides = {}
|
app.dependency_overrides = {}
|
||||||
|
@ -951,7 +958,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
||||||
assert response.text == strings.WORKSPACE_SERVICE_IS_NOT_DEPLOYED
|
assert response.text == strings.WORKSPACE_SERVICE_IS_NOT_DEPLOYED
|
||||||
|
|
||||||
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
||||||
@ patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
@ patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||||
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
||||||
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
||||||
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
||||||
|
@ -998,7 +1005,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
||||||
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
# [PATCH] /workspaces/{workspace_id}/workspace-services/{service_id}/user-resources/{resource_id}
|
||||||
@ patch("api.routes.workspaces.send_resource_request_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
@ patch("api.routes.workspaces.send_resource_request_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
||||||
@ patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=None)
|
@ patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=None)
|
||||||
@ patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
@ patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||||
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
@ patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id", return_value=sample_workspace_service())
|
||||||
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
@ patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
|
||||||
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
@ patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=sample_user_resource_object())
|
||||||
|
@ -1026,7 +1033,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
||||||
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
||||||
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
||||||
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id")
|
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id")
|
||||||
@patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
@patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||||
async def test_delete_user_resource_raises_400_if_user_resource_is_enabled(self, _, get_user_resource_mock, ___, ____, resource_template_repo, app, client, basic_user_resource_template):
|
async def test_delete_user_resource_raises_400_if_user_resource_is_enabled(self, _, get_user_resource_mock, ___, ____, resource_template_repo, app, client, basic_user_resource_template):
|
||||||
user_resource = sample_user_resource_object()
|
user_resource = sample_user_resource_object()
|
||||||
get_user_resource_mock.return_value = user_resource
|
get_user_resource_mock.return_value = user_resource
|
||||||
|
@ -1041,7 +1048,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
||||||
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
||||||
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
||||||
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=disabled_user_resource())
|
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id", return_value=disabled_user_resource())
|
||||||
@patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
@patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||||
@patch("api.routes.workspaces.send_uninstall_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
@patch("api.routes.workspaces.send_uninstall_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
||||||
async def test_delete_user_resource_sends_uninstall_message(self, send_uninstall_mock, __, ___, ____, _____, resource_template_repo, app, client, basic_user_resource_template):
|
async def test_delete_user_resource_sends_uninstall_message(self, send_uninstall_mock, __, ___, ____, _____, resource_template_repo, app, client, basic_user_resource_template):
|
||||||
resource_template_repo.return_value = basic_user_resource_template
|
resource_template_repo.return_value = basic_user_resource_template
|
||||||
|
@ -1052,7 +1059,7 @@ class TestWorkspaceServiceRoutesThatRequireOwnerOrResearcherRights:
|
||||||
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
@patch("api.dependencies.workspaces.WorkspaceServiceRepository.get_workspace_service_by_id")
|
||||||
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id")
|
||||||
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id")
|
@patch("api.dependencies.workspaces.UserResourceRepository.get_user_resource_by_id")
|
||||||
@patch("api.routes.workspaces.validate_user_is_workspace_owner_or_resource_owner")
|
@patch("api.routes.workspaces.validate_user_has_valid_role_for_user_resource")
|
||||||
@patch("api.routes.workspaces.send_uninstall_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
@patch("api.routes.workspaces.send_uninstall_message", return_value=sample_resource_operation(resource_id=USER_RESOURCE_ID, operation_id=OPERATION_ID))
|
||||||
async def test_delete_user_resource_returns_resource_id(self, __, ___, get_user_resource_mock, ____, _____, resource_template_repo, app, client, basic_user_resource_template):
|
async def test_delete_user_resource_returns_resource_id(self, __, ___, get_user_resource_mock, ____, _____, resource_template_repo, app, client, basic_user_resource_template):
|
||||||
user_resource = disabled_user_resource()
|
user_resource = disabled_user_resource()
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "0.3.7"
|
__version__ = "0.3.8"
|
||||||
|
|
|
@ -67,9 +67,11 @@ public class AuthenticationProviderService {
|
||||||
|
|
||||||
List<String> rolesList = roles.asList(String.class);
|
List<String> rolesList = roles.asList(String.class);
|
||||||
if (rolesList.stream().noneMatch(x -> x.equalsIgnoreCase("WorkspaceOwner")
|
if (rolesList.stream().noneMatch(x -> x.equalsIgnoreCase("WorkspaceOwner")
|
||||||
|| x.equalsIgnoreCase("WorkspaceResearcher"))) {
|
|| x.equalsIgnoreCase("WorkspaceResearcher")
|
||||||
|
|| x.equalsIgnoreCase("AirlockManager"))) {
|
||||||
throw new GuacamoleInvalidCredentialsException(
|
throw new GuacamoleInvalidCredentialsException(
|
||||||
"User must have a workspace owner or workspace researcher role", CredentialsInfo.USERNAME_PASSWORD);
|
"User must have a workspace owner or workspace researcher or Airlock Manager role",
|
||||||
|
CredentialsInfo.USERNAME_PASSWORD);
|
||||||
}
|
}
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ex) {
|
||||||
LOGGER.error("Could not validate token", ex);
|
LOGGER.error("Could not validate token", ex);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
name: tre-service-guacamole
|
name: tre-service-guacamole
|
||||||
version: 0.4.5
|
version: 0.4.6
|
||||||
description: "An Azure TRE service for Guacamole"
|
description: "An Azure TRE service for Guacamole"
|
||||||
dockerfile: Dockerfile.tmpl
|
dockerfile: Dockerfile.tmpl
|
||||||
registry: azuretre
|
registry: azuretre
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
"description": "Linux virtual machine.",
|
"description": "Linux virtual machine.",
|
||||||
"required": [
|
"required": [
|
||||||
],
|
],
|
||||||
|
"authorizedRoles": [
|
||||||
|
"WorkspaceOwner", "WorkspaceResearcher"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"os_image": {
|
"os_image": {
|
||||||
"$id": "#/properties/os_image",
|
"$id": "#/properties/os_image",
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
"description": "Windows virtual machine.",
|
"description": "Windows virtual machine.",
|
||||||
"required": [
|
"required": [
|
||||||
],
|
],
|
||||||
|
"authorizedRoles": [
|
||||||
|
"WorkspaceOwner", "WorkspaceResearcher"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"os_image": {
|
"os_image": {
|
||||||
"$id": "#/properties/os_image",
|
"$id": "#/properties/os_image",
|
||||||
|
|
|
@ -74,7 +74,7 @@ export const ResourceContextMenu: React.FunctionComponent<ResourceContextMenuPro
|
||||||
wsAuth = true;
|
wsAuth = true;
|
||||||
break;
|
break;
|
||||||
case ResourceType.UserResource:
|
case ResourceType.UserResource:
|
||||||
r = [WorkspaceRoleName.WorkspaceOwner, WorkspaceRoleName.WorkspaceResearcher];
|
r = [WorkspaceRoleName.WorkspaceOwner, WorkspaceRoleName.WorkspaceResearcher, WorkspaceRoleName.AirlockManager];
|
||||||
wsAuth = true;
|
wsAuth = true;
|
||||||
break;
|
break;
|
||||||
case ResourceType.Workspace:
|
case ResourceType.Workspace:
|
||||||
|
|
|
@ -112,7 +112,7 @@ export const WorkspaceServiceItem: React.FunctionComponent<WorkspaceServiceItemP
|
||||||
<Stack.Item>
|
<Stack.Item>
|
||||||
<Stack horizontal horizontalAlign="space-between">
|
<Stack horizontal horizontalAlign="space-between">
|
||||||
<h1>Resources</h1>
|
<h1>Resources</h1>
|
||||||
<SecuredByRole allowedRoles={[WorkspaceRoleName.WorkspaceOwner, WorkspaceRoleName.WorkspaceResearcher]} workspaceAuth={true} element={
|
<SecuredByRole allowedRoles={[WorkspaceRoleName.WorkspaceOwner, WorkspaceRoleName.WorkspaceResearcher, WorkspaceRoleName.AirlockManager]} workspaceAuth={true} element={
|
||||||
<PrimaryButton iconProps={{ iconName: 'Add' }} text="Create new"
|
<PrimaryButton iconProps={{ iconName: 'Add' }} text="Create new"
|
||||||
disabled={!workspaceService.isEnabled || latestUpdate.componentAction === ComponentAction.Lock || successStates.indexOf(workspaceService.deploymentStatus) === -1}
|
disabled={!workspaceService.isEnabled || latestUpdate.componentAction === ComponentAction.Lock || successStates.indexOf(workspaceService.deploymentStatus) === -1}
|
||||||
title={(!workspaceService.isEnabled || latestUpdate.componentAction === ComponentAction.Lock || successStates.indexOf(workspaceService.deploymentStatus) === -1) ? 'Service must be enabled, successfully deployed, and not locked' : 'Create a User Resource'}
|
title={(!workspaceService.isEnabled || latestUpdate.componentAction === ComponentAction.Lock || successStates.indexOf(workspaceService.deploymentStatus) === -1) ? 'Service must be enabled, successfully deployed, and not locked' : 'Create a User Resource'}
|
||||||
|
|
|
@ -5,5 +5,6 @@ export enum RoleName {
|
||||||
|
|
||||||
export enum WorkspaceRoleName {
|
export enum WorkspaceRoleName {
|
||||||
WorkspaceOwner = "WorkspaceOwner",
|
WorkspaceOwner = "WorkspaceOwner",
|
||||||
WorkspaceResearcher = "WorkspaceResearcher"
|
WorkspaceResearcher = "WorkspaceResearcher",
|
||||||
}
|
AirlockManager = "AirlockManager"
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче